From 78a00e2a3a1bbc7486de0fad72603617958062c3 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Mon, 25 Aug 2014 15:12:10 +0000 Subject: Merging from trunk r1617322:1617736 in the Java tree git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/0.30@1620337 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/qpid/amqp_1_0/jms/example/Hello.java | 7 +- .../replication/ReplicatedEnvironmentFacade.java | 130 +- .../virtualhost/berkeleydb/BDBVirtualHost.java | 2 +- .../berkeleydb/BDBHAVirtualHostNodeImpl.java | 72 +- .../berkeleydb/BDBVirtualHostNode.java | 2 +- .../java/resources/virtualhostnode/bdb/add.html | 4 +- .../bdb_ha/add/existinggroup/add.html | 4 +- .../virtualhostnode/bdb_ha/add/newgroup/add.html | 4 +- .../resources/virtualhostnode/bdb_ha/edit.html | 4 +- .../ReplicatedEnvironmentFacadeTest.java | 48 +- ...BDBHAVirtualHostNodeOperationalLoggingTest.java | 55 +- .../server/store/berkeleydb/BDBBackupTest.java | 194 --- .../berkeleydb/BDBHAVirtualHostNodeRestTest.java | 443 ----- .../store/berkeleydb/BDBHAVirtualHostRestTest.java | 157 -- .../server/store/berkeleydb/BDBUpgradeTest.java | 548 ------ .../store/berkeleydb/HAClusterBlackboxTest.java | 292 ---- .../store/berkeleydb/HAClusterManagementTest.java | 321 ---- .../store/berkeleydb/HAClusterTwoNodeTest.java | 195 --- .../store/berkeleydb/HAClusterWhiteboxTest.java | 250 --- .../store/berkeleydb/HATestClusterCreator.java | 529 ------ .../server/store/berkeleydb/BDBBackupTest.java | 194 +++ .../server/store/berkeleydb/BDBUpgradeTest.java | 548 ++++++ .../replication/BDBHAVirtualHostNodeRestTest.java | 455 +++++ .../replication/BDBHAVirtualHostRestTest.java | 156 ++ .../store/berkeleydb/replication/GroupCreator.java | 535 ++++++ .../berkeleydb/replication/JMXManagementTest.java | 321 ++++ .../berkeleydb/replication/MultiNodeTest.java | 371 +++++ .../store/berkeleydb/replication/TwoNodeTest.java | 195 +++ .../server/message/internal/InternalMessage.java | 119 +- .../internal/InternalMessageMetaDataType.java | 3 +- .../virtualhostnode/JsonVirtualHostNode.java | 2 +- .../src/main/resources/initial-config.json | 3 +- .../server/virtualhost/derby/DerbyVirtualHost.java | 2 +- .../derby/DerbyVirtualHostNode.java | 2 +- .../java/resources/virtualhostnode/derby/add.html | 4 +- .../server/management/plugin/HttpManagement.java | 9 + .../plugin/HttpManagementConfiguration.java | 8 + .../management/plugin/HttpManagementUtil.java | 48 + .../plugin/servlet/DefinedFileServlet.java | 32 +- .../management/plugin/servlet/FileServlet.java | 6 +- .../plugin/servlet/rest/AbstractServlet.java | 29 +- .../plugin/servlet/rest/HelperServlet.java | 8 +- .../plugin/servlet/rest/LogFileListingServlet.java | 9 +- .../plugin/servlet/rest/LogRecordsServlet.java | 9 +- .../rest/LoggedOnUserPreferencesServlet.java | 9 +- .../plugin/servlet/rest/MessageContentServlet.java | 2 +- .../plugin/servlet/rest/MessageServlet.java | 6 +- .../plugin/servlet/rest/MetaDataServlet.java | 3 +- .../plugin/servlet/rest/RestServlet.java | 3 +- .../plugin/servlet/rest/SaslServlet.java | 8 +- .../plugin/servlet/rest/StructureServlet.java | 4 +- .../servlet/rest/UserPreferencesServlet.java | 13 +- .../java/resources/js/qpid/management/Broker.js | 39 +- .../js/qpid/management/plugin/managementhttp.js | 12 + .../java/resources/plugin/showManagementHttp.html | 4 + .../resources/virtualhost/sizemonitoring/add.html | 4 +- .../resources/virtualhost/sizemonitoring/edit.html | 4 +- .../resources/virtualhostnode/filebased/edit.html | 4 +- .../java/resources/virtualhostnode/json/add.html | 4 +- .../main/java/org/apache/qpid/example/Hello.java | 17 +- .../org/apache/qpid/disttest/AbstractRunner.java | 6 +- .../systest/disttest/ConfigFileTestHelper.java | 48 - .../disttest/DistributedTestSystemTestBase.java | 72 - .../systest/disttest/QpidQueueCreatorTest.java | 100 -- .../qpid/systest/disttest/SystemTestConstants.java | 28 - .../clientonly/BasicDistributedClientTest.java | 186 --- .../clientonly/ConsumerParticipantTest.java | 156 -- .../disttest/clientonly/ControllerQueue.java | 110 -- .../disttest/clientonly/DistributedClientTest.java | 325 ---- .../disttest/clientonly/MessageProviderTest.java | 119 -- .../clientonly/ProducerParticipantTest.java | 132 -- .../ControllerAndClientTest.java | 263 --- .../controllerandclient/iteratingFeature.json | 63 - .../controllerandclient/produceClient.json | 41 - .../producerAndConsumerInSeparateClients.json | 56 - ...producerAndThreeConsumersInSeparateClients.json | 77 - .../controllerandclient/testWithTwoTests.json | 107 -- .../controlleronly/DistributedControllerTest.java | 157 -- .../controlleronly/distributedControllerTest.json | 17 - .../systest/disttest/endtoend/EndToEndTest.java | 100 -- .../qpid/systest/disttest/endtoend/endtoend.json | 65 - .../systest/disttest/perftests.systests.properties | 29 - .../systest/disttest/ConfigFileTestHelper.java | 48 + .../disttest/DistributedTestSystemTestBase.java | 72 + .../systest/disttest/QpidQueueCreatorTest.java | 100 ++ .../qpid/systest/disttest/SystemTestConstants.java | 28 + .../clientonly/BasicDistributedClientTest.java | 186 +++ .../clientonly/ConsumerParticipantTest.java | 156 ++ .../disttest/clientonly/ControllerQueue.java | 110 ++ .../disttest/clientonly/DistributedClientTest.java | 325 ++++ .../disttest/clientonly/MessageProviderTest.java | 119 ++ .../clientonly/ProducerParticipantTest.java | 132 ++ .../ControllerAndClientTest.java | 263 +++ .../controlleronly/DistributedControllerTest.java | 157 ++ .../systest/disttest/endtoend/EndToEndTest.java | 100 ++ .../controllerandclient/iteratingFeature.json | 63 + .../controllerandclient/produceClient.json | 41 + .../producerAndConsumerInSeparateClients.json | 56 + ...producerAndThreeConsumersInSeparateClients.json | 77 + .../controllerandclient/testWithTwoTests.json | 107 ++ .../controlleronly/distributedControllerTest.json | 17 + .../qpid/systest/disttest/endtoend/endtoend.json | 65 + .../systest/disttest/perftests.systests.properties | 29 + qpid/java/qpid-systests-parent/pom.xml | 14 - .../qpid/client/AMQQueueDeferredOrderingTest.java | 145 -- .../apache/qpid/client/AMQTestConnection_0_10.java | 34 - .../qpid/client/AsynchMessageListenerTest.java | 362 ---- .../java/org/apache/qpid/client/HeartbeatTest.java | 224 --- .../org/apache/qpid/client/SessionCreateTest.java | 61 - .../org/apache/qpid/client/SynchReceiveTest.java | 133 -- .../AddressBasedFailoverBehaviourTest.java | 34 - .../client/failover/FailoverBehaviourTest.java | 1436 ---------------- .../failover/MultipleBrokersFailoverTest.java | 288 ---- .../client/message/AMQPEncodedMapMessageTest.java | 275 --- .../qpid/client/message/NonQpidObjectMessage.java | 235 --- .../client/prefetch/PrefetchBehaviourTest.java | 235 --- .../client/redelivered/RedeliveredMessageTest.java | 71 - .../qpid/client/session/QueueDeclareTest.java | 68 - .../java/org/apache/qpid/client/ssl/SSLTest.java | 485 ------ .../org/apache/qpid/jms/xa/XAResourceTest.java | 158 -- .../org/apache/qpid/ra/QpidRAConnectionTest.java | 89 - .../org/apache/qpid/ra/QpidRAXAResourceTest.java | 55 - .../ra/admin/QpidConnectionFactoryProxyTest.java | 113 -- .../org/apache/qpid/scripts/QpidPasswdTest.java | 80 - .../org/apache/qpid/server/BrokerStartupTest.java | 186 --- .../qpid/server/SupportedProtocolVersionsTest.java | 163 -- .../ReturnUnroutableMandatoryMessageTest.java | 306 ---- .../qpid/server/failover/FailoverMethodTest.java | 269 --- .../qpid/server/logging/AbstractTestLogging.java | 413 ----- .../server/logging/AccessControlLoggingTest.java | 177 -- .../apache/qpid/server/logging/AlertingTest.java | 196 --- .../qpid/server/logging/BindingLoggingTest.java | 227 --- .../qpid/server/logging/BrokerLoggingTest.java | 1035 ------------ .../qpid/server/logging/ChannelLoggingTest.java | 417 ----- .../qpid/server/logging/ConnectionLoggingTest.java | 198 --- .../qpid/server/logging/ConsumerLoggingTest.java | 407 ----- .../server/logging/DurableQueueLoggingTest.java | 311 ---- .../qpid/server/logging/ExchangeLoggingTest.java | 254 --- .../qpid/server/logging/QueueLoggingTest.java | 183 -- .../server/logging/TransientQueueLoggingTest.java | 30 - .../server/logging/VirtualHostLoggingTest.java | 130 -- .../message/MessageProtocolConversionTest.java | 322 ---- .../persistent/NoLocalAfterRecoveryTest.java | 185 --- .../MultiVersionProtocolEngineFactoryTest.java | 308 ---- .../server/queue/DeepQueueConsumeWithSelector.java | 159 -- .../qpid/server/queue/LastValueQueueTest.java | 574 ------- .../qpid/server/queue/MessageGroupQueueTest.java | 604 ------- .../org/apache/qpid/server/queue/ModelTest.java | 342 ---- .../queue/MultipleTransactedBatchProducerTest.java | 250 --- .../qpid/server/queue/PriorityQueueTest.java | 303 ---- .../qpid/server/queue/ProducerFlowControlTest.java | 494 ------ .../apache/qpid/server/queue/QueueBindTest.java | 130 -- .../server/queue/QueueDepthWithSelectorTest.java | 175 -- .../server/queue/QueueMessageDurabilityTest.java | 216 --- .../apache/qpid/server/queue/SortedQueueTest.java | 538 ------ .../apache/qpid/server/queue/TimeToLiveTest.java | 397 ----- .../server/security/acl/AbstractACLTestCase.java | 192 --- .../server/security/acl/ExhaustiveACLTest.java | 216 --- .../server/security/acl/ExternalACLJMXTest.java | 320 ---- .../qpid/server/security/acl/ExternalACLTest.java | 487 ------ .../auth/manager/ExternalAuthenticationTest.java | 374 ----- .../MultipleAuthenticationManagersTest.java | 127 -- .../qpid/server/stats/StatisticsReportingTest.java | 183 -- .../qpid/server/store/PersistentStoreTest.java | 164 -- .../apache/qpid/server/store/SplitStoreTest.java | 141 -- .../server/store/VirtualHostMessageStoreTest.java | 875 ---------- .../org/apache/qpid/server/util/AveragedRun.java | 68 - .../java/org/apache/qpid/server/util/RunStats.java | 57 - .../java/org/apache/qpid/server/util/TimedRun.java | 52 - .../management/jmx/BrokerManagementTest.java | 119 -- .../management/jmx/ConnectionManagementTest.java | 285 ---- .../management/jmx/ExchangeManagementTest.java | 164 -- .../management/jmx/LoggingManagementTest.java | 148 -- .../systest/management/jmx/MBeanLifeCycleTest.java | 140 -- .../management/jmx/ManagementActorLoggingTest.java | 482 ------ .../management/jmx/ManagementLoggingTest.java | 324 ---- .../management/jmx/QueueManagementTest.java | 869 ---------- .../systest/management/jmx/StatisticsTest.java | 211 --- .../systest/management/jmx/UserManagementTest.java | 261 --- .../UserManagementWithBase64MD5PasswordsTest.java | 37 - .../rest/AccessControlProviderRestTest.java | 288 ---- .../qpid/systest/rest/AnonymousAccessRestTest.java | 115 -- .../rest/AuthenticationProviderRestTest.java | 337 ---- .../qpid/systest/rest/BasicAuthRestTest.java | 122 -- .../apache/qpid/systest/rest/BindingRestTest.java | 131 -- .../systest/rest/BrokerRestHttpAndHttpsTest.java | 85 - .../rest/BrokerRestHttpsClientCertAuthTest.java | 86 - .../qpid/systest/rest/BrokerRestHttpsTest.java | 77 - .../apache/qpid/systest/rest/BrokerRestTest.java | 242 --- .../qpid/systest/rest/ConnectionRestTest.java | 281 ---- .../apache/qpid/systest/rest/ExchangeRestTest.java | 120 -- .../qpid/systest/rest/GroupProviderRestTest.java | 373 ----- .../apache/qpid/systest/rest/GroupRestTest.java | 109 -- .../qpid/systest/rest/HttpManagementRestTest.java | 91 - .../apache/qpid/systest/rest/KeyStoreRestTest.java | 272 --- .../qpid/systest/rest/LogRecordsRestTest.java | 63 - .../apache/qpid/systest/rest/LogViewerTest.java | 105 -- .../apache/qpid/systest/rest/MessagesRestTest.java | 355 ---- .../org/apache/qpid/systest/rest/PortRestTest.java | 366 ---- .../systest/rest/PreferencesProviderRestTest.java | 199 --- .../qpid/systest/rest/PreferencesRestTest.java | 114 -- .../apache/qpid/systest/rest/QueueRestTest.java | 262 --- .../org/apache/qpid/systest/rest/SaslRestTest.java | 384 ----- .../qpid/systest/rest/StructureRestTest.java | 129 -- .../qpid/systest/rest/TrustStoreRestTest.java | 263 --- .../qpid/systest/rest/UserPreferencesRestTest.java | 150 -- .../org/apache/qpid/systest/rest/UserRestTest.java | 100 -- .../qpid/systest/rest/VirtualHostNodeRestTest.java | 164 -- .../qpid/systest/rest/VirtualHostRestTest.java | 635 ------- .../qpid/systest/rest/acl/BrokerACLTest.java | 1009 ------------ .../qpid/systest/rest/acl/ExchangeRestACLTest.java | 244 --- .../qpid/systest/rest/acl/GroupRestACLTest.java | 193 --- .../qpid/systest/rest/acl/LogViewerACLTest.java | 99 -- .../qpid/systest/rest/acl/QueueRestACLTest.java | 188 --- .../rest/acl/UserPreferencesRestACLTest.java | 197 --- .../qpid/systest/rest/acl/UserRestACLTest.java | 195 --- .../qpid/systest/rest/acl/VirtualHostACLTest.java | 145 -- .../systest/rest/acl/VirtualHostNodeACLTest.java | 155 -- .../CloseOnNoRouteForMandatoryMessageTest.java | 241 --- .../org/apache/qpid/test/client/DupsOkTest.java | 167 -- .../apache/qpid/test/client/FlowControlTest.java | 220 --- .../ImmediateAndMandatoryPublishingTest.java | 237 --- .../qpid/test/client/QueueBrowserAutoAckTest.java | 440 ----- .../test/client/QueueBrowserClientAckTest.java | 34 - .../qpid/test/client/QueueBrowserDupsOkTest.java | 31 - .../qpid/test/client/QueueBrowserNoAckTest.java | 33 - .../qpid/test/client/QueueBrowserPreAckTest.java | 32 - .../test/client/QueueBrowserTransactedTest.java | 31 - .../apache/qpid/test/client/RollbackOrderTest.java | 189 --- .../UnroutableMessageTestExceptionListener.java | 178 -- .../destination/AddressBasedDestinationTest.java | 1464 ---------------- .../qpid/test/client/failover/FailoverTest.java | 349 ---- .../test/client/message/JMSDestinationTest.java | 359 ---- .../qpid/test/client/message/JMSReplyToTest.java | 169 -- .../test/client/message/MessageToStringTest.java | 255 --- .../test/client/message/ObjectMessageTest.java | 157 -- .../qpid/test/client/message/SelectorTest.java | 314 ---- .../org/apache/qpid/test/client/queue/LVQTest.java | 84 - .../qpid/test/client/queue/QueuePolicyTest.java | 120 -- .../test/unit/ack/Acknowledge2ConsumersTest.java | 193 --- .../test/unit/ack/AcknowledgeOnMessageTest.java | 226 --- .../apache/qpid/test/unit/ack/AcknowledgeTest.java | 188 --- .../qpid/test/unit/ack/ClientAcknowledgeTest.java | 82 - .../org/apache/qpid/test/unit/ack/RecoverTest.java | 483 ------ .../qpid/test/unit/basic/BytesMessageTest.java | 324 ---- .../test/unit/basic/FieldTableMessageTest.java | 165 -- .../test/unit/basic/InvalidDestinationTest.java | 171 -- .../qpid/test/unit/basic/LargeMessageTest.java | 190 --- .../qpid/test/unit/basic/MapMessageTest.java | 1269 -------------- .../test/unit/basic/MultipleConnectionTest.java | 223 --- .../qpid/test/unit/basic/ObjectMessageTest.java | 276 ---- .../qpid/test/unit/basic/PropertyValueTest.java | 386 ----- .../test/unit/basic/PubSubTwoConnectionTest.java | 75 - .../qpid/test/unit/basic/SessionStartTest.java | 115 -- .../qpid/test/unit/basic/TextMessageTest.java | 246 --- .../qpid/test/unit/basic/close/CloseTest.java | 58 - .../qpid/test/unit/client/AMQSessionTest.java | 104 -- .../client/DynamicQueueExchangeCreateTest.java | 258 --- .../test/unit/client/MaxDeliveryCountTest.java | 660 -------- .../test/unit/client/QueueSessionFactoryTest.java | 113 -- .../test/unit/client/TopicSessionFactoryTest.java | 98 -- .../channelclose/CloseWithBlockingReceiveTest.java | 73 - .../BrokerClosesClientConnectionTest.java | 215 --- .../client/connection/ConnectionFactoryTest.java | 78 - .../client/connection/ConnectionStartTest.java | 157 -- .../unit/client/connection/ConnectionTest.java | 378 ----- .../client/connection/ExceptionListenerTest.java | 244 --- .../unit/client/message/ObjectMessageTest.java | 334 ---- .../client/protocol/AMQProtocolSessionTest.java | 198 --- .../client/temporaryqueue/TemporaryQueueTest.java | 166 -- .../close/JavaServerCloseRaceConditionTest.java | 118 -- .../test/unit/close/MessageConsumerCloseTest.java | 77 - .../qpid/test/unit/close/MessageRequeueTest.java | 371 ----- .../test/unit/close/TopicPublisherCloseTest.java | 69 - .../qpid/test/unit/ct/DurableSubscriberTest.java | 503 ------ .../qpid/test/unit/message/JMSPropertiesTest.java | 206 --- .../qpid/test/unit/message/StreamMessageTest.java | 165 -- .../java/org/apache/qpid/test/unit/message/UTF8En | 4 - .../java/org/apache/qpid/test/unit/message/UTF8Jp | 4 - .../apache/qpid/test/unit/message/UTF8Test.java | 97 -- .../test/unit/topic/DurableSubscriptionTest.java | 1063 ------------ .../qpid/test/unit/topic/TemporaryTopicTest.java | 182 -- .../qpid/test/unit/topic/TopicPublisherTest.java | 76 - .../qpid/test/unit/topic/TopicSessionTest.java | 388 ----- .../test/unit/transacted/CommitRollbackTest.java | 544 ------ .../qpid/test/unit/transacted/TransactedTest.java | 389 ----- .../transacted/TransactionTimeoutDisabledTest.java | 77 - .../unit/transacted/TransactionTimeoutTest.java | 350 ---- .../transacted/TransactionTimeoutTestCase.java | 244 --- .../qpid/test/unit/xa/AbstractXATestCase.java | 138 -- .../org/apache/qpid/test/unit/xa/FaultTest.java | 414 ----- .../org/apache/qpid/test/unit/xa/QueueTest.java | 669 -------- .../org/apache/qpid/test/unit/xa/TopicTest.java | 1742 -------------------- .../qpid/test/utils/BrokerCommandHelperTest.java | 79 - .../qpid/test/utils/ConversationFactory.java | 484 ------ .../apache/qpid/test/utils/FailoverBaseCase.java | 94 -- .../apache/qpid/test/utils/QpidBrokerTestCase.java | 17 +- .../qpid/test/utils/QpidClientConnection.java | 288 ---- .../qpid/test/utils/SpawnedBrokerHolder.java | 98 +- .../apache/qpid/transport/MaxFrameSizeTest.java | 349 ---- .../org/apache/qpid/util/ClasspathScanner.java | 239 --- .../main/java/org/apache/qpid/util/LogMonitor.java | 336 ---- .../java/org/apache/qpid/util/LogMonitorTest.java | 274 --- qpid/java/systests/src/main/java/systests.log4j | 28 - .../qpid/client/AMQQueueDeferredOrderingTest.java | 145 ++ .../apache/qpid/client/AMQTestConnection_0_10.java | 34 + .../qpid/client/AsynchMessageListenerTest.java | 362 ++++ .../java/org/apache/qpid/client/HeartbeatTest.java | 224 +++ .../org/apache/qpid/client/SessionCreateTest.java | 61 + .../org/apache/qpid/client/SynchReceiveTest.java | 133 ++ .../AddressBasedFailoverBehaviourTest.java | 34 + .../client/failover/FailoverBehaviourTest.java | 1436 ++++++++++++++++ .../failover/MultipleBrokersFailoverTest.java | 288 ++++ .../client/message/AMQPEncodedMapMessageTest.java | 275 +++ .../qpid/client/message/NonQpidObjectMessage.java | 235 +++ .../client/prefetch/PrefetchBehaviourTest.java | 235 +++ .../client/redelivered/RedeliveredMessageTest.java | 71 + .../qpid/client/session/QueueDeclareTest.java | 68 + .../java/org/apache/qpid/client/ssl/SSLTest.java | 485 ++++++ .../org/apache/qpid/jms/xa/XAResourceTest.java | 158 ++ .../org/apache/qpid/ra/QpidRAConnectionTest.java | 89 + .../org/apache/qpid/ra/QpidRAXAResourceTest.java | 55 + .../ra/admin/QpidConnectionFactoryProxyTest.java | 113 ++ .../org/apache/qpid/scripts/QpidPasswdTest.java | 80 + .../org/apache/qpid/server/BrokerStartupTest.java | 186 +++ .../qpid/server/SupportedProtocolVersionsTest.java | 163 ++ .../ReturnUnroutableMandatoryMessageTest.java | 306 ++++ .../qpid/server/failover/FailoverMethodTest.java | 269 +++ .../qpid/server/logging/AbstractTestLogging.java | 413 +++++ .../server/logging/AccessControlLoggingTest.java | 177 ++ .../apache/qpid/server/logging/AlertingTest.java | 196 +++ .../qpid/server/logging/BindingLoggingTest.java | 227 +++ .../qpid/server/logging/BrokerLoggingTest.java | 1035 ++++++++++++ .../qpid/server/logging/ChannelLoggingTest.java | 417 +++++ .../qpid/server/logging/ConnectionLoggingTest.java | 198 +++ .../qpid/server/logging/ConsumerLoggingTest.java | 407 +++++ .../server/logging/DurableQueueLoggingTest.java | 311 ++++ .../qpid/server/logging/ExchangeLoggingTest.java | 254 +++ .../qpid/server/logging/QueueLoggingTest.java | 183 ++ .../server/logging/TransientQueueLoggingTest.java | 30 + .../server/logging/VirtualHostLoggingTest.java | 130 ++ .../message/MessageProtocolConversionTest.java | 322 ++++ .../persistent/NoLocalAfterRecoveryTest.java | 185 +++ .../MultiVersionProtocolEngineFactoryTest.java | 308 ++++ .../server/queue/DeepQueueConsumeWithSelector.java | 159 ++ .../qpid/server/queue/LastValueQueueTest.java | 574 +++++++ .../qpid/server/queue/MessageGroupQueueTest.java | 604 +++++++ .../org/apache/qpid/server/queue/ModelTest.java | 342 ++++ .../queue/MultipleTransactedBatchProducerTest.java | 250 +++ .../qpid/server/queue/PriorityQueueTest.java | 303 ++++ .../qpid/server/queue/ProducerFlowControlTest.java | 494 ++++++ .../apache/qpid/server/queue/QueueBindTest.java | 130 ++ .../server/queue/QueueDepthWithSelectorTest.java | 175 ++ .../server/queue/QueueMessageDurabilityTest.java | 216 +++ .../apache/qpid/server/queue/SortedQueueTest.java | 538 ++++++ .../apache/qpid/server/queue/TimeToLiveTest.java | 397 +++++ .../server/security/acl/AbstractACLTestCase.java | 192 +++ .../server/security/acl/ExhaustiveACLTest.java | 216 +++ .../server/security/acl/ExternalACLJMXTest.java | 320 ++++ .../qpid/server/security/acl/ExternalACLTest.java | 487 ++++++ .../auth/manager/ExternalAuthenticationTest.java | 374 +++++ .../MultipleAuthenticationManagersTest.java | 127 ++ .../qpid/server/stats/StatisticsReportingTest.java | 183 ++ .../qpid/server/store/PersistentStoreTest.java | 164 ++ .../apache/qpid/server/store/SplitStoreTest.java | 141 ++ .../server/store/VirtualHostMessageStoreTest.java | 875 ++++++++++ .../org/apache/qpid/server/util/AveragedRun.java | 68 + .../java/org/apache/qpid/server/util/RunStats.java | 57 + .../java/org/apache/qpid/server/util/TimedRun.java | 52 + .../management/jmx/BrokerManagementTest.java | 119 ++ .../management/jmx/ConnectionManagementTest.java | 285 ++++ .../management/jmx/ExchangeManagementTest.java | 164 ++ .../management/jmx/LoggingManagementTest.java | 148 ++ .../systest/management/jmx/MBeanLifeCycleTest.java | 140 ++ .../management/jmx/ManagementActorLoggingTest.java | 482 ++++++ .../management/jmx/ManagementLoggingTest.java | 324 ++++ .../management/jmx/QueueManagementTest.java | 869 ++++++++++ .../systest/management/jmx/StatisticsTest.java | 211 +++ .../systest/management/jmx/UserManagementTest.java | 261 +++ .../UserManagementWithBase64MD5PasswordsTest.java | 37 + .../rest/AccessControlProviderRestTest.java | 288 ++++ .../qpid/systest/rest/AnonymousAccessRestTest.java | 115 ++ .../rest/AuthenticationProviderRestTest.java | 337 ++++ .../qpid/systest/rest/BasicAuthRestTest.java | 122 ++ .../apache/qpid/systest/rest/BindingRestTest.java | 131 ++ .../systest/rest/BrokerRestHttpAndHttpsTest.java | 85 + .../rest/BrokerRestHttpsClientCertAuthTest.java | 86 + .../qpid/systest/rest/BrokerRestHttpsTest.java | 77 + .../apache/qpid/systest/rest/BrokerRestTest.java | 242 +++ .../systest/rest/CompressedResponsesRestTest.java | 141 ++ .../qpid/systest/rest/ConnectionRestTest.java | 281 ++++ .../apache/qpid/systest/rest/ExchangeRestTest.java | 120 ++ .../qpid/systest/rest/GroupProviderRestTest.java | 373 +++++ .../apache/qpid/systest/rest/GroupRestTest.java | 109 ++ .../qpid/systest/rest/HttpManagementRestTest.java | 91 + .../apache/qpid/systest/rest/KeyStoreRestTest.java | 272 +++ .../qpid/systest/rest/LogRecordsRestTest.java | 63 + .../apache/qpid/systest/rest/LogViewerTest.java | 105 ++ .../apache/qpid/systest/rest/MessagesRestTest.java | 355 ++++ .../org/apache/qpid/systest/rest/PortRestTest.java | 366 ++++ .../systest/rest/PreferencesProviderRestTest.java | 199 +++ .../qpid/systest/rest/PreferencesRestTest.java | 114 ++ .../apache/qpid/systest/rest/QueueRestTest.java | 262 +++ .../org/apache/qpid/systest/rest/SaslRestTest.java | 384 +++++ .../qpid/systest/rest/StructureRestTest.java | 129 ++ .../qpid/systest/rest/TrustStoreRestTest.java | 263 +++ .../qpid/systest/rest/UserPreferencesRestTest.java | 150 ++ .../org/apache/qpid/systest/rest/UserRestTest.java | 100 ++ .../qpid/systest/rest/VirtualHostNodeRestTest.java | 191 +++ .../qpid/systest/rest/VirtualHostRestTest.java | 631 +++++++ .../qpid/systest/rest/acl/BrokerACLTest.java | 1009 ++++++++++++ .../qpid/systest/rest/acl/ExchangeRestACLTest.java | 244 +++ .../qpid/systest/rest/acl/GroupRestACLTest.java | 193 +++ .../qpid/systest/rest/acl/LogViewerACLTest.java | 99 ++ .../qpid/systest/rest/acl/QueueRestACLTest.java | 188 +++ .../rest/acl/UserPreferencesRestACLTest.java | 197 +++ .../qpid/systest/rest/acl/UserRestACLTest.java | 195 +++ .../qpid/systest/rest/acl/VirtualHostACLTest.java | 145 ++ .../systest/rest/acl/VirtualHostNodeACLTest.java | 155 ++ .../CloseOnNoRouteForMandatoryMessageTest.java | 241 +++ .../org/apache/qpid/test/client/DupsOkTest.java | 167 ++ .../apache/qpid/test/client/FlowControlTest.java | 220 +++ .../ImmediateAndMandatoryPublishingTest.java | 237 +++ .../qpid/test/client/QueueBrowserAutoAckTest.java | 440 +++++ .../test/client/QueueBrowserClientAckTest.java | 34 + .../qpid/test/client/QueueBrowserDupsOkTest.java | 31 + .../qpid/test/client/QueueBrowserNoAckTest.java | 33 + .../qpid/test/client/QueueBrowserPreAckTest.java | 32 + .../test/client/QueueBrowserTransactedTest.java | 31 + .../apache/qpid/test/client/RollbackOrderTest.java | 189 +++ .../UnroutableMessageTestExceptionListener.java | 178 ++ .../destination/AddressBasedDestinationTest.java | 1464 ++++++++++++++++ .../qpid/test/client/failover/FailoverTest.java | 349 ++++ .../test/client/message/JMSDestinationTest.java | 359 ++++ .../qpid/test/client/message/JMSReplyToTest.java | 169 ++ .../test/client/message/MessageToStringTest.java | 255 +++ .../test/client/message/ObjectMessageTest.java | 157 ++ .../qpid/test/client/message/SelectorTest.java | 314 ++++ .../org/apache/qpid/test/client/queue/LVQTest.java | 84 + .../qpid/test/client/queue/QueuePolicyTest.java | 120 ++ .../test/unit/ack/Acknowledge2ConsumersTest.java | 193 +++ .../test/unit/ack/AcknowledgeOnMessageTest.java | 226 +++ .../apache/qpid/test/unit/ack/AcknowledgeTest.java | 188 +++ .../qpid/test/unit/ack/ClientAcknowledgeTest.java | 82 + .../org/apache/qpid/test/unit/ack/RecoverTest.java | 483 ++++++ .../qpid/test/unit/basic/BytesMessageTest.java | 324 ++++ .../test/unit/basic/FieldTableMessageTest.java | 165 ++ .../test/unit/basic/InvalidDestinationTest.java | 171 ++ .../qpid/test/unit/basic/LargeMessageTest.java | 190 +++ .../qpid/test/unit/basic/MapMessageTest.java | 1269 ++++++++++++++ .../test/unit/basic/MultipleConnectionTest.java | 223 +++ .../qpid/test/unit/basic/ObjectMessageTest.java | 276 ++++ .../qpid/test/unit/basic/PropertyValueTest.java | 386 +++++ .../test/unit/basic/PubSubTwoConnectionTest.java | 75 + .../qpid/test/unit/basic/SessionStartTest.java | 115 ++ .../qpid/test/unit/basic/TextMessageTest.java | 246 +++ .../qpid/test/unit/basic/close/CloseTest.java | 58 + .../qpid/test/unit/client/AMQSessionTest.java | 104 ++ .../client/DynamicQueueExchangeCreateTest.java | 258 +++ .../test/unit/client/MaxDeliveryCountTest.java | 660 ++++++++ .../test/unit/client/QueueSessionFactoryTest.java | 113 ++ .../test/unit/client/TopicSessionFactoryTest.java | 98 ++ .../channelclose/CloseWithBlockingReceiveTest.java | 73 + .../BrokerClosesClientConnectionTest.java | 215 +++ .../client/connection/ConnectionFactoryTest.java | 78 + .../client/connection/ConnectionStartTest.java | 157 ++ .../unit/client/connection/ConnectionTest.java | 378 +++++ .../client/connection/ExceptionListenerTest.java | 244 +++ .../unit/client/message/ObjectMessageTest.java | 334 ++++ .../client/protocol/AMQProtocolSessionTest.java | 198 +++ .../client/temporaryqueue/TemporaryQueueTest.java | 166 ++ .../close/JavaServerCloseRaceConditionTest.java | 118 ++ .../test/unit/close/MessageConsumerCloseTest.java | 77 + .../qpid/test/unit/close/MessageRequeueTest.java | 371 +++++ .../test/unit/close/TopicPublisherCloseTest.java | 69 + .../qpid/test/unit/ct/DurableSubscriberTest.java | 503 ++++++ .../qpid/test/unit/message/JMSPropertiesTest.java | 206 +++ .../qpid/test/unit/message/StreamMessageTest.java | 165 ++ .../apache/qpid/test/unit/message/UTF8Test.java | 97 ++ .../test/unit/topic/DurableSubscriptionTest.java | 1063 ++++++++++++ .../qpid/test/unit/topic/TemporaryTopicTest.java | 182 ++ .../qpid/test/unit/topic/TopicPublisherTest.java | 76 + .../qpid/test/unit/topic/TopicSessionTest.java | 388 +++++ .../test/unit/transacted/CommitRollbackTest.java | 544 ++++++ .../qpid/test/unit/transacted/TransactedTest.java | 389 +++++ .../transacted/TransactionTimeoutDisabledTest.java | 77 + .../unit/transacted/TransactionTimeoutTest.java | 350 ++++ .../transacted/TransactionTimeoutTestCase.java | 244 +++ .../qpid/test/unit/xa/AbstractXATestCase.java | 138 ++ .../org/apache/qpid/test/unit/xa/FaultTest.java | 414 +++++ .../org/apache/qpid/test/unit/xa/QueueTest.java | 669 ++++++++ .../org/apache/qpid/test/unit/xa/TopicTest.java | 1742 ++++++++++++++++++++ .../qpid/test/utils/BrokerCommandHelperTest.java | 79 + .../qpid/test/utils/ConversationFactory.java | 484 ++++++ .../apache/qpid/test/utils/FailoverBaseCase.java | 94 ++ .../qpid/test/utils/QpidClientConnection.java | 288 ++++ .../apache/qpid/transport/MaxFrameSizeTest.java | 349 ++++ .../org/apache/qpid/util/ClasspathScanner.java | 239 +++ .../test/java/org/apache/qpid/util/LogMonitor.java | 336 ++++ .../java/org/apache/qpid/util/LogMonitorTest.java | 274 +++ .../org/apache/qpid/test/unit/message/UTF8En | 4 + .../org/apache/qpid/test/unit/message/UTF8Jp | 4 + .../systests/src/test/resources/systests.log4j | 28 + qpid/java/test-profiles/CPPExcludes | 2 + qpid/java/test-profiles/JavaJsonExcludes | 2 +- qpid/java/test-profiles/JavaTransientExcludes | 1 - .../main/java/org/apache/qpid/tools/JNDICheck.java | 27 +- 507 files changed, 57898 insertions(+), 57660 deletions(-) delete mode 100644 qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBBackupTest.java delete mode 100644 qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeRestTest.java delete mode 100644 qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostRestTest.java delete mode 100644 qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java delete mode 100644 qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HAClusterBlackboxTest.java delete mode 100644 qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HAClusterManagementTest.java delete mode 100644 qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HAClusterTwoNodeTest.java delete mode 100644 qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HAClusterWhiteboxTest.java delete mode 100644 qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HATestClusterCreator.java create mode 100644 qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBBackupTest.java create mode 100644 qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java create mode 100644 qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostNodeRestTest.java create mode 100644 qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostRestTest.java create mode 100644 qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/GroupCreator.java create mode 100644 qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/JMXManagementTest.java create mode 100644 qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/MultiNodeTest.java create mode 100644 qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/TwoNodeTest.java delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/ConfigFileTestHelper.java delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/DistributedTestSystemTestBase.java delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/QpidQueueCreatorTest.java delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/SystemTestConstants.java delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/BasicDistributedClientTest.java delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/ConsumerParticipantTest.java delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/ControllerQueue.java delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/DistributedClientTest.java delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/MessageProviderTest.java delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/ProducerParticipantTest.java delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/ControllerAndClientTest.java delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/iteratingFeature.json delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/produceClient.json delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndConsumerInSeparateClients.json delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndThreeConsumersInSeparateClients.json delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/testWithTwoTests.json delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controlleronly/DistributedControllerTest.java delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controlleronly/distributedControllerTest.json delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/endtoend/EndToEndTest.java delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/endtoend/endtoend.json delete mode 100644 qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/perftests.systests.properties create mode 100644 qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/ConfigFileTestHelper.java create mode 100644 qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/DistributedTestSystemTestBase.java create mode 100644 qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/QpidQueueCreatorTest.java create mode 100644 qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/SystemTestConstants.java create mode 100644 qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/BasicDistributedClientTest.java create mode 100644 qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ConsumerParticipantTest.java create mode 100644 qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ControllerQueue.java create mode 100644 qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/DistributedClientTest.java create mode 100644 qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/MessageProviderTest.java create mode 100644 qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ProducerParticipantTest.java create mode 100644 qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/ControllerAndClientTest.java create mode 100644 qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/controlleronly/DistributedControllerTest.java create mode 100644 qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/endtoend/EndToEndTest.java create mode 100644 qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/iteratingFeature.json create mode 100644 qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/produceClient.json create mode 100644 qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/producerAndConsumerInSeparateClients.json create mode 100644 qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/producerAndThreeConsumersInSeparateClients.json create mode 100644 qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/testWithTwoTests.json create mode 100644 qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controlleronly/distributedControllerTest.json create mode 100644 qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/endtoend/endtoend.json create mode 100644 qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/perftests.systests.properties delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/client/AMQTestConnection_0_10.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/client/AsynchMessageListenerTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/client/HeartbeatTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/client/SessionCreateTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/client/SynchReceiveTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/client/failover/AddressBasedFailoverBehaviourTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/client/failover/FailoverBehaviourTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/client/failover/MultipleBrokersFailoverTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessageTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/client/message/NonQpidObjectMessage.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/client/redelivered/RedeliveredMessageTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/client/session/QueueDeclareTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/jms/xa/XAResourceTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/ra/QpidRAConnectionTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/ra/QpidRAXAResourceTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxyTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/scripts/QpidPasswdTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/BrokerStartupTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/SupportedProtocolVersionsTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/exchange/ReturnUnroutableMandatoryMessageTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/failover/FailoverMethodTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AbstractTestLogging.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AccessControlLoggingTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AlertingTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BindingLoggingTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BrokerLoggingTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ChannelLoggingTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ConnectionLoggingTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ConsumerLoggingTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/logging/DurableQueueLoggingTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ExchangeLoggingTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/logging/QueueLoggingTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/logging/TransientQueueLoggingTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/message/MessageProtocolConversionTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/persistent/NoLocalAfterRecoveryTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactoryTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/queue/DeepQueueConsumeWithSelector.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/queue/LastValueQueueTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/queue/MessageGroupQueueTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/queue/MultipleTransactedBatchProducerTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/queue/PriorityQueueTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/queue/QueueBindTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/queue/QueueMessageDurabilityTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/queue/SortedQueueTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/queue/TimeToLiveTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExhaustiveACLTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/stats/StatisticsReportingTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/store/PersistentStoreTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/store/SplitStoreTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/store/VirtualHostMessageStoreTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/util/AveragedRun.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/util/RunStats.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/server/util/TimedRun.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ExchangeManagementTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/MBeanLifeCycleTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AccessControlProviderRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AnonymousAccessRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BindingRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpAndHttpsTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpsClientCertAuthTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/ConnectionRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/ExchangeRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/HttpManagementRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/KeyStoreRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/LogRecordsRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/LogViewerTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/MessagesRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PortRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PreferencesProviderRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PreferencesRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QueueRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/SaslRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/StructureRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/TrustStoreRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/UserPreferencesRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/UserRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/VirtualHostNodeRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/ExchangeRestACLTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/LogViewerACLTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/QueueRestACLTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/UserPreferencesRestACLTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/VirtualHostACLTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/VirtualHostNodeACLTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/CloseOnNoRouteForMandatoryMessageTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/FlowControlTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/ImmediateAndMandatoryPublishingTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserClientAckTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserDupsOkTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserNoAckTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserPreAckTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserTransactedTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/RollbackOrderTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/UnroutableMessageTestExceptionListener.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/destination/AddressBasedDestinationTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/failover/FailoverTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/JMSDestinationTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/JMSReplyToTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/MessageToStringTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/ObjectMessageTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/SelectorTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/queue/LVQTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/client/queue/QueuePolicyTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/Acknowledge2ConsumersTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeOnMessageTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/ClientAcknowledgeTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/FieldTableMessageTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/MapMessageTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/ObjectMessageTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/PropertyValueTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/PubSubTwoConnectionTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SessionStartTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/TextMessageTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/close/CloseTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQSessionTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/MaxDeliveryCountTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/QueueSessionFactoryTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/TopicSessionFactoryTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/CloseWithBlockingReceiveTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/BrokerClosesClientConnectionTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionFactoryTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ExceptionListenerTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/message/ObjectMessageTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/JavaServerCloseRaceConditionTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageConsumerCloseTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/TopicPublisherCloseTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ct/DurableSubscriberTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/StreamMessageTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8En delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8Jp delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8Test.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TemporaryTopicTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicPublisherTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutDisabledTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTestCase.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/AbstractXATestCase.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/FaultTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/QueueTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/TopicTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/utils/BrokerCommandHelperTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/utils/ConversationFactory.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidClientConnection.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/transport/MaxFrameSizeTest.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/util/ClasspathScanner.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/util/LogMonitor.java delete mode 100644 qpid/java/systests/src/main/java/org/apache/qpid/util/LogMonitorTest.java delete mode 100644 qpid/java/systests/src/main/java/systests.log4j create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/client/AMQTestConnection_0_10.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/client/AsynchMessageListenerTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/client/HeartbeatTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/client/SessionCreateTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/client/SynchReceiveTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/client/failover/AddressBasedFailoverBehaviourTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/client/failover/FailoverBehaviourTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/client/failover/MultipleBrokersFailoverTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/client/message/AMQPEncodedMapMessageTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/client/message/NonQpidObjectMessage.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/client/redelivered/RedeliveredMessageTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/client/session/QueueDeclareTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/client/ssl/SSLTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/jms/xa/XAResourceTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/ra/QpidRAConnectionTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/ra/QpidRAXAResourceTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxyTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/scripts/QpidPasswdTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/BrokerStartupTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/SupportedProtocolVersionsTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/exchange/ReturnUnroutableMandatoryMessageTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/failover/FailoverMethodTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/logging/AbstractTestLogging.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/logging/AccessControlLoggingTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/logging/AlertingTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/logging/BindingLoggingTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/logging/BrokerLoggingTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/logging/ChannelLoggingTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/logging/ConnectionLoggingTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/logging/ConsumerLoggingTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/logging/DurableQueueLoggingTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/logging/ExchangeLoggingTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/logging/QueueLoggingTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/logging/TransientQueueLoggingTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/message/MessageProtocolConversionTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/persistent/NoLocalAfterRecoveryTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactoryTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/queue/DeepQueueConsumeWithSelector.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/queue/LastValueQueueTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/queue/MessageGroupQueueTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/queue/ModelTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/queue/MultipleTransactedBatchProducerTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/queue/PriorityQueueTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/queue/QueueBindTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/queue/QueueMessageDurabilityTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/queue/SortedQueueTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/queue/TimeToLiveTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/security/acl/ExhaustiveACLTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/security/acl/ExternalACLTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/stats/StatisticsReportingTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/store/PersistentStoreTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/store/SplitStoreTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/store/VirtualHostMessageStoreTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/util/AveragedRun.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/util/RunStats.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/server/util/TimedRun.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ExchangeManagementTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/MBeanLifeCycleTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AccessControlProviderRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AnonymousAccessRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BindingRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpAndHttpsTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsClientCertAuthTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/CompressedResponsesRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ConnectionRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ExchangeRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/GroupRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/HttpManagementRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/KeyStoreRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/LogRecordsRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/LogViewerTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/MessagesRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PreferencesProviderRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PreferencesRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/QueueRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/SaslRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/StructureRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/TrustStoreRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/UserPreferencesRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/UserRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/VirtualHostNodeRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/ExchangeRestACLTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/LogViewerACLTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/QueueRestACLTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/UserPreferencesRestACLTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/VirtualHostACLTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/VirtualHostNodeACLTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/CloseOnNoRouteForMandatoryMessageTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/DupsOkTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/FlowControlTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/ImmediateAndMandatoryPublishingTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserClientAckTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserDupsOkTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserNoAckTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserPreAckTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserTransactedTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/RollbackOrderTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/UnroutableMessageTestExceptionListener.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/destination/AddressBasedDestinationTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/failover/FailoverTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/JMSDestinationTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/JMSReplyToTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/MessageToStringTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/ObjectMessageTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/SelectorTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/queue/LVQTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/client/queue/QueuePolicyTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/Acknowledge2ConsumersTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/AcknowledgeOnMessageTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/ClientAcknowledgeTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/RecoverTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/FieldTableMessageTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/MapMessageTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/ObjectMessageTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/PropertyValueTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/PubSubTwoConnectionTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/SessionStartTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/TextMessageTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/close/CloseTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/AMQSessionTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/MaxDeliveryCountTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/QueueSessionFactoryTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/TopicSessionFactoryTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/channelclose/CloseWithBlockingReceiveTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/BrokerClosesClientConnectionTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionFactoryTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/ExceptionListenerTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/message/ObjectMessageTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/close/JavaServerCloseRaceConditionTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/close/MessageConsumerCloseTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/close/TopicPublisherCloseTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ct/DurableSubscriberTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/message/StreamMessageTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/message/UTF8Test.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/topic/TemporaryTopicTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/topic/TopicPublisherTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/TransactedTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutDisabledTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTestCase.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/xa/AbstractXATestCase.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/xa/FaultTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/xa/QueueTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/unit/xa/TopicTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/utils/BrokerCommandHelperTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/utils/ConversationFactory.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/utils/FailoverBaseCase.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/test/utils/QpidClientConnection.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/transport/MaxFrameSizeTest.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/util/ClasspathScanner.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/util/LogMonitor.java create mode 100644 qpid/java/systests/src/test/java/org/apache/qpid/util/LogMonitorTest.java create mode 100644 qpid/java/systests/src/test/resources/org/apache/qpid/test/unit/message/UTF8En create mode 100644 qpid/java/systests/src/test/resources/org/apache/qpid/test/unit/message/UTF8Jp create mode 100644 qpid/java/systests/src/test/resources/systests.log4j diff --git a/qpid/java/amqp-1-0-client-jms/example/src/main/java/org/apache/qpid/amqp_1_0/jms/example/Hello.java b/qpid/java/amqp-1-0-client-jms/example/src/main/java/org/apache/qpid/amqp_1_0/jms/example/Hello.java index b94c672133..670f358a26 100644 --- a/qpid/java/amqp-1-0-client-jms/example/src/main/java/org/apache/qpid/amqp_1_0/jms/example/Hello.java +++ b/qpid/java/amqp-1-0-client-jms/example/src/main/java/org/apache/qpid/amqp_1_0/jms/example/Hello.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.amqp_1_0.jms.example; +import java.io.InputStream; import java.util.Properties; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -51,11 +52,11 @@ public class Hello private void runExample() { - try + try(InputStream propertiesStream = getClass().getResourceAsStream("hello.properties")) { - // Read the hello.properties JNDI properties file and use contents to create the InitialContext. Properties properties = new Properties(); - properties.load(getClass().getResourceAsStream("hello.properties")); + // Read the hello.properties JNDI properties file and use contents to create the InitialContext. + properties.load(propertiesStream); Context context = new InitialContext(properties); // Alternatively, JNDI information can be supplied by setting the "java.naming.factory.initial" // system property to value "org.apache.qpid.amqp_1_0.jms.jndi.PropertiesFileInitialContextFactory" diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacade.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacade.java index 92115dd39f..d045ae01fa 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacade.java +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacade.java @@ -95,7 +95,7 @@ import org.apache.qpid.server.util.DaemonThreadFactory; public class ReplicatedEnvironmentFacade implements EnvironmentFacade, StateChangeListener { public static final String MASTER_TRANSFER_TIMEOUT_PROPERTY_NAME = "qpid.bdb.ha.master_transfer_interval"; - public static final String DB_PING_SOCKET_TIMEOUT_PROPERTY_NAME = "qpid.bdb.ha.db_ping_socket_timeout"; + public static final String DB_PING_SOCKET_TIMEOUT_PROPERTY_NAME = "qpid.bdb.replication.db_ping_socket_timeout"; public static final String REMOTE_NODE_MONITOR_INTERVAL_PROPERTY_NAME = "qpid.bdb.ha.remote_node_monitor_interval"; private static final Logger LOGGER = Logger.getLogger(ReplicatedEnvironmentFacade.class); @@ -289,10 +289,20 @@ public class ReplicatedEnvironmentFacade implements EnvironmentFacade, StateChan { try { + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug("Closing replicated environment"); + } + closeEnvironment(); } finally { + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug("Deregistering environment home " + _environmentDirectory); + } + EnvHomeRegistry.getInstance().deregisterHome(_environmentDirectory); } } @@ -823,6 +833,11 @@ public class ReplicatedEnvironmentFacade implements EnvironmentFacade, StateChan private void closeEnvironment() { + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug("Closing JE environment for " + _prettyGroupNodeName); + } + // Clean the log before closing. This makes sure it doesn't contain // redundant data. Closing without doing this means the cleaner may not // get a chance to finish. @@ -1094,15 +1109,6 @@ public class ReplicatedEnvironmentFacade implements EnvironmentFacade, StateChan return environment; } - NodeState getRemoteNodeState(ReplicationNode repNode) throws IOException, ServiceConnectFailedException - { - if (repNode == null) - { - throw new IllegalArgumentException("Node cannot be null"); - } - return new DbPing(repNode, (String)_configuration.getGroupName(), DB_PING_SOCKET_TIMEOUT).getNodeState(); - } - public int getNumberOfElectableGroupMembers() { if (_state.get() != State.OPEN) @@ -1181,6 +1187,105 @@ public class ReplicatedEnvironmentFacade implements EnvironmentFacade, StateChan } } + Set getPermittedNodes() + { + return Collections.unmodifiableSet(_permittedNodes); + } + + public static NodeState getRemoteNodeState(String groupName, ReplicationNode repNode) throws IOException, ServiceConnectFailedException + { + if (repNode == null) + { + throw new IllegalArgumentException("Node cannot be null"); + } + return new DbPing(repNode, groupName, DB_PING_SOCKET_TIMEOUT).getNodeState(); + } + + public static Set convertApplicationStateBytesToPermittedNodeList(byte[] applicationState) + { + if (applicationState == null || applicationState.length == 0) + { + return Collections.emptySet(); + } + + ObjectMapper objectMapper = new ObjectMapper(); + try + { + Map settings = objectMapper.readValue(applicationState, Map.class); + return new HashSet((Collection)settings.get(PERMITTED_NODE_LIST)); + } + catch (Exception e) + { + throw new RuntimeException("Unexpected exception on de-serializing of application state", e); + } + } + + public static void connectToHelperNodeAndCheckPermittedHosts(String nodeName, String hostPort, String groupName, String helperNodeName, String helperHostPort) + { + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug(String.format("Requesting state of the node '%s' at '%s'", helperNodeName, helperHostPort)); + } + + if (helperNodeName == null || "".equals(helperNodeName)) + { + throw new IllegalConfigurationException(String.format("A helper node is not specified for node '%s'" + + " joining the group '%s'", nodeName, groupName)); + } + + Collection permittedNodes = null; + try + { + ReplicationNodeImpl node = new ReplicationNodeImpl(helperNodeName, helperHostPort); + NodeState state = getRemoteNodeState(groupName, node); + byte[] applicationState = state.getAppState(); + permittedNodes = convertApplicationStateBytesToPermittedNodeList(applicationState); + } + catch (IOException e) + { + throw new IllegalConfigurationException(String.format("Cannot connect to '%s'", helperHostPort), e); + } + catch (ServiceConnectFailedException e) + { + throw new IllegalConfigurationException(String.format("Failure to connect to '%s'", helperHostPort), e); + } + catch (Exception e) + { + throw new RuntimeException(String.format("Unexpected exception on attempt to retrieve state from '%s' at '%s'", + helperNodeName, helperHostPort), e); + } + + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug(String.format("Attribute 'permittedNodes' on node '%s' is set to '%s'", helperNodeName, String.valueOf(permittedNodes))); + } + + if (permittedNodes==null || !permittedNodes.contains(hostPort)) + { + throw new IllegalConfigurationException(String.format("Node from '%s' is not permitted!", hostPort)); + } + } + + private void findMasterNodeStateAndApplyPermittedNodes(Collection nodeStates) + { + if (ReplicatedEnvironment.State.MASTER != _environment.getState()) + { + for (NodeState nodeState : nodeStates) + { + if (nodeState.getNodeState() == ReplicatedEnvironment.State.MASTER) + { + byte[] applicationState = nodeState.getAppState(); + Set permittedNodes = convertApplicationStateBytesToPermittedNodeList(applicationState); + if (!_permittedNodes.equals(permittedNodes)) + { + setPermittedNodes(permittedNodes); + } + break; + } + } + } + } + private void registerAppStateMonitorIfPermittedNodesSpecified() { if (!_permittedNodes.isEmpty()) @@ -1286,8 +1391,9 @@ public class ReplicatedEnvironmentFacade implements EnvironmentFacade, StateChan executeDatabasePingerOnNodeChangesIfMaster(nodeStates); notifyGroupListenerAboutNodeStates(nodeStates); - } + findMasterNodeStateAndApplyPermittedNodes(nodeStates.values()); + } } finally { @@ -1384,7 +1490,7 @@ public class ReplicatedEnvironmentFacade implements EnvironmentFacade, StateChan NodeState nodeStateObject = null; try { - nodeStateObject = getRemoteNodeState(node); + nodeStateObject = getRemoteNodeState((String)_configuration.getGroupName(), node); } catch (IOException | ServiceConnectFailedException e ) { diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBVirtualHost.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBVirtualHost.java index 12511ad9e0..ac8d33685a 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBVirtualHost.java +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBVirtualHost.java @@ -38,7 +38,7 @@ public interface BDBVirtualHost> extends VirtualHost Math.min(200l*1024l*1024l, Runtime.getRuntime().maxMemory()/20l)); - @ManagedAttribute(mandatory = true) + @ManagedAttribute(mandatory = true, defaultValue = "${qpid.work_dir}${file.separator}${this:name}${file.separator}messages") String getStorePath(); @ManagedAttribute(mandatory = true, defaultValue = "0") diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeImpl.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeImpl.java index cacb04736c..5489493f74 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeImpl.java +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeImpl.java @@ -20,11 +20,9 @@ */ package org.apache.qpid.server.virtualhostnode.berkeleydb; -import java.io.IOException; import java.net.InetSocketAddress; import java.security.PrivilegedAction; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -43,10 +41,8 @@ import com.sleepycat.je.rep.ReplicatedEnvironment; import com.sleepycat.je.rep.ReplicationNode; import com.sleepycat.je.rep.StateChangeEvent; import com.sleepycat.je.rep.StateChangeListener; -import com.sleepycat.je.rep.util.DbPing; import com.sleepycat.je.rep.util.ReplicationGroupAdmin; import com.sleepycat.je.rep.utilint.HostPortPair; -import com.sleepycat.je.rep.utilint.ServiceDispatcher; import org.apache.log4j.Logger; import org.apache.qpid.server.configuration.IllegalConfigurationException; @@ -73,7 +69,6 @@ import org.apache.qpid.server.store.berkeleydb.replication.ReplicationGroupListe import org.apache.qpid.server.util.ServerScopedRuntimeException; import org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHostImpl; import org.apache.qpid.server.virtualhostnode.AbstractVirtualHostNode; -import org.codehaus.jackson.map.ObjectMapper; @ManagedObject( category = false, type = BDBHAVirtualHostNodeImpl.VIRTUAL_HOST_NODE_TYPE ) public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode implements @@ -263,7 +258,7 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode permittedNodes = null; - try - { - ReplicatedEnvironmentFacade.ReplicationNodeImpl node = new ReplicatedEnvironmentFacade.ReplicationNodeImpl(helperNodeName, helperHostPort); - NodeState state = new DbPing(node, getGroupName(), ReplicatedEnvironmentFacade.DB_PING_SOCKET_TIMEOUT).getNodeState(); - byte[] applicationState = state.getAppState(); - permittedNodes = bytesToPermittedNodeList(applicationState); - } - catch (IOException e) - { - throw new IllegalConfigurationException(String.format("Cannot connect to '%s'", helperHostPort), e); - } - catch (ServiceDispatcher.ServiceConnectFailedException e) - { - throw new IllegalConfigurationException(String.format("Failure to connect to '%s'", helperHostPort), e); - } - catch (Exception e) - { - throw new RuntimeException(String.format("Unexpected exception on attempt to retrieve state from '%s' at '%s'", - helperNodeName, helperHostPort), e); - } - - if (LOGGER.isDebugEnabled()) - { - LOGGER.debug(String.format("Attribute 'permittedNodes' on node '%s' is set to '%s'", helperNodeName, String.valueOf(permittedNodes))); - } - - if (permittedNodes != null && !permittedNodes.isEmpty() && !permittedNodes.contains(hostPort)) - { - throw new IllegalConfigurationException(String.format("Node from '%s' is not permitted!", hostPort)); - } - } - - private Collection bytesToPermittedNodeList(byte[] applicationState) - { - if (applicationState == null || applicationState.length == 0) - { - return Collections.emptySet(); - } - - ObjectMapper objectMapper = new ObjectMapper(); - try - { - Map settings = objectMapper.readValue(applicationState, Map.class); - return (Collection)settings.get(ReplicatedEnvironmentFacade.PERMITTED_NODE_LIST); - } - catch (Exception e) - { - throw new RuntimeException("Unexpected exception on de-serializing of application state", e); - } - } - private class RemoteNodesDiscoverer implements ReplicationGroupListener { @Override diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBVirtualHostNode.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBVirtualHostNode.java index 763b59146b..61b0d1882a 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBVirtualHostNode.java +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBVirtualHostNode.java @@ -26,6 +26,6 @@ public interface BDBVirtualHostNode> extends org { String STORE_PATH = "storePath"; - @ManagedAttribute(mandatory = true) + @ManagedAttribute(mandatory = true, defaultValue = "${qpid.work_dir}${file.separator}${this:name}${file.separator}config") String getStorePath(); } diff --git a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb/add.html b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb/add.html index f9e9d0a82f..9ce23084c5 100644 --- a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb/add.html +++ b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb/add.html @@ -20,15 +20,13 @@ -->
-
Store path*:
+
Store path:
diff --git a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/existinggroup/add.html b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/existinggroup/add.html index b08c734e35..820a94e754 100644 --- a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/existinggroup/add.html +++ b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/existinggroup/add.html @@ -81,15 +81,13 @@
-
Store path*:
+
Store path:
diff --git a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/newgroup/add.html b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/newgroup/add.html index 3d06d15d5c..1d3b2a1906 100644 --- a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/newgroup/add.html +++ b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/newgroup/add.html @@ -45,15 +45,13 @@
-
Store path*:
+
Store path:
diff --git a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/edit.html b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/edit.html index c18ca34fdb..189eb6f7b6 100644 --- a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/edit.html +++ b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/edit.html @@ -45,15 +45,13 @@
-
Configuration store path*:
+
Configuration store path:
diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacadeTest.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacadeTest.java index 44fc19e14f..5ed533f1e5 100644 --- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacadeTest.java +++ b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacadeTest.java @@ -656,7 +656,8 @@ public class ReplicatedEnvironmentFacadeTest extends QpidTestCase permittedNodes.add("localhost:" + getNextAvailable(TEST_NODE_PORT + 1)); firstNode.setPermittedNodes(permittedNodes); - NodeState nodeState = firstNode.getRemoteNodeState(new ReplicatedEnvironmentFacade.ReplicationNodeImpl(TEST_NODE_NAME, TEST_NODE_HOST_PORT)); + ReplicatedEnvironmentFacade.ReplicationNodeImpl replicationNode = new ReplicatedEnvironmentFacade.ReplicationNodeImpl(TEST_NODE_NAME, TEST_NODE_HOST_PORT); + NodeState nodeState = ReplicatedEnvironmentFacade.getRemoteNodeState(TEST_GROUP_NAME, replicationNode); ObjectMapper objectMapper = new ObjectMapper(); @@ -708,10 +709,52 @@ public class ReplicatedEnvironmentFacadeTest extends QpidTestCase firstNode.setPermittedNodes(permittedNodes); String nodeName = TEST_NODE_NAME + "_1"; + createIntruder(nodeName, node1NodeHostPort); + assertTrue("Intruder node was not detected", intruderLatch.await(10, TimeUnit.SECONDS)); + } + + public void testIntruderNodeDetectionOnMasterAndReplicaNodes() throws Exception + { + final CountDownLatch intruderLatch = new CountDownLatch(2); + ReplicationGroupListener listener = new NoopReplicationGroupListener() + { + @Override + public void onIntruderNode(ReplicationNode node) + { + intruderLatch.countDown(); + } + }; + + ReplicatedEnvironmentFacade firstNode = createMaster(listener); + int replica1Port = getNextAvailable(TEST_NODE_PORT + 1); + String node2NodeHostPort = "localhost:" + replica1Port; + String nodeName2 = TEST_NODE_NAME + "_1"; + ReplicatedEnvironmentFacade secondNode = createReplica(nodeName2, node2NodeHostPort, listener); + + Set permittedNodes = new HashSet(); + permittedNodes.add("localhost:" + TEST_NODE_PORT); + permittedNodes.add(nodeName2); + firstNode.setPermittedNodes(permittedNodes); + + int counter = 0; + while(secondNode.getPermittedNodes().isEmpty() && counter < 100) + { + counter++; + Thread.sleep(50); + } + assertEquals("Permitted nodes are not set on a replica", permittedNodes, secondNode.getPermittedNodes()); + + int intruderPort = getNextAvailable(replica1Port+ 1); + createIntruder("intruder", "localhost:" + intruderPort); + assertTrue("Intruder node was not detected", intruderLatch.await(10, TimeUnit.SECONDS)); + } + + private void createIntruder(String nodeName, String node1NodeHostPort) + { File environmentPathFile = new File(_storePath, nodeName); environmentPathFile.mkdirs(); - ReplicationConfig replicationConfig = new ReplicationConfig(TEST_GROUP_NAME, TEST_NODE_NAME + "_1", node1NodeHostPort); + ReplicationConfig replicationConfig = new ReplicationConfig(TEST_GROUP_NAME, nodeName, node1NodeHostPort); replicationConfig.setHelperHosts(TEST_NODE_HOST_PORT); EnvironmentConfig envConfig = new EnvironmentConfig(); @@ -730,7 +773,6 @@ public class ReplicatedEnvironmentFacadeTest extends QpidTestCase intruder.close(); } } - assertTrue("Intruder node was not detected", intruderLatch.await(10, TimeUnit.SECONDS)); } private ReplicatedEnvironmentFacade createMaster() throws Exception diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeOperationalLoggingTest.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeOperationalLoggingTest.java index 45527313e6..ef1021160c 100644 --- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeOperationalLoggingTest.java +++ b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeOperationalLoggingTest.java @@ -24,7 +24,6 @@ import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.*; import java.util.Collections; -import java.util.List; import java.util.Map; import org.apache.qpid.server.logging.EventLogger; @@ -34,7 +33,6 @@ import org.apache.qpid.server.logging.messages.HighAvailabilityMessages; import org.apache.qpid.server.model.SystemConfig; import org.apache.qpid.test.utils.QpidTestCase; import org.hamcrest.Description; -import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; /** @@ -360,22 +358,51 @@ public class BDBHAVirtualHostNodeOperationalLoggingTest extends QpidTestCase reset(_eventLogger); node2 = (BDBHAVirtualHostNodeImpl)_helper.recoverHaVHN(node2.getId(), node2Attributes); - _helper.assertNodeRole(node2, "REPLICA"); - + _helper.assertNodeRole(node2, "REPLICA", "MASTER"); waitForNodeDetachedField(remoteNode, false); - ArgumentCaptor subjectArgument = ArgumentCaptor.forClass(LogSubject.class); - ArgumentCaptor messageArgument = ArgumentCaptor.forClass(LogMessage.class); - verify(_eventLogger, times(2)).message(subjectArgument.capture(), messageArgument.capture()); - - assertEquals("Unexpected subject", node1.getVirtualHostNodeLogSubject(), subjectArgument.getValue()); + final String expectedMessage = HighAvailabilityMessages.ATTACHED(node2.getName(), groupName, "REPLICA").toString(); + final String expectedMessage2 = HighAvailabilityMessages.ATTACHED(node2.getName(), groupName, "UNKNOWN").toString(); + final String expectedMessage3 = HighAvailabilityMessages.ATTACHED(node2.getName(), groupName, "MASTER").toString(); + ArgumentMatcher matcher = new ArgumentMatcher() + { + private String _messageErrorDescription = null; + private String _hierarchyErrorDescription = null; - String expectedMessage = HighAvailabilityMessages.ATTACHED(node2.getName(), groupName, "REPLICA").toString(); - String expectedMessage2 = HighAvailabilityMessages.ATTACHED(node2.getName(), groupName, "UNKNOWN").toString(); + @Override + public boolean matches(Object argument) + { + LogMessage logMessage = (LogMessage)argument; + String actualMessage = logMessage.toString(); + boolean expectedMessageMatches = expectedMessage.equals(actualMessage) + || expectedMessage2.equals(actualMessage) || expectedMessage3.equals(actualMessage); + if (!expectedMessageMatches) + { + _messageErrorDescription = "Actual message does not match any expected: " + actualMessage; + } + boolean expectedHierarchyMatches = HighAvailabilityMessages.ATTACHED_LOG_HIERARCHY.equals(logMessage.getLogHierarchy()); + if (!expectedHierarchyMatches) + { + _hierarchyErrorDescription = "Actual hierarchy does not match expected: " + logMessage.getLogHierarchy(); + } + return expectedMessageMatches && expectedHierarchyMatches; + } - List capturedValues = messageArgument.getAllValues(); - String m = capturedValues.get(0).toString(); - assertTrue("Unexpected attached message :" + m, m.equals(expectedMessage) || m.equals(expectedMessage2)); + @Override + public void describeTo(Description description) + { + if (_messageErrorDescription != null) + { + description.appendText(_messageErrorDescription); + } + if (_hierarchyErrorDescription != null) + { + description.appendText(_hierarchyErrorDescription); + } + } + }; + verify(_eventLogger).message(argThat(new LogSubjectMatcher(node1.getVirtualHostNodeLogSubject())), + argThat(matcher)); } private void waitForNodeDetachedField(BDBHARemoteReplicationNodeImpl remoteNode, boolean expectedDetached) throws InterruptedException { diff --git a/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBBackupTest.java b/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBBackupTest.java deleted file mode 100644 index fab889a49f..0000000000 --- a/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBBackupTest.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.store.berkeleydb; - -import java.io.File; -import java.io.IOException; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -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 org.apache.log4j.Logger; -import org.apache.qpid.server.model.VirtualHostNode; -import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBVirtualHostNode; -import org.apache.qpid.test.utils.Piper; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.util.FileUtils; -import org.apache.qpid.util.Strings; -import org.apache.qpid.util.SystemUtils; - -/** - * Tests the BDB backup script can successfully perform a backup and that - * backup can be restored and used by the Broker. - */ -public class BDBBackupTest extends QpidBrokerTestCase -{ - protected static final Logger LOGGER = Logger.getLogger(BDBBackupTest.class); - - private static final String BACKUP_SCRIPT = "/bin/backup.sh"; - private static final String BACKUP_COMPLETE_MESSAGE = "Hot Backup Completed"; - - private static final String TEST_VHOST = "test"; - private static final String SYSTEM_TMP_DIR = System.getProperty("java.io.tmpdir"); - - private File _backupToDir; - private File _backupFromDir; - - @Override - protected void setUp() throws Exception - { - super.setUp(); - _backupToDir = new File(SYSTEM_TMP_DIR + File.separator + getTestName()); - _backupToDir.mkdirs(); - - Map virtualHostNodeAttributes = getBrokerConfiguration().getObjectAttributes(VirtualHostNode.class, TEST_VHOST); - _backupFromDir = new File(Strings.expand((String) virtualHostNodeAttributes.get(BDBVirtualHostNode.STORE_PATH))); - boolean fromDirExistsAndIsDir = _backupFromDir.isDirectory(); - assertTrue("backupFromDir " + _backupFromDir + " should already exist", fromDirExistsAndIsDir); - } - - @Override - protected void tearDown() throws Exception - { - try - { - super.tearDown(); - } - finally - { - FileUtils.delete(_backupToDir, true); - } - } - - public void testBackupAndRestoreMaintainsMessages() throws Exception - { - sendNumberedMessages(0, 10); - invokeBdbBackup(_backupFromDir, _backupToDir); - sendNumberedMessages(10, 20); - confirmBrokerHasMessages(0, 20); - stopBroker(); - - deleteStore(_backupFromDir); - replaceStoreWithBackup(_backupToDir, _backupFromDir); - - startBroker(); - confirmBrokerHasMessages(0, 10); - } - - private void sendNumberedMessages(final int startIndex, final int endIndex) throws JMSException, Exception - { - Connection con = getConnection(); - Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - Destination destination = session.createQueue(getTestQueueName()); - // Create queue by consumer side-effect - session.createConsumer(destination).close(); - - final int numOfMessages = endIndex - startIndex; - final int batchSize = 0; - sendMessage(session, destination, numOfMessages, startIndex, batchSize); - con.close(); - } - - private void confirmBrokerHasMessages(final int startIndex, final int endIndex) throws Exception - { - Connection con = getConnection(); - Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - con.start(); - Destination destination = session.createQueue(getTestQueueName()); - MessageConsumer consumer = session.createConsumer(destination); - for (int i = startIndex; i < endIndex; i++) - { - Message msg = consumer.receive(RECEIVE_TIMEOUT); - assertNotNull("Message " + i + " not received", msg); - assertEquals("Did not receive the expected message", i, msg.getIntProperty(INDEX)); - } - - Message msg = consumer.receive(100); - if(msg != null) - { - fail("No more messages should be received, but received additional message with index: " + msg.getIntProperty(INDEX)); - } - con.close(); - } - - private void invokeBdbBackup(final File backupFromDir, final File backupToDir) throws Exception - { - if (SystemUtils.isWindows()) - { - BDBBackup.main(new String[]{"-todir", backupToDir.getAbsolutePath(), "-fromdir", backupFromDir.getAbsolutePath()}); - } - else - { - runBdbBackupScript(backupFromDir, backupToDir); - } - } - - private void runBdbBackupScript(final File backupFromDir, final File backupToDir) throws IOException, - InterruptedException - { - Process backupProcess = null; - try - { - String qpidHome = System.getProperty(QPID_HOME); - ProcessBuilder pb = new ProcessBuilder(qpidHome + BACKUP_SCRIPT, "-todir", backupToDir.getAbsolutePath(), "-fromdir", backupFromDir.getAbsolutePath()); - pb.redirectErrorStream(true); - Map env = pb.environment(); - env.put(QPID_HOME, qpidHome); - - LOGGER.debug("Backup command is " + pb.command()); - backupProcess = pb.start(); - Piper piper = new Piper(backupProcess.getInputStream(), _testcaseOutputStream, null, BACKUP_COMPLETE_MESSAGE); - piper.start(); - piper.await(2, TimeUnit.SECONDS); - backupProcess.waitFor(); - piper.join(); - - LOGGER.debug("Backup command completed " + backupProcess.exitValue()); - assertEquals("Unexpected exit value from backup script", 0, backupProcess.exitValue()); - } - finally - { - if (backupProcess != null) - { - backupProcess.getErrorStream().close(); - backupProcess.getInputStream().close(); - backupProcess.getOutputStream().close(); - } - } - } - - private void replaceStoreWithBackup(File source, File dst) throws Exception - { - LOGGER.debug("Copying store " + source + " to " + dst); - FileUtils.copyRecursive(source, dst); - } - - private void deleteStore(File storeDir) - { - LOGGER.debug("Deleting store " + storeDir); - FileUtils.delete(storeDir, true); - } - -} diff --git a/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeRestTest.java b/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeRestTest.java deleted file mode 100644 index 1e7c79f7da..0000000000 --- a/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeRestTest.java +++ /dev/null @@ -1,443 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.store.berkeleydb; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.servlet.http.HttpServletResponse; - -import com.sleepycat.je.Durability; -import com.sleepycat.je.EnvironmentConfig; -import com.sleepycat.je.rep.ReplicatedEnvironment; -import com.sleepycat.je.rep.ReplicationConfig; -import org.apache.qpid.server.model.RemoteReplicationNode; -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.model.VirtualHost; -import org.apache.qpid.server.model.VirtualHostNode; -import org.apache.qpid.server.store.berkeleydb.replication.ReplicatedEnvironmentFacade; -import org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHost; -import org.apache.qpid.server.virtualhostnode.AbstractVirtualHostNode; -import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHARemoteReplicationNode; -import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHAVirtualHostNode; -import org.apache.qpid.systest.rest.Asserts; -import org.apache.qpid.systest.rest.QpidRestTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.util.FileUtils; - -public class BDBHAVirtualHostNodeRestTest extends QpidRestTestCase -{ - private static final String NODE1 = "node1"; - private static final String NODE2 = "node2"; - private static final String NODE3 = "node3"; - - private int _node1HaPort; - private int _node2HaPort; - private int _node3HaPort; - - private String _hostName; - private File _storeBaseDir; - private String _baseNodeRestUrl; - - @Override - public void setUp() throws Exception - { - setTestSystemProperty(ReplicatedEnvironmentFacade.REMOTE_NODE_MONITOR_INTERVAL_PROPERTY_NAME, "1000"); - - super.setUp(); - _hostName = getTestName(); - _baseNodeRestUrl = "virtualhostnode/"; - - _storeBaseDir = new File(TMP_FOLDER, "store-" + _hostName + "-" + System.currentTimeMillis()); - - _node1HaPort = findFreePort(); - _node2HaPort = getNextAvailable(_node1HaPort + 1); - _node3HaPort = getNextAvailable(_node2HaPort + 1); - - - } - - @Override - public void tearDown() throws Exception - { - try - { - super.tearDown(); - } - finally - { - if (_storeBaseDir != null) - { - FileUtils.delete(_storeBaseDir, true); - } - } - } - - @Override - protected void customizeConfiguration() throws IOException - { - super.customizeConfiguration(); - TestBrokerConfiguration config = getBrokerConfiguration(); - config.removeObjectConfiguration(VirtualHostNode.class, TEST2_VIRTUALHOST); - config.removeObjectConfiguration(VirtualHostNode.class, TEST3_VIRTUALHOST); - } - - public void testCreate3NodeGroup() throws Exception - { - createHANode(NODE1, _node1HaPort, _node1HaPort); - assertNode(NODE1, _node1HaPort, _node1HaPort, NODE1); - createHANode(NODE2, _node2HaPort, _node1HaPort); - assertNode(NODE2, _node2HaPort, _node1HaPort, NODE1); - createHANode(NODE3, _node3HaPort, _node1HaPort); - assertNode(NODE3, _node3HaPort, _node1HaPort, NODE1); - assertRemoteNodes(NODE1, NODE2, NODE3); - } - - public void testMutateStateOfOneNode() throws Exception - { - createHANode(NODE1, _node1HaPort, _node1HaPort); - createHANode(NODE2, _node2HaPort, _node1HaPort); - createHANode(NODE3, _node3HaPort, _node1HaPort); - - String node1Url = _baseNodeRestUrl + NODE1; - String node2Url = _baseNodeRestUrl + NODE2; - String node3Url = _baseNodeRestUrl + NODE3; - - assertActualAndDesiredStates(node1Url, "ACTIVE", "ACTIVE"); - assertActualAndDesiredStates(node2Url, "ACTIVE", "ACTIVE"); - assertActualAndDesiredStates(node3Url, "ACTIVE", "ACTIVE"); - - mutateDesiredState(node1Url, "STOPPED"); - - assertActualAndDesiredStates(node1Url, "STOPPED", "STOPPED"); - assertActualAndDesiredStates(node2Url, "ACTIVE", "ACTIVE"); - assertActualAndDesiredStates(node3Url, "ACTIVE", "ACTIVE"); - - List> remoteNodes = getRestTestHelper().getJsonAsList("replicationnode/" + NODE2); - assertEquals("Unexpected number of remote nodes on " + NODE2, 2, remoteNodes.size()); - - Map remoteNode1 = findRemoteNodeByName(remoteNodes, NODE1); - - assertEquals("Node 1 observed from node 2 is in the wrong state", - "UNAVAILABLE", remoteNode1.get(BDBHARemoteReplicationNode.STATE)); - assertEquals("Node 1 observed from node 2 has the wrong role", - "UNKNOWN", remoteNode1.get(BDBHARemoteReplicationNode.ROLE)); - - } - - public void testNewMasterElectedWhenVirtualHostIsStopped() throws Exception - { - createHANode(NODE1, _node1HaPort, _node1HaPort); - createHANode(NODE2, _node2HaPort, _node1HaPort); - createHANode(NODE3, _node3HaPort, _node1HaPort); - - String node1Url = _baseNodeRestUrl + NODE1; - String node2Url = _baseNodeRestUrl + NODE2; - String node3Url = _baseNodeRestUrl + NODE3; - - assertActualAndDesiredStates(node1Url, "ACTIVE", "ACTIVE"); - assertActualAndDesiredStates(node2Url, "ACTIVE", "ACTIVE"); - assertActualAndDesiredStates(node3Url, "ACTIVE", "ACTIVE"); - - // Put virtualhost in STOPPED state - String virtualHostRestUrl = "virtualhost/" + NODE1 + "/" + _hostName; - assertActualAndDesiredStates(virtualHostRestUrl, "ACTIVE", "ACTIVE"); - mutateDesiredState(virtualHostRestUrl, "STOPPED"); - assertActualAndDesiredStates(virtualHostRestUrl, "STOPPED", "STOPPED"); - - // Now stop node 1 to cause an election between nodes 2 & 3 - mutateDesiredState(node1Url, "STOPPED"); - assertActualAndDesiredStates(node1Url, "STOPPED", "STOPPED"); - - Map newMasterData = awaitNewMaster(node2Url, node3Url); - - //Check the virtual host of the new master is in the stopped state - String newMasterVirtualHostRestUrl = "virtualhost/" + newMasterData.get(BDBHAVirtualHostNode.NAME) + "/" + _hostName; - assertActualAndDesiredStates(newMasterVirtualHostRestUrl, "STOPPED", "STOPPED"); - } - - public void testDeleteReplicaNode() throws Exception - { - createHANode(NODE1, _node1HaPort, _node1HaPort); - createHANode(NODE2, _node2HaPort, _node1HaPort); - createHANode(NODE3, _node3HaPort, _node1HaPort); - - assertRemoteNodes(NODE1, NODE2, NODE3); - - List> data = getRestTestHelper().getJsonAsList("replicationnode/" + NODE1); - assertEquals("Unexpected number of remote nodes on " + NODE1, 2, data.size()); - - int responseCode = getRestTestHelper().submitRequest(_baseNodeRestUrl + NODE2, "DELETE"); - assertEquals("Unexpected response code on deletion of virtual host node " + NODE2, 200, responseCode); - - int counter = 0; - while (data.size() != 1 && counter<50) - { - data = getRestTestHelper().getJsonAsList("replicationnode/" + NODE1); - if (data.size() != 1) - { - Thread.sleep(100l); - } - counter++; - } - assertEquals("Unexpected number of remote nodes on " + NODE1, 1, data.size()); - } - - public void testDeleteMasterNode() throws Exception - { - createHANode(NODE1, _node1HaPort, _node1HaPort); - createHANode(NODE2, _node2HaPort, _node1HaPort); - createHANode(NODE3, _node3HaPort, _node1HaPort); - - assertNode(NODE1, _node1HaPort, _node1HaPort, NODE1); - assertRemoteNodes(NODE1, NODE2, NODE3); - - // change priority to make Node2 a master - int responseCode = getRestTestHelper().submitRequest(_baseNodeRestUrl + NODE2, "PUT", Collections.singletonMap(BDBHAVirtualHostNode.PRIORITY, 100)); - assertEquals("Unexpected response code on priority update of virtual host node " + NODE2, 200, responseCode); - - List> data = getRestTestHelper().getJsonAsList("replicationnode/" + NODE2); - assertEquals("Unexpected number of remote nodes on " + NODE2, 2, data.size()); - - // delete master - responseCode = getRestTestHelper().submitRequest(_baseNodeRestUrl + NODE1, "DELETE"); - assertEquals("Unexpected response code on deletion of virtual host node " + NODE1, 200, responseCode); - - // wait for new master - waitForAttributeChanged(_baseNodeRestUrl + NODE2 + "?depth=0", BDBHAVirtualHostNode.ROLE, "MASTER"); - - // delete remote node - responseCode = getRestTestHelper().submitRequest("replicationnode/" + NODE2 + "/" + NODE1, "DELETE"); - assertEquals("Unexpected response code on deletion of remote node " + NODE1, 200, responseCode); - - int counter = 0; - while (data.size() != 1 && counter<50) - { - data = getRestTestHelper().getJsonAsList("replicationnode/" + NODE2); - if (data.size() != 1) - { - Thread.sleep(100l); - } - counter++; - } - assertEquals("Unexpected number of remote nodes on " + NODE2, 1, data.size()); - } - - public void testIntruderProtection() throws Exception - { - createHANode(NODE1, _node1HaPort, _node1HaPort); - assertNode(NODE1, _node1HaPort, _node1HaPort, NODE1); - - String virtualHostRestUrl = "virtualhost/" + NODE1 + "/" + _hostName; - - Map hostData = new HashMap(); - hostData.put(BDBHAVirtualHost.PERMITTED_NODES, Arrays.asList( "localhost:" + _node1HaPort, "localhost:" + _node3HaPort)); - getRestTestHelper().submitRequest(virtualHostRestUrl, "PUT", hostData, 200); - - // add permitted node - Map node3Data = createNodeAttributeMap(NODE3, _node3HaPort, _node1HaPort); - node3Data.put(BDBHAVirtualHostNode.HELPER_NODE_NAME, NODE1); - getRestTestHelper().submitRequest(_baseNodeRestUrl + NODE3, "PUT", node3Data, 201); - assertNode(NODE3, _node3HaPort, _node1HaPort, NODE1); - assertRemoteNodes(NODE1, NODE3); - - // try to add not permitted node - Map nodeData = createNodeAttributeMap(NODE2, _node2HaPort, _node1HaPort); - nodeData.put(BDBHAVirtualHostNode.HELPER_NODE_NAME, NODE1); - getRestTestHelper().submitRequest(_baseNodeRestUrl + NODE2, "PUT", nodeData, 409); - - assertRemoteNodes(NODE1, NODE3); - - //connect intruder node - String nodeName = NODE2; - String nodeHostPort = (String)nodeData.get(BDBHAVirtualHostNode.ADDRESS); - File environmentPathFile = new File((String)nodeData.get(BDBHAVirtualHostNode.STORE_PATH), nodeName); - environmentPathFile.mkdirs(); - ReplicationConfig replicationConfig = new ReplicationConfig((String)nodeData.get(BDBHAVirtualHostNode.GROUP_NAME), nodeName, nodeHostPort); - replicationConfig.setHelperHosts((String)nodeData.get(BDBHAVirtualHostNode.HELPER_ADDRESS)); - EnvironmentConfig envConfig = new EnvironmentConfig(); - envConfig.setAllowCreate(true); - envConfig.setTransactional(true); - envConfig.setDurability(Durability.parse((String)nodeData.get(BDBHAVirtualHostNode.DURABILITY))); - - ReplicatedEnvironment intruder = null; - try - { - intruder = new ReplicatedEnvironment(environmentPathFile, replicationConfig, envConfig); - } - finally - { - intruder.close(); - } - waitForAttributeChanged(_baseNodeRestUrl + NODE1, VirtualHostNode.STATE, State.ERRORED.name()); - } - - private void createHANode(String nodeName, int nodePort, int helperPort) throws Exception - { - Map nodeData = createNodeAttributeMap(nodeName, nodePort, helperPort); - - int responseCode = getRestTestHelper().submitRequest(_baseNodeRestUrl + nodeName, "PUT", nodeData); - assertEquals("Unexpected response code for virtual host node " + nodeName + " creation request", 201, responseCode); - } - - private Map createNodeAttributeMap(String nodeName, int nodePort, int helperPort) throws Exception - { - Map nodeData = new HashMap(); - nodeData.put(BDBHAVirtualHostNode.NAME, nodeName); - nodeData.put(BDBHAVirtualHostNode.TYPE, "BDB_HA"); - nodeData.put(BDBHAVirtualHostNode.STORE_PATH, _storeBaseDir.getPath() + File.separator + nodeName); - nodeData.put(BDBHAVirtualHostNode.GROUP_NAME, _hostName); - nodeData.put(BDBHAVirtualHostNode.ADDRESS, "localhost:" + nodePort); - nodeData.put(BDBHAVirtualHostNode.HELPER_ADDRESS, "localhost:" + helperPort); - nodeData.put(BDBHAVirtualHostNode.HELPER_NODE_NAME, NODE1); - Map context = new HashMap<>(); - nodeData.put(BDBHAVirtualHostNode.CONTEXT, context); - String bluePrint = HATestClusterCreator.getBlueprint("localhost", _node1HaPort, _node2HaPort, _node3HaPort); - context.put(AbstractVirtualHostNode.VIRTUALHOST_BLUEPRINT_CONTEXT_VAR, bluePrint); - return nodeData; - } - - private void assertNode(String nodeName, int nodePort, int nodeHelperPort, String masterNode) throws Exception - { - boolean isMaster = nodeName.equals(masterNode); - String expectedRole = isMaster? "MASTER" : "REPLICA"; - waitForAttributeChanged(_baseNodeRestUrl + nodeName + "?depth=0", BDBHAVirtualHostNode.ROLE, expectedRole); - - Map nodeData = getRestTestHelper().getJsonAsSingletonList(_baseNodeRestUrl + nodeName + "?depth=0"); - assertEquals("Unexpected name", nodeName, nodeData.get(BDBHAVirtualHostNode.NAME)); - assertEquals("Unexpected type", "BDB_HA", nodeData.get(BDBHAVirtualHostNode.TYPE)); - assertEquals("Unexpected path", new File(_storeBaseDir, nodeName).getPath(), nodeData.get(BDBHAVirtualHostNode.STORE_PATH)); - assertEquals("Unexpected address", "localhost:" + nodePort, nodeData.get(BDBHAVirtualHostNode.ADDRESS)); - assertEquals("Unexpected helper address", "localhost:" + nodeHelperPort, nodeData.get(BDBHAVirtualHostNode.HELPER_ADDRESS)); - assertEquals("Unexpected group name", _hostName, nodeData.get(BDBHAVirtualHostNode.GROUP_NAME)); - assertEquals("Unexpected role", expectedRole, nodeData.get(BDBHAVirtualHostNode.ROLE)); - - Integer lastKnownTransactionId = (Integer) nodeData.get(BDBHAVirtualHostNode.LAST_KNOWN_REPLICATION_TRANSACTION_ID); - assertNotNull("Unexpected lastKnownReplicationId", lastKnownTransactionId); - assertTrue("Unexpected lastKnownReplicationId " + lastKnownTransactionId, lastKnownTransactionId > 0); - - Long joinTime = (Long) nodeData.get(BDBHAVirtualHostNode.JOIN_TIME); - assertNotNull("Unexpected joinTime", joinTime); - assertTrue("Unexpected joinTime " + joinTime, joinTime > 0); - - if (isMaster) - { - waitForAttributeChanged("virtualhost/" + masterNode + "/" + _hostName + "?depth=0", VirtualHost.STATE, State.ACTIVE.name()); - } - - } - - private void assertRemoteNodes(String masterNode, String... replicaNodes) throws Exception - { - List clusterNodes = new ArrayList(Arrays.asList(replicaNodes)); - clusterNodes.add(masterNode); - - for (String clusterNodeName : clusterNodes) - { - List remotes = new ArrayList(clusterNodes); - remotes.remove(clusterNodeName); - for (String remote : remotes) - { - String remoteUrl = "replicationnode/" + clusterNodeName + "/" + remote; - Map nodeData = waitForAttributeChanged(remoteUrl, BDBHARemoteReplicationNode.ROLE, remote.equals(masterNode) ? "MASTER" : "REPLICA"); - assertRemoteNodeData(remote, nodeData); - } - } - } - - private void assertRemoteNodeData(String name, Map nodeData) - { - assertEquals("Remote node " + name + " has unexpected name", name, nodeData.get(BDBHAVirtualHostNode.NAME)); - - Integer lastKnownTransactionId = (Integer) nodeData.get(BDBHAVirtualHostNode.LAST_KNOWN_REPLICATION_TRANSACTION_ID); - assertNotNull("Node " + name + " has unexpected lastKnownReplicationId", lastKnownTransactionId); - assertTrue("Node " + name + " has unexpected lastKnownReplicationId " + lastKnownTransactionId, lastKnownTransactionId > 0); - - Long joinTime = (Long) nodeData.get(BDBHAVirtualHostNode.JOIN_TIME); - assertNotNull("Node " + name + " has unexpected joinTime", joinTime); - assertTrue("Node " + name + " has unexpected joinTime " + joinTime, joinTime > 0); - } - - private void assertActualAndDesiredStates(final String restUrl, - final String expectedDesiredState, - final String expectedActualState) throws IOException - { - Map objectData = getRestTestHelper().getJsonAsSingletonList(restUrl); - Asserts.assertActualAndDesiredState(expectedDesiredState, expectedActualState, objectData); - } - - private void mutateDesiredState(final String restUrl, final String newState) throws IOException - { - Map newAttributes = new HashMap(); - newAttributes.put(VirtualHostNode.DESIRED_STATE, newState); - - getRestTestHelper().submitRequest(restUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); - } - - private Map findRemoteNodeByName(final List> remoteNodes, final String nodeName) - { - Map foundNode = null; - for (Map remoteNode : remoteNodes) - { - if (nodeName.equals(remoteNode.get(RemoteReplicationNode.NAME))) - { - foundNode = remoteNode; - break; - } - } - assertNotNull("Could not find node with name " + nodeName + " amongst remote nodes."); - return foundNode; - } - - private Map awaitNewMaster(final String... nodeUrls) - throws IOException, InterruptedException - { - Map newMasterData = null; - int counter = 0; - while (newMasterData == null && counter < 50) - { - for(String nodeUrl: nodeUrls) - { - Map nodeData = getRestTestHelper().getJsonAsSingletonList(nodeUrl); - if ("MASTER".equals(nodeData.get(BDBHAVirtualHostNode.ROLE))) - { - newMasterData = nodeData; - break; - } - } - if (newMasterData == null) - { - Thread.sleep(100l); - counter++; - } - } - assertNotNull("Could not find new master", newMasterData); - return newMasterData; - } - - -} diff --git a/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostRestTest.java b/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostRestTest.java deleted file mode 100644 index 334544e334..0000000000 --- a/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostRestTest.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.server.store.berkeleydb; - -import static org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHost.LOCAL_TRANSACTION_SYNCHRONIZATION_POLICY; -import static org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHost.REMOTE_TRANSACTION_SYNCHRONIZATION_POLICY; - -import java.io.File; -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import javax.servlet.http.HttpServletResponse; - -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.model.VirtualHost; -import org.apache.qpid.server.model.VirtualHostNode; -import org.apache.qpid.server.store.berkeleydb.replication.ReplicatedEnvironmentFacade; -import org.apache.qpid.server.virtualhostnode.AbstractVirtualHostNode; -import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHAVirtualHostNode; -import org.apache.qpid.systest.rest.Asserts; -import org.apache.qpid.systest.rest.QpidRestTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.util.FileUtils; - -public class BDBHAVirtualHostRestTest extends QpidRestTestCase -{ - private String _hostName; - private File _storeBaseDir; - private int _nodeHaPort; - private Object _nodeName; - private String _virtualhostUrl; - private String _bluePrint; - - @Override - public void setUp() throws Exception - { - setTestSystemProperty(ReplicatedEnvironmentFacade.REMOTE_NODE_MONITOR_INTERVAL_PROPERTY_NAME, "1000"); - _hostName = "ha"; - _nodeName = "node1"; - _storeBaseDir = new File(TMP_FOLDER, "store-" + _hostName + "-" + System.currentTimeMillis()); - _nodeHaPort = getNextAvailable(getRestTestHelper().getHttpPort() + 1); - _virtualhostUrl = "virtualhost/" + _nodeName + "/" + _hostName; - _bluePrint = HATestClusterCreator.getBlueprint("localhost", _nodeHaPort); - - super.setUp(); - } - - @Override - public void tearDown() throws Exception - { - try - { - super.tearDown(); - } - finally - { - if (_storeBaseDir != null) - { - FileUtils.delete(_storeBaseDir, true); - } - } - } - - @Override - protected void customizeConfiguration() throws IOException - { - super.customizeConfiguration(); - TestBrokerConfiguration config = getBrokerConfiguration(); - config.removeObjectConfiguration(VirtualHostNode.class, TEST2_VIRTUALHOST); - config.removeObjectConfiguration(VirtualHostNode.class, TEST3_VIRTUALHOST); - - Map nodeAttributes = new HashMap(); - nodeAttributes.put(BDBHAVirtualHostNode.NAME, _nodeName); - nodeAttributes.put(BDBHAVirtualHostNode.TYPE, "BDB_HA"); - nodeAttributes.put(BDBHAVirtualHostNode.STORE_PATH, _storeBaseDir.getPath() + File.separator + _nodeName); - nodeAttributes.put(BDBHAVirtualHostNode.GROUP_NAME, _hostName); - nodeAttributes.put(BDBHAVirtualHostNode.ADDRESS, "localhost:" + _nodeHaPort); - nodeAttributes.put(BDBHAVirtualHostNode.HELPER_ADDRESS, "localhost:" + _nodeHaPort); - nodeAttributes.put(BDBHAVirtualHostNode.HELPER_NODE_NAME, _nodeName); - Map context = new HashMap(); - context.put(AbstractVirtualHostNode.VIRTUALHOST_BLUEPRINT_CONTEXT_VAR, _bluePrint); - - nodeAttributes.put(BDBHAVirtualHostNode.CONTEXT, context); - config.addObjectConfiguration(VirtualHostNode.class, nodeAttributes); - } - - public void testSetLocalTransactionSynchronizationPolicy() throws Exception - { - Map hostAttributes = waitForAttributeChanged(_virtualhostUrl, VirtualHost.STATE, State.ACTIVE.name()); - assertEquals("Unexpected synchronization policy before change", "SYNC", hostAttributes.get(LOCAL_TRANSACTION_SYNCHRONIZATION_POLICY)); - - Map newPolicy = Collections.singletonMap(LOCAL_TRANSACTION_SYNCHRONIZATION_POLICY, "NO_SYNC"); - getRestTestHelper().submitRequest(_virtualhostUrl, "PUT", newPolicy, HttpServletResponse.SC_OK); - - hostAttributes = getRestTestHelper().getJsonAsSingletonList(_virtualhostUrl); - assertEquals("Unexpected synchronization policy after change", "NO_SYNC", hostAttributes.get(LOCAL_TRANSACTION_SYNCHRONIZATION_POLICY)); - } - - public void testSetRemoteTransactionSynchronizationPolicy() throws Exception - { - Map hostAttributes = waitForAttributeChanged(_virtualhostUrl, VirtualHost.STATE, State.ACTIVE.name()); - assertEquals("Unexpected synchronization policy before change", "NO_SYNC", hostAttributes.get(REMOTE_TRANSACTION_SYNCHRONIZATION_POLICY)); - - Map newPolicy = Collections.singletonMap(REMOTE_TRANSACTION_SYNCHRONIZATION_POLICY, "SYNC"); - getRestTestHelper().submitRequest(_virtualhostUrl, "PUT", newPolicy, HttpServletResponse.SC_OK); - - hostAttributes = getRestTestHelper().getJsonAsSingletonList(_virtualhostUrl); - assertEquals("Unexpected synchronization policy after change", "SYNC", hostAttributes.get(REMOTE_TRANSACTION_SYNCHRONIZATION_POLICY)); - } - - public void testMutateState() throws Exception - { - waitForAttributeChanged(_virtualhostUrl, VirtualHost.STATE, "ACTIVE"); - assertActualAndDesireStates(_virtualhostUrl, "ACTIVE", "ACTIVE"); - - Map newAttributes = Collections.singletonMap(VirtualHost.DESIRED_STATE, "STOPPED"); - getRestTestHelper().submitRequest(_virtualhostUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); - - waitForAttributeChanged(_virtualhostUrl, VirtualHost.STATE, "STOPPED"); - assertActualAndDesireStates(_virtualhostUrl, "STOPPED", "STOPPED"); - - newAttributes = Collections.singletonMap(VirtualHost.DESIRED_STATE, "ACTIVE"); - getRestTestHelper().submitRequest(_virtualhostUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); - - waitForAttributeChanged(_virtualhostUrl, VirtualHost.STATE, "ACTIVE"); - assertActualAndDesireStates(_virtualhostUrl, "ACTIVE", "ACTIVE"); - } - - private void assertActualAndDesireStates(final String restUrl, - final String expectedDesiredState, - final String expectedActualState) throws IOException - { - Map virtualhost = getRestTestHelper().getJsonAsSingletonList(restUrl); - Asserts.assertActualAndDesiredState(expectedDesiredState, expectedActualState, virtualhost); - } - -} diff --git a/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java b/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java deleted file mode 100644 index 491856d953..0000000000 --- a/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java +++ /dev/null @@ -1,548 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.store.berkeleydb; - -import java.io.File; -import java.io.InputStream; -import java.util.Map; - -import javax.jms.Connection; -import javax.jms.DeliveryMode; -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.Session; -import javax.jms.TextMessage; -import javax.jms.Topic; -import javax.jms.TopicConnection; -import javax.jms.TopicPublisher; -import javax.jms.TopicSession; -import javax.jms.TopicSubscriber; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.TabularDataSupport; - -import org.apache.qpid.management.common.mbeans.ManagedExchange; -import org.apache.qpid.management.common.mbeans.ManagedQueue; -import org.apache.qpid.server.model.VirtualHostNode; -import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBVirtualHostNode; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.util.FileUtils; -import org.apache.qpid.util.Strings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Tests upgrading a BDB store on broker startup. - * The store will then be used to verify that the upgrade is completed - * properly and that once upgraded it functions as expected. - * - * Store prepared using old client/broker with BDBStoreUpgradeTestPreparer. - */ -public class BDBUpgradeTest extends QpidBrokerTestCase -{ - protected static final Logger _logger = LoggerFactory.getLogger(BDBUpgradeTest.class); - - private static final String QPID_WORK_ORIG = System.getProperty("QPID_WORK"); - - private static final String STRING_1024 = generateString(1024); - private static final String STRING_1024_256 = generateString(1024*256); - - private static final String TOPIC_NAME="myUpgradeTopic"; - private static final String SUB_NAME="myDurSubName"; - private static final String SELECTOR_SUB_NAME="mySelectorDurSubName"; - private static final String SELECTOR_TOPIC_NAME="mySelectorUpgradeTopic"; - private static final String QUEUE_NAME="myUpgradeQueue"; - private static final String NON_DURABLE_QUEUE_NAME="queue-non-durable"; - private static final String PRIORITY_QUEUE_NAME="myPriorityQueue"; - private static final String QUEUE_WITH_DLQ_NAME="myQueueWithDLQ"; - - private String _storeLocation; - - @Override - public void setUp() throws Exception - { - assertNotNull("QPID_WORK must be set", QPID_WORK_ORIG); - Map virtualHostNodeAttributes = getBrokerConfiguration().getObjectAttributes(VirtualHostNode.class, TestBrokerConfiguration.ENTRY_NAME_VIRTUAL_HOST); - _storeLocation = Strings.expand((String)virtualHostNodeAttributes.get(BDBVirtualHostNode.STORE_PATH)); - - //Clear the two target directories if they exist. - File directory = new File(_storeLocation); - if (directory.exists() && directory.isDirectory()) - { - FileUtils.delete(directory, true); - } - directory.mkdirs(); - - // copy store files - InputStream src = getClass().getClassLoader().getResourceAsStream("upgrade/bdbstore-v4/test-store/00000000.jdb"); - FileUtils.copy(src, new File(_storeLocation, "00000000.jdb")); - - getBrokerConfiguration().addJmxManagementConfiguration(); - super.setUp(); - } - - /** - * Test that the selector applied to the DurableSubscription was successfully - * transfered to the new store, and functions as expected with continued use - * by monitoring message count while sending new messages to the topic and then - * consuming them. - */ - public void testSelectorDurability() throws Exception - { - JMXTestUtils jmxUtils = null; - try - { - jmxUtils = new JMXTestUtils(this, "guest", "guest"); - jmxUtils.open(); - } - catch (Exception e) - { - fail("Unable to establish JMX connection, test cannot proceed"); - } - - try - { - ManagedQueue dursubQueue = jmxUtils.getManagedQueue("clientid" + ":" + SELECTOR_SUB_NAME); - assertEquals("DurableSubscription backing queue should have 1 message on it initially", - new Integer(1), dursubQueue.getMessageCount()); - - // Create a connection and start it - TopicConnection connection = (TopicConnection) getConnection(); - connection.start(); - - // Send messages which don't match and do match the selector, checking message count - TopicSession pubSession = connection.createTopicSession(true, Session.SESSION_TRANSACTED); - Topic topic = pubSession.createTopic(SELECTOR_TOPIC_NAME); - TopicPublisher publisher = pubSession.createPublisher(topic); - - publishMessages(pubSession, publisher, topic, DeliveryMode.PERSISTENT, 1*1024, 1, "false"); - pubSession.commit(); - assertEquals("DurableSubscription backing queue should still have 1 message on it", - Integer.valueOf(1), dursubQueue.getMessageCount()); - - publishMessages(pubSession, publisher, topic, DeliveryMode.PERSISTENT, 1*1024, 1, "true"); - pubSession.commit(); - assertEquals("DurableSubscription backing queue should now have 2 messages on it", - Integer.valueOf(2), dursubQueue.getMessageCount()); - - TopicSubscriber durSub = pubSession.createDurableSubscriber(topic, SELECTOR_SUB_NAME,"testprop='true'", false); - Message m = durSub.receive(2000); - assertNotNull("Failed to receive an expected message", m); - m = durSub.receive(2000); - assertNotNull("Failed to receive an expected message", m); - pubSession.commit(); - - pubSession.close(); - } - finally - { - jmxUtils.close(); - } - } - - /** - * Test that the DurableSubscription without selector was successfully - * transfered to the new store, and functions as expected with continued use. - */ - public void testDurableSubscriptionWithoutSelector() throws Exception - { - JMXTestUtils jmxUtils = null; - try - { - jmxUtils = new JMXTestUtils(this, "guest", "guest"); - jmxUtils.open(); - } - catch (Exception e) - { - fail("Unable to establish JMX connection, test cannot proceed"); - } - - try - { - ManagedQueue dursubQueue = jmxUtils.getManagedQueue("clientid" + ":" + SUB_NAME); - assertEquals("DurableSubscription backing queue should have 1 message on it initially", - new Integer(1), dursubQueue.getMessageCount()); - - // Create a connection and start it - TopicConnection connection = (TopicConnection) getConnection(); - connection.start(); - - // Send new message matching the topic, checking message count - TopicSession session = connection.createTopicSession(true, Session.SESSION_TRANSACTED); - Topic topic = session.createTopic(TOPIC_NAME); - TopicPublisher publisher = session.createPublisher(topic); - - publishMessages(session, publisher, topic, DeliveryMode.PERSISTENT, 1*1024, 1, "indifferent"); - session.commit(); - assertEquals("DurableSubscription backing queue should now have 2 messages on it", - Integer.valueOf(2), dursubQueue.getMessageCount()); - - TopicSubscriber durSub = session.createDurableSubscriber(topic, SUB_NAME); - Message m = durSub.receive(2000); - assertNotNull("Failed to receive an expected message", m); - m = durSub.receive(2000); - assertNotNull("Failed to receive an expected message", m); - - session.commit(); - session.close(); - } - finally - { - jmxUtils.close(); - } - } - - /** - * Test that the backing queue for the durable subscription created was successfully - * detected and set as being exclusive during the upgrade process, and that the - * regular queue was not. - */ - public void testQueueExclusivity() throws Exception - { - JMXTestUtils jmxUtils = null; - try - { - jmxUtils = new JMXTestUtils(this, "guest", "guest"); - jmxUtils.open(); - } - catch (Exception e) - { - fail("Unable to establish JMX connection, test cannot proceed"); - } - - try - { - ManagedQueue queue = jmxUtils.getManagedQueue(QUEUE_NAME); - assertFalse("Queue should not have been marked as Exclusive during upgrade", queue.isExclusive()); - - ManagedQueue dursubQueue = jmxUtils.getManagedQueue("clientid" + ":" + SUB_NAME); - assertTrue("DurableSubscription backing queue should have been marked as Exclusive during upgrade", dursubQueue.isExclusive()); - } - finally - { - jmxUtils.close(); - } - } - - /** - * Test that the upgraded queue continues to function properly when used - * for persistent messaging and restarting the broker. - * - * Sends the new messages to the queue BEFORE consuming those which were - * sent before the upgrade. In doing so, this also serves to test that - * the queue bindings were successfully transitioned during the upgrade. - */ - public void testBindingAndMessageDurabability() throws Exception - { - // Create a connection and start it - TopicConnection connection = (TopicConnection) getConnection(); - connection.start(); - - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Queue queue = session.createQueue(QUEUE_NAME); - MessageProducer messageProducer = session.createProducer(queue); - - // Send a new message - sendMessages(session, messageProducer, queue, DeliveryMode.PERSISTENT, 256*1024, 1); - - session.close(); - - // Restart the broker - restartBroker(); - - // Drain the queue of all messages - connection = (TopicConnection) getConnection(); - connection.start(); - consumeQueueMessages(connection, true); - } - - /** - * Test that all of the committed persistent messages previously sent to - * the broker are properly received following update of the MetaData and - * Content entries during the store upgrade process. - */ - public void testConsumptionOfUpgradedMessages() throws Exception - { - // Create a connection and start it - Connection connection = getConnection(); - connection.start(); - - consumeDurableSubscriptionMessages(connection, true); - consumeDurableSubscriptionMessages(connection, false); - consumeQueueMessages(connection, false); - } - - /** - * Tests store migration containing messages for non-existing queue. - * - * @throws Exception - */ - public void testMigrationOfMessagesForNonDurableQueues() throws Exception - { - // Create a connection and start it - Connection connection = getConnection(); - connection.start(); - - // consume a message for non-existing store - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Queue queue = session.createQueue(NON_DURABLE_QUEUE_NAME); - MessageConsumer messageConsumer = session.createConsumer(queue); - - for (int i = 1; i <= 3; i++) - { - Message message = messageConsumer.receive(1000); - assertNotNull("Message was not migrated!", message); - assertTrue("Unexpected message received!", message instanceof TextMessage); - assertEquals("ID property did not match", i, message.getIntProperty("ID")); - } - } - - /** - * Tests store upgrade has maintained the priority queue configuration, - * such that sending messages with priorities out-of-order and then consuming - * them gets the messages back in priority order. - */ - public void testPriorityQueue() throws Exception - { - // Create a connection and start it - Connection connection = getConnection(); - connection.start(); - - // send some messages to the priority queue - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Queue queue = session.createQueue(PRIORITY_QUEUE_NAME); - MessageProducer producer = session.createProducer(queue); - - producer.setPriority(4); - producer.send(createMessage(1, false, session, producer)); - producer.setPriority(1); - producer.send(createMessage(2, false, session, producer)); - producer.setPriority(9); - producer.send(createMessage(3, false, session, producer)); - session.close(); - - //consume the messages, expected order: msg 3, msg 1, msg 2. - session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer consumer = session.createConsumer(queue); - - Message msg = consumer.receive(1500); - assertNotNull("expected message was not received", msg); - assertEquals(3, msg.getIntProperty("msg")); - msg = consumer.receive(1500); - assertNotNull("expected message was not received", msg); - assertEquals(1, msg.getIntProperty("msg")); - msg = consumer.receive(1500); - assertNotNull("expected message was not received", msg); - assertEquals(2, msg.getIntProperty("msg")); - } - - /** - * - * TODO (QPID-5650) Resolve so this test can be reenabled. - * - * Test that the queue configured to have a DLQ was recovered and has the alternate exchange - * and max delivery count, the DLE exists, the DLQ exists with no max delivery count, the - * DLQ is bound to the DLE, and that the DLQ does not itself have a DLQ. - * - * DLQs are NOT enabled at the virtualhost level, we are testing recovery of the arguments - * that turned it on for this specific queue. - */ - public void xtestRecoveryOfQueueWithDLQ() throws Exception - { - JMXTestUtils jmxUtils = null; - try - { - jmxUtils = new JMXTestUtils(this, "guest", "guest"); - jmxUtils.open(); - } - catch (Exception e) - { - fail("Unable to establish JMX connection, test cannot proceed"); - } - - try - { - //verify the DLE exchange exists, has the expected type, and a single binding for the DLQ - ManagedExchange exchange = jmxUtils.getManagedExchange(QUEUE_WITH_DLQ_NAME + "_DLE"); - assertEquals("Wrong exchange type", "fanout", exchange.getExchangeType()); - TabularDataSupport bindings = (TabularDataSupport) exchange.bindings(); - assertEquals(1, bindings.size()); - for(Object o : bindings.values()) - { - CompositeData binding = (CompositeData) o; - - String bindingKey = (String) binding.get(ManagedExchange.BINDING_KEY); - String[] queueNames = (String[]) binding.get(ManagedExchange.QUEUE_NAMES); - - //Because its a fanout exchange, we just return a single '*' key with all bound queues - assertEquals("unexpected binding key", "*", bindingKey); - assertEquals("unexpected number of queues bound", 1, queueNames.length); - assertEquals("unexpected queue name", QUEUE_WITH_DLQ_NAME + "_DLQ", queueNames[0]); - } - - //verify the queue exists, has the expected alternate exchange and max delivery count - ManagedQueue queue = jmxUtils.getManagedQueue(QUEUE_WITH_DLQ_NAME); - assertEquals("Queue does not have the expected AlternateExchange", QUEUE_WITH_DLQ_NAME + "_DLE", queue.getAlternateExchange()); - assertEquals("Unexpected maximum delivery count", Integer.valueOf(2), queue.getMaximumDeliveryCount()); - - ManagedQueue dlQqueue = jmxUtils.getManagedQueue(QUEUE_WITH_DLQ_NAME + "_DLQ"); - assertNull("Queue should not have an AlternateExchange", dlQqueue.getAlternateExchange()); - assertEquals("Unexpected maximum delivery count", Integer.valueOf(0), dlQqueue.getMaximumDeliveryCount()); - - String dlqDlqObjectNameString = jmxUtils.getQueueObjectNameString("test", QUEUE_WITH_DLQ_NAME + "_DLQ" + "_DLQ"); - assertFalse("a DLQ should not exist for the DLQ itself", jmxUtils.doesManagedObjectExist(dlqDlqObjectNameString)); - } - finally - { - jmxUtils.close(); - } - } - - private void consumeDurableSubscriptionMessages(Connection connection, boolean selector) throws Exception - { - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Topic topic = null; - TopicSubscriber durSub = null; - - if(selector) - { - topic = session.createTopic(SELECTOR_TOPIC_NAME); - durSub = session.createDurableSubscriber(topic, SELECTOR_SUB_NAME,"testprop='true'", false); - } - else - { - topic = session.createTopic(TOPIC_NAME); - durSub = session.createDurableSubscriber(topic, SUB_NAME); - } - - - // Retrieve the matching message - Message m = durSub.receive(2000); - assertNotNull("Failed to receive an expected message", m); - if(selector) - { - assertEquals("Selector property did not match", "true", m.getStringProperty("testprop")); - } - assertEquals("ID property did not match", 1, m.getIntProperty("ID")); - assertEquals("Message content was not as expected", generateString(1024) , ((TextMessage)m).getText()); - - // Verify that no more messages are received - m = durSub.receive(1000); - assertNull("No more messages should have been recieved", m); - - durSub.close(); - session.close(); - } - - private void consumeQueueMessages(Connection connection, boolean extraMessage) throws Exception - { - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Queue queue = session.createQueue(QUEUE_NAME); - - MessageConsumer consumer = session.createConsumer(queue); - Message m; - - // Retrieve the initial pre-upgrade messages - for (int i=1; i <= 5 ; i++) - { - m = consumer.receive(2000); - assertNotNull("Failed to receive an expected message", m); - assertEquals("ID property did not match", i, m.getIntProperty("ID")); - assertEquals("Message content was not as expected", STRING_1024_256, ((TextMessage)m).getText()); - } - for (int i=1; i <= 5 ; i++) - { - m = consumer.receive(2000); - assertNotNull("Failed to receive an expected message", m); - assertEquals("ID property did not match", i, m.getIntProperty("ID")); - assertEquals("Message content was not as expected", STRING_1024, ((TextMessage)m).getText()); - } - - if(extraMessage) - { - //verify that the extra message is received - m = consumer.receive(2000); - assertNotNull("Failed to receive an expected message", m); - assertEquals("ID property did not match", 1, m.getIntProperty("ID")); - assertEquals("Message content was not as expected", STRING_1024_256, ((TextMessage)m).getText()); - } - - // Verify that no more messages are received - m = consumer.receive(1000); - assertNull("No more messages should have been recieved", m); - - consumer.close(); - session.close(); - } - - private Message createMessage(int msgId, boolean first, Session producerSession, MessageProducer producer) throws JMSException - { - Message send = producerSession.createTextMessage("Message: " + msgId); - send.setIntProperty("msg", msgId); - - return send; - } - - /** - * Generates a string of a given length consisting of the sequence 0,1,2,..,9,0,1,2. - * - * @param length number of characters in the string - * @return string sequence of the given length - */ - private static String generateString(int length) - { - char[] base_chars = new char[]{'0','1','2','3','4','5','6','7','8','9'}; - char[] chars = new char[length]; - for (int i = 0; i < (length); i++) - { - chars[i] = base_chars[i % 10]; - } - return new String(chars); - } - - private static void sendMessages(Session session, MessageProducer messageProducer, - Destination dest, int deliveryMode, int length, int numMesages) throws JMSException - { - for (int i = 1; i <= numMesages; i++) - { - Message message = session.createTextMessage(generateString(length)); - message.setIntProperty("ID", i); - messageProducer.send(message, deliveryMode, Message.DEFAULT_PRIORITY, Message.DEFAULT_TIME_TO_LIVE); - } - } - - private static void publishMessages(Session session, TopicPublisher publisher, - Destination dest, int deliveryMode, int length, int numMesages, String selectorProperty) throws JMSException - { - for (int i = 1; i <= numMesages; i++) - { - Message message = session.createTextMessage(generateString(length)); - message.setIntProperty("ID", i); - message.setStringProperty("testprop", selectorProperty); - publisher.publish(message, deliveryMode, Message.DEFAULT_PRIORITY, Message.DEFAULT_TIME_TO_LIVE); - } - } -} diff --git a/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HAClusterBlackboxTest.java b/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HAClusterBlackboxTest.java deleted file mode 100644 index 9867ce2eca..0000000000 --- a/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HAClusterBlackboxTest.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.store.berkeleydb; - -import java.io.File; -import java.util.Collections; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import javax.jms.Connection; -import javax.jms.Session; - -import org.apache.log4j.Logger; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.jms.ConnectionListener; -import org.apache.qpid.jms.ConnectionURL; -import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHAVirtualHostNode; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.test.utils.TestUtils; - -/** - * The HA black box tests test the BDB cluster as a opaque unit. Client connects to - * the cluster via a failover url - * - * @see HAClusterWhiteboxTest - */ -public class HAClusterBlackboxTest extends QpidBrokerTestCase -{ - protected static final Logger LOGGER = Logger.getLogger(HAClusterBlackboxTest.class); - - private static final String VIRTUAL_HOST = "test"; - private static final int NUMBER_OF_NODES = 3; - - private final HATestClusterCreator _clusterCreator = new HATestClusterCreator(this, VIRTUAL_HOST, NUMBER_OF_NODES); - - private FailoverAwaitingListener _failoverListener; - private ConnectionURL _brokerFailoverUrl; - - @Override - protected void setUp() throws Exception - { - _brokerType = BrokerType.SPAWNED; - - assertTrue(isJavaBroker()); - assertTrue(isBrokerStorePersistent()); - - setSystemProperty("java.util.logging.config.file", "etc" + File.separator + "log.properties"); - - _clusterCreator.configureClusterNodes(); - - _brokerFailoverUrl = _clusterCreator.getConnectionUrlForAllClusterNodes(); - - _clusterCreator.startCluster(); - _failoverListener = new FailoverAwaitingListener(); - - super.setUp(); - } - - @Override - public void startBroker() throws Exception - { - // Don't start default broker provided by QBTC. - } - - public void testLossOfMasterNodeCausesClientToFailover() throws Exception - { - final Connection connection = getConnection(_brokerFailoverUrl); - - ((AMQConnection)connection).setConnectionListener(_failoverListener); - - final int activeBrokerPort = _clusterCreator.getBrokerPortNumberFromConnection(connection); - LOGGER.info("Active connection port " + activeBrokerPort); - - _clusterCreator.stopNode(activeBrokerPort); - LOGGER.info("Node is stopped"); - _failoverListener.awaitFailoverCompletion(20000); - LOGGER.info("Listener has finished"); - // any op to ensure connection remains - connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - } - - public void testLossOfReplicaNodeDoesNotCauseClientToFailover() throws Exception - { - LOGGER.info("Connecting to " + _brokerFailoverUrl); - final Connection connection = getConnection(_brokerFailoverUrl); - LOGGER.info("Got connection to cluster"); - - ((AMQConnection)connection).setConnectionListener(_failoverListener); - final int activeBrokerPort = _clusterCreator.getBrokerPortNumberFromConnection(connection); - LOGGER.info("Active connection port " + activeBrokerPort); - final int inactiveBrokerPort = _clusterCreator.getPortNumberOfAnInactiveBroker(connection); - - LOGGER.info("Stopping inactive broker on port " + inactiveBrokerPort); - - _clusterCreator.stopNode(inactiveBrokerPort); - - _failoverListener.assertNoFailoverCompletionWithin(2000); - - // any op to ensure connection remains - connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - } - - public void testTransferMasterFromLocalNode() throws Exception - { - final Connection connection = getConnection(_brokerFailoverUrl); - - ((AMQConnection)connection).setConnectionListener(_failoverListener); - - final int activeBrokerPort = _clusterCreator.getBrokerPortNumberFromConnection(connection); - LOGGER.info("Active connection port " + activeBrokerPort); - - final int inactiveBrokerPort = _clusterCreator.getPortNumberOfAnInactiveBroker(connection); - LOGGER.info("Update role attribute on inactive broker on port " + inactiveBrokerPort); - - Map attributes = _clusterCreator.getNodeAttributes(inactiveBrokerPort); - assertEquals("Inactive broker has unexpected role", "REPLICA", attributes.get(BDBHAVirtualHostNode.ROLE)); - _clusterCreator.setNodeAttributes(inactiveBrokerPort, Collections.singletonMap(BDBHAVirtualHostNode.ROLE, "MASTER")); - - _failoverListener.awaitFailoverCompletion(20000); - LOGGER.info("Listener has finished"); - - attributes = _clusterCreator.getNodeAttributes(inactiveBrokerPort); - assertEquals("Inactive broker has unexpected role", "MASTER", attributes.get(BDBHAVirtualHostNode.ROLE)); - - assertProducingConsuming(connection); - - _clusterCreator.awaitNodeToAttainRole(activeBrokerPort, "REPLICA"); - } - - public void testTransferMasterFromRemoteNode() throws Exception - { - final Connection connection = getConnection(_brokerFailoverUrl); - - ((AMQConnection)connection).setConnectionListener(_failoverListener); - - final int activeBrokerPort = _clusterCreator.getBrokerPortNumberFromConnection(connection); - LOGGER.info("Active connection port " + activeBrokerPort); - - final int inactiveBrokerPort = _clusterCreator.getPortNumberOfAnInactiveBroker(connection); - LOGGER.info("Update role attribute on inactive broker on port " + inactiveBrokerPort); - - _clusterCreator.awaitNodeToAttainRole(activeBrokerPort, inactiveBrokerPort, "REPLICA"); - Map attributes = _clusterCreator.getNodeAttributes(activeBrokerPort, inactiveBrokerPort); - assertEquals("Inactive broker has unexpected role", "REPLICA", attributes.get(BDBHAVirtualHostNode.ROLE)); - - _clusterCreator.setNodeAttributes(activeBrokerPort, inactiveBrokerPort, Collections.singletonMap(BDBHAVirtualHostNode.ROLE, "MASTER")); - - _failoverListener.awaitFailoverCompletion(20000); - LOGGER.info("Listener has finished"); - - attributes = _clusterCreator.getNodeAttributes(inactiveBrokerPort); - assertEquals("Inactive broker has unexpected role", "MASTER", attributes.get(BDBHAVirtualHostNode.ROLE)); - - assertProducingConsuming(connection); - - _clusterCreator.awaitNodeToAttainRole(activeBrokerPort, "REPLICA"); - } - - public void testQuorumOverride() throws Exception - { - final Connection connection = getConnection(_brokerFailoverUrl); - - ((AMQConnection)connection).setConnectionListener(_failoverListener); - - Set ports = _clusterCreator.getBrokerPortNumbersForNodes(); - - final int activeBrokerPort = _clusterCreator.getBrokerPortNumberFromConnection(connection); - ports.remove(activeBrokerPort); - - // Stop all other nodes - for (Integer p : ports) - { - _clusterCreator.stopNode(p); - } - - Map attributes = _clusterCreator.getNodeAttributes(activeBrokerPort); - assertEquals("Broker has unexpected quorum override", new Integer(0), attributes.get(BDBHAVirtualHostNode.QUORUM_OVERRIDE)); - _clusterCreator.setNodeAttributes(activeBrokerPort, Collections.singletonMap(BDBHAVirtualHostNode.QUORUM_OVERRIDE, 1)); - - attributes = _clusterCreator.getNodeAttributes(activeBrokerPort); - assertEquals("Broker has unexpected quorum override", new Integer(1), attributes.get(BDBHAVirtualHostNode.QUORUM_OVERRIDE)); - - assertProducingConsuming(connection); - } - - public void testPriority() throws Exception - { - final Connection connection = getConnection(_brokerFailoverUrl); - - ((AMQConnection)connection).setConnectionListener(_failoverListener); - - final int activeBrokerPort = _clusterCreator.getBrokerPortNumberFromConnection(connection); - LOGGER.info("Active connection port " + activeBrokerPort); - - int priority = 1; - Integer highestPriorityBrokerPort = null; - Set ports = _clusterCreator.getBrokerPortNumbersForNodes(); - for (Integer port : ports) - { - if (activeBrokerPort != port.intValue()) - { - priority = priority + 1; - highestPriorityBrokerPort = port; - _clusterCreator.setNodeAttributes(port, port, Collections.singletonMap(BDBHAVirtualHostNode.PRIORITY, priority)); - Map attributes = _clusterCreator.getNodeAttributes(port, port); - assertEquals("Broker has unexpected priority", priority, attributes.get(BDBHAVirtualHostNode.PRIORITY)); - } - } - - LOGGER.info("Broker on port " + highestPriorityBrokerPort + " has the highest priority of " + priority); - - LOGGER.info("Shutting down the MASTER"); - _clusterCreator.stopNode(activeBrokerPort); - - _failoverListener.awaitFailoverCompletion(20000); - LOGGER.info("Listener has finished"); - - Map attributes = _clusterCreator.getNodeAttributes(highestPriorityBrokerPort, highestPriorityBrokerPort); - assertEquals("Inactive broker has unexpected role", "MASTER", attributes.get(BDBHAVirtualHostNode.ROLE)); - - assertProducingConsuming(connection); - } - - private final class FailoverAwaitingListener implements ConnectionListener - { - private final CountDownLatch _failoverCompletionLatch = new CountDownLatch(1); - - @Override - public boolean preResubscribe() - { - return true; - } - - @Override - public boolean preFailover(boolean redirect) - { - return true; - } - - public void awaitFailoverCompletion(long delay) throws InterruptedException - { - if (!_failoverCompletionLatch.await(delay, TimeUnit.MILLISECONDS)) - { - LOGGER.warn("Test thread dump:\n\n" + TestUtils.dumpThreads() + "\n"); - } - assertEquals("Failover did not occur", 0, _failoverCompletionLatch.getCount()); - } - - public void assertNoFailoverCompletionWithin(long delay) throws InterruptedException - { - _failoverCompletionLatch.await(delay, TimeUnit.MILLISECONDS); - assertEquals("Failover occurred unexpectedly", 1L, _failoverCompletionLatch.getCount()); - } - - @Override - public void failoverComplete() - { - _failoverCompletionLatch.countDown(); - } - - @Override - public void bytesSent(long count) - { - } - - @Override - public void bytesReceived(long count) - { - } - } - -} diff --git a/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HAClusterManagementTest.java b/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HAClusterManagementTest.java deleted file mode 100644 index 0ab10cc318..0000000000 --- a/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HAClusterManagementTest.java +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.store.berkeleydb; - -import static com.sleepycat.je.rep.ReplicatedEnvironment.State.DETACHED; -import static com.sleepycat.je.rep.ReplicatedEnvironment.State.MASTER; -import static com.sleepycat.je.rep.ReplicatedEnvironment.State.REPLICA; -import static com.sleepycat.je.rep.ReplicatedEnvironment.State.UNKNOWN; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.jms.Connection; -import javax.management.ObjectName; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.TabularData; - -import org.apache.log4j.Logger; -import org.apache.qpid.jms.ConnectionURL; -import org.apache.qpid.management.common.mbeans.ManagedBroker; -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.model.VirtualHost; -import org.apache.qpid.server.store.berkeleydb.jmx.ManagedBDBHAMessageStore; -import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHAVirtualHostNode; -import org.apache.qpid.systest.rest.RestTestHelper; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.junit.Assert; - -/** - * System test verifying the ability to control a cluster via the Management API. - * - * @see HAClusterBlackboxTest - */ -public class HAClusterManagementTest extends QpidBrokerTestCase -{ - protected static final Logger LOGGER = Logger.getLogger(HAClusterManagementTest.class); - - private static final Set NON_MASTER_STATES = new HashSet(Arrays.asList(REPLICA.toString(), DETACHED.toString(), UNKNOWN.toString()));; - private static final String VIRTUAL_HOST = "test"; - - private static final String MANAGED_OBJECT_QUERY = "org.apache.qpid:type=BDBHAMessageStore,name=" + ObjectName.quote(VIRTUAL_HOST); - private static final int NUMBER_OF_NODES = 4; - - private final HATestClusterCreator _clusterCreator = new HATestClusterCreator(this, VIRTUAL_HOST, NUMBER_OF_NODES); - private final JMXTestUtils _jmxUtils = new JMXTestUtils(this); - - private ConnectionURL _brokerFailoverUrl; - - @Override - protected void setUp() throws Exception - { - _brokerType = BrokerType.SPAWNED; - - _clusterCreator.configureClusterNodes(); - _brokerFailoverUrl = _clusterCreator.getConnectionUrlForAllClusterNodes(); - _clusterCreator.startCluster(); - - super.setUp(); - } - - @Override - protected void tearDown() throws Exception - { - try - { - _jmxUtils.close(); - } - finally - { - super.tearDown(); - } - } - - @Override - public void startBroker() throws Exception - { - // Don't start default broker provided by QBTC. - } - - public void testReadonlyMBeanAttributes() throws Exception - { - final int brokerPortNumber = getBrokerPortNumbers().iterator().next(); - final int bdbPortNumber = _clusterCreator.getBdbPortForBrokerPort(brokerPortNumber); - - ManagedBDBHAMessageStore storeBean = getStoreBeanForNodeAtBrokerPort(brokerPortNumber); - assertEquals("Unexpected store group name", _clusterCreator.getGroupName(), storeBean.getGroupName()); - assertEquals("Unexpected store node name", _clusterCreator.getNodeNameForNodeAt(bdbPortNumber), storeBean.getNodeName()); - assertEquals("Unexpected store node host port",_clusterCreator.getNodeHostPortForNodeAt(bdbPortNumber), storeBean.getNodeHostPort()); - assertEquals("Unexpected store helper host port", _clusterCreator.getHelperHostPort(), storeBean.getHelperHostPort()); - // As we have chosen an arbitrary broker from the cluster, we cannot predict its state - assertNotNull("Store state must not be null", storeBean.getNodeState()); - } - - public void testStateOfActiveBrokerIsMaster() throws Exception - { - final Connection activeConnection = getConnection(_brokerFailoverUrl); - final int activeBrokerPortNumber = _clusterCreator.getBrokerPortNumberFromConnection(activeConnection); - - ManagedBDBHAMessageStore storeBean = getStoreBeanForNodeAtBrokerPort(activeBrokerPortNumber); - assertEquals("Unexpected store state", MASTER.toString(), storeBean.getNodeState()); - } - - public void testStateOfNonActiveBrokerIsNotMaster() throws Exception - { - final Connection activeConnection = getConnection(_brokerFailoverUrl); - final int inactiveBrokerPortNumber = _clusterCreator.getPortNumberOfAnInactiveBroker(activeConnection); - ManagedBDBHAMessageStore storeBean = getStoreBeanForNodeAtBrokerPort(inactiveBrokerPortNumber); - final String nodeState = storeBean.getNodeState(); - assertTrue("Unexpected store state : " + nodeState, NON_MASTER_STATES.contains(nodeState)); - } - - public void testGroupMembers() throws Exception - { - final int brokerPortNumber = getBrokerPortNumbers().iterator().next(); - - ManagedBDBHAMessageStore storeBean = getStoreBeanForNodeAtBrokerPort(brokerPortNumber); - awaitAllNodesJoiningGroup(storeBean, NUMBER_OF_NODES); - - final TabularData groupMembers = storeBean.getAllNodesInGroup(); - assertNotNull(groupMembers); - - for(int bdbPortNumber : _clusterCreator.getBdbPortNumbers()) - { - final String nodeName = _clusterCreator.getNodeNameForNodeAt(bdbPortNumber); - final String nodeHostPort = _clusterCreator.getNodeHostPortForNodeAt(bdbPortNumber); - - CompositeData row = groupMembers.get(new Object[] {nodeName}); - assertNotNull("Table does not contain row for node name " + nodeName, row); - assertEquals(nodeHostPort, row.get(ManagedBDBHAMessageStore.GRP_MEM_COL_NODE_HOST_PORT)); - } - } - - public void testRemoveRemoteNodeFromGroup() throws Exception - { - final Iterator brokerPortNumberIterator = getBrokerPortNumbers().iterator(); - final int brokerPortNumberToMakeObservation = brokerPortNumberIterator.next(); - final int brokerPortNumberToBeRemoved = brokerPortNumberIterator.next(); - final ManagedBDBHAMessageStore storeBean = getStoreBeanForNodeAtBrokerPort(brokerPortNumberToMakeObservation); - awaitAllNodesJoiningGroup(storeBean, NUMBER_OF_NODES); - - final String removedNodeName = _clusterCreator.getNodeNameForNodeAt(_clusterCreator.getBdbPortForBrokerPort(brokerPortNumberToBeRemoved)); - _clusterCreator.stopNode(brokerPortNumberToBeRemoved); - - storeBean.removeNodeFromGroup(removedNodeName); - - long limitTime = System.currentTimeMillis() + 5000; - while((NUMBER_OF_NODES == storeBean.getAllNodesInGroup().size()) && System.currentTimeMillis() < limitTime) - { - Thread.sleep(100l); - } - - int numberOfDataRowsAfterRemoval = storeBean.getAllNodesInGroup().size(); - assertEquals("Unexpected number of data rows after test", NUMBER_OF_NODES - 1, numberOfDataRowsAfterRemoval); - } - - public void testVirtualHostOperationsDeniedForNonMasterNode() throws Exception - { - final Connection activeConnection = getConnection(_brokerFailoverUrl); - final int inactiveBrokerPortNumber = _clusterCreator.getPortNumberOfAnInactiveBroker(activeConnection); - - ManagedBroker inactiveBroker = getManagedBrokerBeanForNodeAtBrokerPort(inactiveBrokerPortNumber); - - try - { - inactiveBroker.createNewQueue(getTestQueueName(), null, true); - fail("Exception not thrown"); - } - catch (Exception e) - { - String message = e.getMessage(); - assertEquals("The virtual host state of UNAVAILABLE does not permit this operation.", message); - } - - try - { - inactiveBroker.createNewExchange(getName(), "direct", true); - fail("Exception not thrown"); - } - catch (Exception e) - { - String message = e.getMessage(); - assertEquals("The virtual host state of UNAVAILABLE does not permit this operation.", message); - } - } - - public void testSetDesignatedPrimary() throws Exception - { - int brokerPort = _clusterCreator.getBrokerPortNumbersForNodes().iterator().next(); - final ManagedBDBHAMessageStore storeBean = getStoreBeanForNodeAtBrokerPort(brokerPort); - assertFalse("Unexpected designated primary before change", storeBean.getDesignatedPrimary()); - storeBean.setDesignatedPrimary(true); - long limit = System.currentTimeMillis() + 5000; - while(!storeBean.getDesignatedPrimary() && System.currentTimeMillis() < limit) - { - Thread.sleep(100l); - } - assertTrue("Unexpected designated primary after change", storeBean.getDesignatedPrimary()); - } - - public void testVirtualHostMbeanOnMasterTransfer() throws Exception - { - Connection connection = getConnection(_brokerFailoverUrl); - int activeBrokerPort = _clusterCreator.getBrokerPortNumberFromConnection(connection); - LOGGER.info("Active connection port " + activeBrokerPort); - connection.close(); - - Set ports = _clusterCreator.getBrokerPortNumbersForNodes(); - ports.remove(activeBrokerPort); - - int inactiveBrokerPort = ports.iterator().next(); - LOGGER.info("Update role attribute on inactive broker on port " + inactiveBrokerPort); - - ManagedBroker inactiveVirtualHostMBean = getManagedBrokerBeanForNodeAtBrokerPort(inactiveBrokerPort); - - try - { - inactiveVirtualHostMBean.createNewQueue(getTestQueueName(), null, true); - fail("Exception not thrown"); - } - catch (Exception e) - { - String message = e.getMessage(); - assertEquals("The virtual host state of UNAVAILABLE does not permit this operation.", message); - } - - Map attributes = _clusterCreator.getNodeAttributes(inactiveBrokerPort); - assertEquals("Inactive broker has unexpected role", "REPLICA", attributes.get(BDBHAVirtualHostNode.ROLE)); - _clusterCreator.setNodeAttributes(inactiveBrokerPort, Collections.singletonMap(BDBHAVirtualHostNode.ROLE, "MASTER")); - - _clusterCreator.awaitNodeToAttainRole(inactiveBrokerPort, "MASTER"); - - awaitVirtualHostAtNode(inactiveBrokerPort); - - ManagedBroker activeVirtualHostMBean = getManagedBrokerBeanForNodeAtBrokerPort(inactiveBrokerPort); - activeVirtualHostMBean.createNewQueue(getTestQueueName() + inactiveBrokerPort, null, true); - } - - public void awaitVirtualHostAtNode(int brokerPort) throws Exception - { - final long startTime = System.currentTimeMillis(); - Map data = Collections.emptyMap(); - String nodeName = _clusterCreator.getNodeNameForBrokerPort(brokerPort); - RestTestHelper restHelper = _clusterCreator.createRestTestHelper(brokerPort); - while(!State.ACTIVE.name().equals(data.get(VirtualHost.STATE)) && (System.currentTimeMillis() - startTime) < 30000) - { - LOGGER.debug("Awaiting virtual host '" + nodeName + "' to transit into active state"); - List> results= restHelper.getJsonAsList("virtualhost/" + nodeName + "/" + VIRTUAL_HOST); - if (results.size()== 1) - { - data = results.get(0); - } - - if (!State.ACTIVE.name().equals(data.get(VirtualHost.STATE))) - { - Thread.sleep(1000); - } - } - Assert.assertEquals("Virtual host is not active", State.ACTIVE.name(), data.get(VirtualHost.STATE)); - LOGGER.debug("Virtual host '" + nodeName + "' is in active state"); - } - - private ManagedBDBHAMessageStore getStoreBeanForNodeAtBrokerPort(final int brokerPortNumber) throws Exception - { - _jmxUtils.open(brokerPortNumber); - - return _jmxUtils.getManagedObject(ManagedBDBHAMessageStore.class, MANAGED_OBJECT_QUERY); - } - - private ManagedBroker getManagedBrokerBeanForNodeAtBrokerPort(final int brokerPortNumber) throws Exception - { - _jmxUtils.open(brokerPortNumber); - - return _jmxUtils.getManagedBroker(VIRTUAL_HOST); - } - - private void awaitAllNodesJoiningGroup(ManagedBDBHAMessageStore storeBean, int expectedNumberOfNodes) throws Exception - { - long totalTimeWaited = 0l; - long waitInterval = 100l; - long maxWaitTime = 10000; - - int currentNumberOfNodes = storeBean.getAllNodesInGroup().size(); - while (expectedNumberOfNodes > currentNumberOfNodes || totalTimeWaited > maxWaitTime) - { - LOGGER.debug("Still awaiting nodes to join group; expecting " - + expectedNumberOfNodes + " node(s) but only have " + currentNumberOfNodes - + " after " + totalTimeWaited + " ms."); - - totalTimeWaited += waitInterval; - Thread.sleep(waitInterval); - - currentNumberOfNodes = storeBean.getAllNodesInGroup().size(); - } - - assertEquals("Unexpected number of nodes in group after " + totalTimeWaited + " ms", - expectedNumberOfNodes ,currentNumberOfNodes); - } -} diff --git a/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HAClusterTwoNodeTest.java b/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HAClusterTwoNodeTest.java deleted file mode 100644 index 8df419c3a7..0000000000 --- a/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HAClusterTwoNodeTest.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.store.berkeleydb; - -import java.io.File; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.management.ObjectName; - -import org.apache.qpid.jms.ConnectionURL; -import org.apache.qpid.server.store.berkeleydb.jmx.ManagedBDBHAMessageStore; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class HAClusterTwoNodeTest extends QpidBrokerTestCase -{ - private static final String VIRTUAL_HOST = "test"; - - private static final String MANAGED_OBJECT_QUERY = "org.apache.qpid:type=BDBHAMessageStore,name=" + ObjectName.quote(VIRTUAL_HOST); - private static final int NUMBER_OF_NODES = 2; - - private final HATestClusterCreator _clusterCreator = new HATestClusterCreator(this, VIRTUAL_HOST, NUMBER_OF_NODES); - private final JMXTestUtils _jmxUtils = new JMXTestUtils(this); - - private ConnectionURL _brokerFailoverUrl; - - @Override - protected void setUp() throws Exception - { - _brokerType = BrokerType.SPAWNED; - - assertTrue(isJavaBroker()); - assertTrue(isBrokerStorePersistent()); - - super.setUp(); - } - - @Override - protected void tearDown() throws Exception - { - try - { - _jmxUtils.close(); - } - finally - { - super.tearDown(); - } - } - - @Override - public void startBroker() throws Exception - { - // Don't start default broker provided by QBTC. - } - - private void startCluster(boolean designedPrimary) throws Exception - { - setSystemProperty("java.util.logging.config.file", "etc" + File.separator + "log.properties"); - _clusterCreator.configureClusterNodes(); - _clusterCreator.setDesignatedPrimaryOnFirstBroker(designedPrimary); - _brokerFailoverUrl = _clusterCreator.getConnectionUrlForAllClusterNodes(); - _clusterCreator.startCluster(); - } - - public void testMasterDesignatedPrimaryCanBeRestartedWithoutReplica() throws Exception - { - startCluster(true); - final Connection initialConnection = getConnection(_brokerFailoverUrl); - int masterPort = _clusterCreator.getBrokerPortNumberFromConnection(initialConnection); - assertProducingConsuming(initialConnection); - initialConnection.close(); - _clusterCreator.stopCluster(); - _clusterCreator.startNode(masterPort); - final Connection secondConnection = getConnection(_brokerFailoverUrl); - assertProducingConsuming(secondConnection); - secondConnection.close(); - } - - public void testClusterRestartWithoutDesignatedPrimary() throws Exception - { - startCluster(false); - final Connection initialConnection = getConnection(_brokerFailoverUrl); - assertProducingConsuming(initialConnection); - initialConnection.close(); - _clusterCreator.stopCluster(); - _clusterCreator.startClusterParallel(); - final Connection secondConnection = getConnection(_brokerFailoverUrl); - assertProducingConsuming(secondConnection); - secondConnection.close(); - } - - public void testDesignatedPrimaryContinuesAfterSecondaryStopped() throws Exception - { - startCluster(true); - _clusterCreator.stopNode(_clusterCreator.getBrokerPortNumberOfSecondaryNode()); - final Connection connection = getConnection(_brokerFailoverUrl); - assertNotNull("Expected to get a valid connection to primary", connection); - assertProducingConsuming(connection); - } - - public void testPersistentOperationsFailOnNonDesignatedPrimaryAfterSecondaryStopped() throws Exception - { - startCluster(false); - _clusterCreator.stopNode(_clusterCreator.getBrokerPortNumberOfSecondaryNode()); - - try - { - Connection connection = getConnection(_brokerFailoverUrl); - assertProducingConsuming(connection); - fail("Exception not thrown"); - } - catch(JMSException e) - { - // JMSException should be thrown either on getConnection, or produce/consume - // depending on whether the relative timing of the node discovering that the - // secondary has gone. - } - } - - public void testSecondaryDoesNotBecomePrimaryWhenDesignatedPrimaryStopped() throws Exception - { - startCluster(true); - _clusterCreator.stopNode(_clusterCreator.getBrokerPortNumberOfPrimary()); - - try - { - getConnection(_brokerFailoverUrl); - fail("Connection not expected"); - } - catch (JMSException e) - { - // PASS - } - } - - public void testInitialDesignatedPrimaryStateOfNodes() throws Exception - { - startCluster(true); - final ManagedBDBHAMessageStore primaryStoreBean = getStoreBeanForNodeAtBrokerPort(_clusterCreator.getBrokerPortNumberOfPrimary()); - assertTrue("Expected primary node to be set as designated primary", primaryStoreBean.getDesignatedPrimary()); - - final ManagedBDBHAMessageStore secondaryStoreBean = getStoreBeanForNodeAtBrokerPort(_clusterCreator.getBrokerPortNumberOfSecondaryNode()); - assertFalse("Expected secondary node to NOT be set as designated primary", secondaryStoreBean.getDesignatedPrimary()); - } - - public void testSecondaryDesignatedAsPrimaryAfterOriginalPrimaryStopped() throws Exception - { - startCluster(true); - final ManagedBDBHAMessageStore storeBean = getStoreBeanForNodeAtBrokerPort(_clusterCreator.getBrokerPortNumberOfSecondaryNode()); - _clusterCreator.stopNode(_clusterCreator.getBrokerPortNumberOfPrimary()); - - assertFalse("Expected node to NOT be set as designated primary", storeBean.getDesignatedPrimary()); - storeBean.setDesignatedPrimary(true); - - long limit = System.currentTimeMillis() + 5000; - while( !storeBean.getDesignatedPrimary() && System.currentTimeMillis() < limit) - { - Thread.sleep(100); - } - assertTrue("Expected node to now be set as designated primary", storeBean.getDesignatedPrimary()); - - final Connection connection = getConnection(_brokerFailoverUrl); - assertNotNull("Expected to get a valid connection to new primary", connection); - assertProducingConsuming(connection); - } - - private ManagedBDBHAMessageStore getStoreBeanForNodeAtBrokerPort( - final int activeBrokerPortNumber) throws Exception - { - _jmxUtils.open(activeBrokerPortNumber); - - ManagedBDBHAMessageStore storeBean = _jmxUtils.getManagedObject(ManagedBDBHAMessageStore.class, MANAGED_OBJECT_QUERY); - return storeBean; - } - -} diff --git a/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HAClusterWhiteboxTest.java b/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HAClusterWhiteboxTest.java deleted file mode 100644 index ef5cc7c464..0000000000 --- a/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HAClusterWhiteboxTest.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.store.berkeleydb; - -import java.io.File; -import java.util.Set; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.Queue; -import javax.jms.Session; - -import org.apache.log4j.Logger; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.url.URLSyntaxException; - -/** - * The HA white box tests test the BDB cluster where the test retains the knowledge of the - * individual test nodes. It uses this knowledge to examine the nodes to ensure that they - * remain in the correct state throughout the test. - * - * @see HAClusterBlackboxTest - */ -public class HAClusterWhiteboxTest extends QpidBrokerTestCase -{ - protected static final Logger LOGGER = Logger.getLogger(HAClusterWhiteboxTest.class); - - private static final String VIRTUAL_HOST = "test"; - - private final int NUMBER_OF_NODES = 3; - private final HATestClusterCreator _clusterCreator = new HATestClusterCreator(this, VIRTUAL_HOST, NUMBER_OF_NODES); - - @Override - protected void setUp() throws Exception - { - _brokerType = BrokerType.SPAWNED; - - assertTrue(isJavaBroker()); - assertTrue(isBrokerStorePersistent()); - - setSystemProperty("java.util.logging.config.file", "etc" + File.separator + "log.properties"); - - _clusterCreator.configureClusterNodes(); - _clusterCreator.startCluster(); - - super.setUp(); - } - - @Override - public void startBroker() throws Exception - { - // Don't start default broker provided by QBTC. - } - - public void testClusterPermitsConnectionToOnlyOneNode() throws Exception - { - int connectionSuccesses = 0; - int connectionFails = 0; - - for (int brokerPortNumber : getBrokerPortNumbers()) - { - try - { - getConnection(_clusterCreator.getConnectionUrlForSingleNodeWithoutRetry(brokerPortNumber)); - connectionSuccesses++; - } - catch(JMSException e) - { - assertTrue(e.getMessage().contains("Virtual host '" + VIRTUAL_HOST + "' is not active")); - connectionFails++; - } - } - - assertEquals("Unexpected number of failed connections", NUMBER_OF_NODES - 1, connectionFails); - assertEquals("Unexpected number of successful connections", 1, connectionSuccesses); - } - - public void testClusterThatLosesNodeStillAllowsConnection() throws Exception - { - final Connection initialConnection = getConnectionToNodeInCluster(); - assertNotNull(initialConnection); - - closeConnectionAndKillBroker(initialConnection); - - final Connection subsequentConnection = getConnectionToNodeInCluster(); - assertNotNull(subsequentConnection); - - // verify that JMS persistence operations are working - assertProducingConsuming(subsequentConnection); - - closeConnection(initialConnection); - } - - public void testClusterThatLosesAllButOneNodeRefusesConnection() throws Exception - { - final Connection initialConnection = getConnectionToNodeInCluster(); - assertNotNull(initialConnection); - - closeConnectionAndKillBroker(initialConnection); - - final Connection subsequentConnection = getConnectionToNodeInCluster(); - assertNotNull(subsequentConnection); - final int subsequentPortNumber = _clusterCreator.getBrokerPortNumberFromConnection(subsequentConnection); - - killBroker(subsequentPortNumber); - - final Connection finalConnection = getConnectionToNodeInCluster(); - assertNull(finalConnection); - - closeConnection(initialConnection); - } - - public void testClusterWithRestartedNodeStillAllowsConnection() throws Exception - { - final Connection connection = getConnectionToNodeInCluster(); - assertNotNull(connection); - - final int brokerPortNumber = _clusterCreator.getBrokerPortNumberFromConnection(connection); - connection.close(); - - _clusterCreator.stopNode(brokerPortNumber); - _clusterCreator.startNode(brokerPortNumber); - - final Connection subsequentConnection = getConnectionToNodeInCluster(); - assertNotNull(subsequentConnection); - } - - public void testClusterLosingNodeRetainsData() throws Exception - { - final Connection initialConnection = getConnectionToNodeInCluster(); - - final String queueNamePrefix = getTestQueueName(); - final String inbuiltExchangeQueueUrl = "direct://amq.direct/" + queueNamePrefix + "1/" + queueNamePrefix + "1?durable='true'"; - final String customExchangeQueueUrl = "direct://my.exchange/" + queueNamePrefix + "2/" + queueNamePrefix + "2?durable='true'"; - - populateBrokerWithData(initialConnection, inbuiltExchangeQueueUrl, customExchangeQueueUrl); - - closeConnectionAndKillBroker(initialConnection); - - final Connection subsequentConnection = getConnectionToNodeInCluster(); - - assertNotNull("no valid connection obtained", subsequentConnection); - - checkBrokerData(subsequentConnection, inbuiltExchangeQueueUrl, customExchangeQueueUrl); - } - - public void xtestRecoveryOfOutOfDateNode() throws Exception - { - /* - * TODO: Implement - * - * Cant yet find a way to control cleaning in a deterministic way to allow provoking - * a node to become out of date. We do now know that even a new joiner to the group - * can throw the InsufficientLogException, so ensuring an existing cluster of nodes has - * done *any* cleaning and then adding a new node should be sufficient to cause this. - */ - } - - private void populateBrokerWithData(final Connection connection, final String... queueUrls) throws JMSException, Exception - { - populateBrokerWithData(connection, 1, queueUrls); - } - - private void populateBrokerWithData(final Connection connection, int noOfMessages, final String... queueUrls) throws JMSException, Exception - { - final Session session = connection.createSession(true, Session.SESSION_TRANSACTED); - for (final String queueUrl : queueUrls) - { - final Queue queue = session.createQueue(queueUrl); - session.createConsumer(queue).close(); - sendMessage(session, queue, noOfMessages); - } - } - - private void checkBrokerData(final Connection connection, final String... queueUrls) throws JMSException - { - connection.start(); - final Session session = connection.createSession(true, Session.SESSION_TRANSACTED); - for (final String queueUrl : queueUrls) - { - final Queue queue = session.createQueue(queueUrl); - final MessageConsumer consumer = session.createConsumer(queue); - final Message message = consumer.receive(1000); - session.commit(); - assertNotNull("Queue " + queue + " should have message", message); - assertEquals("Queue " + queue + " message has unexpected content", 0, message.getIntProperty(INDEX)); - } - } - - private Connection getConnectionToNodeInCluster() throws URLSyntaxException - { - Connection connection = null; - Set runningBrokerPorts = getBrokerPortNumbers(); - - for (int brokerPortNumber : runningBrokerPorts) - { - try - { - connection = getConnection(_clusterCreator.getConnectionUrlForSingleNodeWithRetry(brokerPortNumber)); - break; - } - catch(JMSException je) - { - assertTrue(je.getMessage().contains("Virtual host '" + VIRTUAL_HOST + "' is not active")); - } - } - return connection; - } - - private void closeConnectionAndKillBroker(final Connection initialConnection) throws Exception - { - final int initialPortNumber = _clusterCreator.getBrokerPortNumberFromConnection(initialConnection); - initialConnection.close(); - - killBroker(initialPortNumber); // kill awaits the death of the child - } - - private void closeConnection(final Connection initialConnection) - { - try - { - initialConnection.close(); - } - catch(Exception e) - { - // ignore. - // java.net.SocketException is seen sometimes on active connection - } - } -} diff --git a/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HATestClusterCreator.java b/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HATestClusterCreator.java deleted file mode 100644 index ebc32b482a..0000000000 --- a/qpid/java/bdbstore/systests/src/main/java/org/apache/qpid/server/store/berkeleydb/HATestClusterCreator.java +++ /dev/null @@ -1,529 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.store.berkeleydb; - -import java.io.File; -import java.io.IOException; -import java.io.StringWriter; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.concurrent.Callable; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import javax.jms.Connection; - -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQConnectionURL; -import org.apache.qpid.server.management.plugin.HttpManagement; -import org.apache.qpid.server.model.Plugin; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.VirtualHost; -import org.apache.qpid.server.model.VirtualHostNode; -import org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHost; -import org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHostImpl; -import org.apache.qpid.server.virtualhostnode.AbstractVirtualHostNode; -import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHARemoteReplicationNode; -import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHAVirtualHostNode; -import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHAVirtualHostNodeImpl; -import org.apache.qpid.systest.rest.RestTestHelper; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.url.URLSyntaxException; -import org.codehaus.jackson.map.ObjectMapper; -import org.codehaus.jackson.map.SerializationConfig; -import org.junit.Assert; - -import com.sleepycat.je.rep.ReplicationConfig; - -public class HATestClusterCreator -{ - protected static final Logger LOGGER = Logger.getLogger(HATestClusterCreator.class); - - private static final String MANY_BROKER_URL_FORMAT = "amqp://guest:guest@/%s?brokerlist='%s'&failover='roundrobin?cyclecount='%d''"; - private static final String BROKER_PORTION_FORMAT = "tcp://localhost:%d?connectdelay='%d',retries='%d'"; - - private static final int FAILOVER_CYCLECOUNT = 10; - private static final int FAILOVER_RETRIES = 1; - private static final int FAILOVER_CONNECTDELAY = 1000; - - private static final String SINGLE_BROKER_URL_WITH_RETRY_FORMAT = "amqp://guest:guest@/%s?brokerlist='tcp://localhost:%d?connectdelay='%d',retries='%d''"; - private static final String SINGLE_BROKER_URL_WITHOUT_RETRY_FORMAT = "amqp://guest:guest@/%s?brokerlist='tcp://localhost:%d'"; - - private static final int RETRIES = 60; - private static final int CONNECTDELAY = 75; - - private final QpidBrokerTestCase _testcase; - private final Map _brokerPortToBdbPortMap = new TreeMap(); - private final String _virtualHostName; - - private final String _ipAddressOfBroker; - private final String _groupName ; - private final int _numberOfNodes; - private int _bdbHelperPort; - private int _primaryBrokerPort; - - public HATestClusterCreator(QpidBrokerTestCase testcase, String virtualHostName, int numberOfNodes) - { - _testcase = testcase; - _virtualHostName = virtualHostName; - _groupName = virtualHostName; - _ipAddressOfBroker = getIpAddressOfBrokerHost(); - _numberOfNodes = numberOfNodes; - _bdbHelperPort = 0; - } - - public void configureClusterNodes() throws Exception - { - int brokerPort = _testcase.findFreePort(); - - int[] bdbPorts = new int[_numberOfNodes]; - for (int i = 0; i < _numberOfNodes; i++) - { - int bdbPort = _testcase.getNextAvailable(brokerPort + 1); - bdbPorts[i] = bdbPort; - _brokerPortToBdbPortMap.put(brokerPort, bdbPort); - brokerPort = _testcase.getNextAvailable(bdbPort + 1); - } - - String bluePrintJson = getBlueprint(_ipAddressOfBroker, bdbPorts); - - String helperName = null; - for (Map.Entry entry: _brokerPortToBdbPortMap.entrySet()) - { - brokerPort = entry.getKey(); - int bdbPort = entry.getValue(); - LOGGER.debug("Cluster broker port " + brokerPort + ", bdb replication port " + bdbPort); - if (_bdbHelperPort == 0) - { - _bdbHelperPort = bdbPort; - } - - String nodeName = getNodeNameForNodeAt(bdbPort); - if (helperName == null) - { - helperName = nodeName; - } - - Map virtualHostNodeAttributes = new HashMap(); - virtualHostNodeAttributes.put(BDBHAVirtualHostNode.STORE_PATH, System.getProperty("QPID_WORK") + File.separator + brokerPort); - virtualHostNodeAttributes.put(BDBHAVirtualHostNode.GROUP_NAME, _groupName); - virtualHostNodeAttributes.put(BDBHAVirtualHostNode.NAME, nodeName); - virtualHostNodeAttributes.put(BDBHAVirtualHostNode.ADDRESS, getNodeHostPortForNodeAt(bdbPort)); - virtualHostNodeAttributes.put(BDBHAVirtualHostNode.HELPER_ADDRESS, getHelperHostPort()); - virtualHostNodeAttributes.put(BDBHAVirtualHostNode.TYPE, BDBHAVirtualHostNodeImpl.VIRTUAL_HOST_NODE_TYPE); - virtualHostNodeAttributes.put(BDBHAVirtualHostNode.HELPER_NODE_NAME, helperName); - - Map context = new HashMap<>(); - context.put(ReplicationConfig.INSUFFICIENT_REPLICAS_TIMEOUT, "2 s"); - context.put(ReplicationConfig.ELECTIONS_PRIMARY_RETRIES, "0"); - context.put(AbstractVirtualHostNode.VIRTUALHOST_BLUEPRINT_CONTEXT_VAR, bluePrintJson); - virtualHostNodeAttributes.put(BDBHAVirtualHostNode.CONTEXT, context); - - TestBrokerConfiguration brokerConfiguration = _testcase.getBrokerConfiguration(brokerPort); - brokerConfiguration.addJmxManagementConfiguration(); - brokerConfiguration.addHttpManagementConfiguration(); - brokerConfiguration.setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); - brokerConfiguration.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.PORT, _testcase.getHttpManagementPort(brokerPort)); - brokerConfiguration.setObjectAttributes(VirtualHostNode.class, _virtualHostName, virtualHostNodeAttributes); - - } - _primaryBrokerPort = getPrimaryBrokerPort(); - } - - public void setDesignatedPrimaryOnFirstBroker(boolean designatedPrimary) throws Exception - { - if (_numberOfNodes != 2) - { - throw new IllegalArgumentException("Only two nodes groups have the concept of primary"); - } - TestBrokerConfiguration config = _testcase.getBrokerConfiguration(_primaryBrokerPort); - String nodeName = getNodeNameForNodeAt(_brokerPortToBdbPortMap.get(_primaryBrokerPort)); - config.setObjectAttribute(VirtualHostNode.class, nodeName, BDBHAVirtualHostNode.DESIGNATED_PRIMARY, designatedPrimary); - config.setSaved(false); - } - - private int getPrimaryBrokerPort() - { - return _brokerPortToBdbPortMap.keySet().iterator().next(); - } - - public void startNode(final int brokerPortNumber) throws Exception - { - _testcase.startBroker(brokerPortNumber); - } - - public void startCluster() throws Exception - { - for (final Integer brokerPortNumber : _brokerPortToBdbPortMap.keySet()) - { - startNode(brokerPortNumber); - } - } - - public void startClusterParallel() throws Exception - { - final ExecutorService executor = Executors.newFixedThreadPool(_brokerPortToBdbPortMap.size()); - try - { - List> brokers = new CopyOnWriteArrayList>(); - for (final Integer brokerPortNumber : _brokerPortToBdbPortMap.keySet()) - { - final TestBrokerConfiguration brokerConfig = _testcase.getBrokerConfiguration(brokerPortNumber); - Future future = executor.submit(new Callable() - { - public Object call() - { - try - { - _testcase.startBroker(brokerPortNumber, brokerConfig); - return "OK"; - } - catch (Exception e) - { - return e; - } - } - }); - brokers.add(future); - } - for (Future future : brokers) - { - Object result = future.get(30, TimeUnit.SECONDS); - LOGGER.debug("Node startup result:" + result); - if (result instanceof Exception) - { - throw (Exception) result; - } - else if (!"OK".equals(result)) - { - throw new Exception("One of the cluster nodes is not started"); - } - } - } - catch (Exception e) - { - stopCluster(); - throw e; - } - finally - { - executor.shutdown(); - } - - } - - public void stopNode(final int brokerPortNumber) - { - _testcase.killBroker(brokerPortNumber); - } - - public void stopCluster() throws Exception - { - for (final Integer brokerPortNumber : _brokerPortToBdbPortMap.keySet()) - { - try - { - stopNode(brokerPortNumber); - } - catch(Exception e) - { - LOGGER.warn("Failed to stop node on port:" + brokerPortNumber); - } - } - } - - public int getBrokerPortNumberFromConnection(Connection connection) - { - final AMQConnection amqConnection = (AMQConnection)connection; - return amqConnection.getActiveBrokerDetails().getPort(); - } - - public int getPortNumberOfAnInactiveBroker(final Connection activeConnection) - { - final Set allBrokerPorts = _testcase.getBrokerPortNumbers(); - LOGGER.debug("Broker ports:" + allBrokerPorts); - final int activeBrokerPort = getBrokerPortNumberFromConnection(activeConnection); - allBrokerPorts.remove(activeBrokerPort); - LOGGER.debug("Broker ports:" + allBrokerPorts); - final int inactiveBrokerPort = allBrokerPorts.iterator().next(); - return inactiveBrokerPort; - } - - public int getBdbPortForBrokerPort(final int brokerPortNumber) - { - return _brokerPortToBdbPortMap.get(brokerPortNumber); - } - - public Set getBdbPortNumbers() - { - return new HashSet(_brokerPortToBdbPortMap.values()); - } - - public AMQConnectionURL getConnectionUrlForAllClusterNodes() throws Exception - { - final StringBuilder brokerList = new StringBuilder(); - - for(Iterator itr = _brokerPortToBdbPortMap.keySet().iterator(); itr.hasNext(); ) - { - int brokerPortNumber = itr.next(); - - brokerList.append(String.format(BROKER_PORTION_FORMAT, brokerPortNumber, FAILOVER_CONNECTDELAY, FAILOVER_RETRIES)); - if (itr.hasNext()) - { - brokerList.append(";"); - } - } - - return new AMQConnectionURL(String.format(MANY_BROKER_URL_FORMAT, _virtualHostName, brokerList, FAILOVER_CYCLECOUNT)); - } - - public AMQConnectionURL getConnectionUrlForSingleNodeWithoutRetry(final int brokerPortNumber) throws URLSyntaxException - { - return getConnectionUrlForSingleNode(brokerPortNumber, false); - } - - public AMQConnectionURL getConnectionUrlForSingleNodeWithRetry(final int brokerPortNumber) throws URLSyntaxException - { - return getConnectionUrlForSingleNode(brokerPortNumber, true); - } - - private AMQConnectionURL getConnectionUrlForSingleNode(final int brokerPortNumber, boolean retryAllowed) throws URLSyntaxException - { - final String url; - if (retryAllowed) - { - url = String.format(SINGLE_BROKER_URL_WITH_RETRY_FORMAT, _virtualHostName, brokerPortNumber, CONNECTDELAY, RETRIES); - } - else - { - url = String.format(SINGLE_BROKER_URL_WITHOUT_RETRY_FORMAT, _virtualHostName, brokerPortNumber); - } - - return new AMQConnectionURL(url); - } - - public String getGroupName() - { - return _groupName; - } - - public String getNodeNameForNodeAt(final int bdbPort) - { - return "node" + _testcase.getName() + bdbPort; - } - - public String getNodeHostPortForNodeAt(final int bdbPort) - { - return _ipAddressOfBroker + ":" + bdbPort; - } - - public String getHelperHostPort() - { - if (_bdbHelperPort == 0) - { - throw new IllegalStateException("Helper port not yet assigned."); - } - - return _ipAddressOfBroker + ":" + _bdbHelperPort; - } - - public void setHelperHostPort(int bdbHelperPort) - { - _bdbHelperPort = bdbHelperPort; - } - - public int getBrokerPortNumberOfPrimary() - { - if (_numberOfNodes != 2) - { - throw new IllegalArgumentException("Only two nodes groups have the concept of primary"); - } - - return _primaryBrokerPort; - } - - public int getBrokerPortNumberOfSecondaryNode() - { - final Set portNumbers = getBrokerPortNumbersForNodes(); - portNumbers.remove(getBrokerPortNumberOfPrimary()); - return portNumbers.iterator().next(); - } - - public Set getBrokerPortNumbersForNodes() - { - return new HashSet(_brokerPortToBdbPortMap.keySet()); - } - - - public String getIpAddressOfBrokerHost() - { - String brokerHost = _testcase.getBroker().getHost(); - try - { - return InetAddress.getByName(brokerHost).getHostAddress(); - } - catch (UnknownHostException e) - { - throw new RuntimeException("Could not determine IP address of host : " + brokerHost, e); - } - } - - public void modifyClusterNodeBdbAddress(int brokerPortNumberToBeMoved, int newBdbPort) - { - TestBrokerConfiguration config = _testcase.getBrokerConfiguration(brokerPortNumberToBeMoved); - String nodeName = getNodeNameForNodeAt(_brokerPortToBdbPortMap.get(brokerPortNumberToBeMoved)); - - Map objectAttributes = config.getObjectAttributes(VirtualHostNode.class, nodeName); - - String oldBdbHostPort = (String)objectAttributes.get(BDBHAVirtualHostNode.ADDRESS); - String[] oldHostAndPort = StringUtils.split(oldBdbHostPort, ":"); - String oldHost = oldHostAndPort[0]; - String newBdbHostPort = oldHost + ":" + newBdbPort; - config.setObjectAttribute(VirtualHostNode.class, nodeName, BDBHAVirtualHostNode.ADDRESS, newBdbHostPort); - config.setSaved(false); - } - - public String getNodeNameForBrokerPort(final int brokerPort) - { - return getNodeNameForNodeAt(_brokerPortToBdbPortMap.get(brokerPort)); - } - - public void setNodeAttributes(int brokerPort, Map attributeMap) - throws Exception - { - setNodeAttributes(brokerPort, brokerPort, attributeMap); - } - - public void setNodeAttributes(int localNodePort, int remoteNodePort, Map attributeMap) - throws Exception - { - RestTestHelper restHelper = createRestTestHelper(localNodePort); - String url = getNodeRestUrl(localNodePort, remoteNodePort); - int status = restHelper.submitRequest(url, "PUT", attributeMap); - if (status != 200) - { - throw new Exception("Unexpected http status when updating " + getNodeNameForBrokerPort(remoteNodePort) + " attribute's : " + status); - } - } - - private String getNodeRestUrl(int localNodePort, int remoteNodePort) - { - String remoteNodeName = getNodeNameForBrokerPort(remoteNodePort); - String localNodeName = getNodeNameForBrokerPort(localNodePort); - String url = null; - if (localNodePort == remoteNodePort) - { - url = "/api/latest/virtualhostnode/" + localNodeName; - } - else - { - url = "/api/latest/replicationnode/" + localNodeName + "/" + remoteNodeName; - } - return url; - } - - public Map getNodeAttributes(int brokerPort) throws IOException - { - return getNodeAttributes(brokerPort, brokerPort); - } - - public Map getNodeAttributes(int localNodePort, int remoteNodePort) throws IOException - { - RestTestHelper restHelper = createRestTestHelper(localNodePort); - List> results= restHelper.getJsonAsList(getNodeRestUrl(localNodePort, remoteNodePort)); - int size = results.size(); - if (size == 0) - { - return Collections.emptyMap(); - } - else if (size == 1) - { - return results.get(0); - } - else - { - throw new RuntimeException("Unexpected number of nodes " + size); - } - } - - public void awaitNodeToAttainRole(int brokerPort, String desiredRole) throws Exception - { - awaitNodeToAttainRole(brokerPort, brokerPort, desiredRole); - } - - public void awaitNodeToAttainRole(int localNodePort, int remoteNodePort, String desiredRole) throws Exception - { - final long startTime = System.currentTimeMillis(); - Map data = Collections.emptyMap(); - - while(!desiredRole.equals(data.get(BDBHARemoteReplicationNode.ROLE)) && (System.currentTimeMillis() - startTime) < 30000) - { - LOGGER.debug("Awaiting node '" + getNodeNameForBrokerPort(remoteNodePort) + "' to transit into " + desiredRole + " role"); - data = getNodeAttributes(localNodePort, remoteNodePort); - if (!desiredRole.equals(data.get(BDBHARemoteReplicationNode.ROLE))) - { - Thread.sleep(1000); - } - } - LOGGER.debug("Node '" + getNodeNameForBrokerPort(remoteNodePort) + "' role is " + data.get(BDBHARemoteReplicationNode.ROLE)); - Assert.assertEquals("Node is in unexpected role", desiredRole, data.get(BDBHARemoteReplicationNode.ROLE)); - } - - public RestTestHelper createRestTestHelper(int brokerPort) - { - int httpPort = _testcase.getHttpManagementPort(brokerPort); - RestTestHelper helper = new RestTestHelper(httpPort); - helper.setUsernameAndPassword("webadmin", "webadmin"); - return helper; - } - - public static String getBlueprint(String hostName, int... ports) throws Exception - { - List permittedNodes = new ArrayList(); - for (int port:ports) - { - permittedNodes.add(hostName + ":" + port); - } - Map bluePrint = new HashMap<>(); - bluePrint.put(VirtualHost.TYPE, BDBHAVirtualHostImpl.VIRTUAL_HOST_TYPE); - bluePrint.put(BDBHAVirtualHost.PERMITTED_NODES, permittedNodes); - - StringWriter writer = new StringWriter(); - ObjectMapper mapper = new ObjectMapper(); - mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); - mapper.writeValue(writer, bluePrint); - return writer.toString(); - } -} diff --git a/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBBackupTest.java b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBBackupTest.java new file mode 100644 index 0000000000..fab889a49f --- /dev/null +++ b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBBackupTest.java @@ -0,0 +1,194 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.store.berkeleydb; + +import java.io.File; +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +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 org.apache.log4j.Logger; +import org.apache.qpid.server.model.VirtualHostNode; +import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBVirtualHostNode; +import org.apache.qpid.test.utils.Piper; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.util.FileUtils; +import org.apache.qpid.util.Strings; +import org.apache.qpid.util.SystemUtils; + +/** + * Tests the BDB backup script can successfully perform a backup and that + * backup can be restored and used by the Broker. + */ +public class BDBBackupTest extends QpidBrokerTestCase +{ + protected static final Logger LOGGER = Logger.getLogger(BDBBackupTest.class); + + private static final String BACKUP_SCRIPT = "/bin/backup.sh"; + private static final String BACKUP_COMPLETE_MESSAGE = "Hot Backup Completed"; + + private static final String TEST_VHOST = "test"; + private static final String SYSTEM_TMP_DIR = System.getProperty("java.io.tmpdir"); + + private File _backupToDir; + private File _backupFromDir; + + @Override + protected void setUp() throws Exception + { + super.setUp(); + _backupToDir = new File(SYSTEM_TMP_DIR + File.separator + getTestName()); + _backupToDir.mkdirs(); + + Map virtualHostNodeAttributes = getBrokerConfiguration().getObjectAttributes(VirtualHostNode.class, TEST_VHOST); + _backupFromDir = new File(Strings.expand((String) virtualHostNodeAttributes.get(BDBVirtualHostNode.STORE_PATH))); + boolean fromDirExistsAndIsDir = _backupFromDir.isDirectory(); + assertTrue("backupFromDir " + _backupFromDir + " should already exist", fromDirExistsAndIsDir); + } + + @Override + protected void tearDown() throws Exception + { + try + { + super.tearDown(); + } + finally + { + FileUtils.delete(_backupToDir, true); + } + } + + public void testBackupAndRestoreMaintainsMessages() throws Exception + { + sendNumberedMessages(0, 10); + invokeBdbBackup(_backupFromDir, _backupToDir); + sendNumberedMessages(10, 20); + confirmBrokerHasMessages(0, 20); + stopBroker(); + + deleteStore(_backupFromDir); + replaceStoreWithBackup(_backupToDir, _backupFromDir); + + startBroker(); + confirmBrokerHasMessages(0, 10); + } + + private void sendNumberedMessages(final int startIndex, final int endIndex) throws JMSException, Exception + { + Connection con = getConnection(); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(getTestQueueName()); + // Create queue by consumer side-effect + session.createConsumer(destination).close(); + + final int numOfMessages = endIndex - startIndex; + final int batchSize = 0; + sendMessage(session, destination, numOfMessages, startIndex, batchSize); + con.close(); + } + + private void confirmBrokerHasMessages(final int startIndex, final int endIndex) throws Exception + { + Connection con = getConnection(); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + con.start(); + Destination destination = session.createQueue(getTestQueueName()); + MessageConsumer consumer = session.createConsumer(destination); + for (int i = startIndex; i < endIndex; i++) + { + Message msg = consumer.receive(RECEIVE_TIMEOUT); + assertNotNull("Message " + i + " not received", msg); + assertEquals("Did not receive the expected message", i, msg.getIntProperty(INDEX)); + } + + Message msg = consumer.receive(100); + if(msg != null) + { + fail("No more messages should be received, but received additional message with index: " + msg.getIntProperty(INDEX)); + } + con.close(); + } + + private void invokeBdbBackup(final File backupFromDir, final File backupToDir) throws Exception + { + if (SystemUtils.isWindows()) + { + BDBBackup.main(new String[]{"-todir", backupToDir.getAbsolutePath(), "-fromdir", backupFromDir.getAbsolutePath()}); + } + else + { + runBdbBackupScript(backupFromDir, backupToDir); + } + } + + private void runBdbBackupScript(final File backupFromDir, final File backupToDir) throws IOException, + InterruptedException + { + Process backupProcess = null; + try + { + String qpidHome = System.getProperty(QPID_HOME); + ProcessBuilder pb = new ProcessBuilder(qpidHome + BACKUP_SCRIPT, "-todir", backupToDir.getAbsolutePath(), "-fromdir", backupFromDir.getAbsolutePath()); + pb.redirectErrorStream(true); + Map env = pb.environment(); + env.put(QPID_HOME, qpidHome); + + LOGGER.debug("Backup command is " + pb.command()); + backupProcess = pb.start(); + Piper piper = new Piper(backupProcess.getInputStream(), _testcaseOutputStream, null, BACKUP_COMPLETE_MESSAGE); + piper.start(); + piper.await(2, TimeUnit.SECONDS); + backupProcess.waitFor(); + piper.join(); + + LOGGER.debug("Backup command completed " + backupProcess.exitValue()); + assertEquals("Unexpected exit value from backup script", 0, backupProcess.exitValue()); + } + finally + { + if (backupProcess != null) + { + backupProcess.getErrorStream().close(); + backupProcess.getInputStream().close(); + backupProcess.getOutputStream().close(); + } + } + } + + private void replaceStoreWithBackup(File source, File dst) throws Exception + { + LOGGER.debug("Copying store " + source + " to " + dst); + FileUtils.copyRecursive(source, dst); + } + + private void deleteStore(File storeDir) + { + LOGGER.debug("Deleting store " + storeDir); + FileUtils.delete(storeDir, true); + } + +} diff --git a/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java new file mode 100644 index 0000000000..491856d953 --- /dev/null +++ b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java @@ -0,0 +1,548 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store.berkeleydb; + +import java.io.File; +import java.io.InputStream; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.jms.TopicConnection; +import javax.jms.TopicPublisher; +import javax.jms.TopicSession; +import javax.jms.TopicSubscriber; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularDataSupport; + +import org.apache.qpid.management.common.mbeans.ManagedExchange; +import org.apache.qpid.management.common.mbeans.ManagedQueue; +import org.apache.qpid.server.model.VirtualHostNode; +import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBVirtualHostNode; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.util.FileUtils; +import org.apache.qpid.util.Strings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Tests upgrading a BDB store on broker startup. + * The store will then be used to verify that the upgrade is completed + * properly and that once upgraded it functions as expected. + * + * Store prepared using old client/broker with BDBStoreUpgradeTestPreparer. + */ +public class BDBUpgradeTest extends QpidBrokerTestCase +{ + protected static final Logger _logger = LoggerFactory.getLogger(BDBUpgradeTest.class); + + private static final String QPID_WORK_ORIG = System.getProperty("QPID_WORK"); + + private static final String STRING_1024 = generateString(1024); + private static final String STRING_1024_256 = generateString(1024*256); + + private static final String TOPIC_NAME="myUpgradeTopic"; + private static final String SUB_NAME="myDurSubName"; + private static final String SELECTOR_SUB_NAME="mySelectorDurSubName"; + private static final String SELECTOR_TOPIC_NAME="mySelectorUpgradeTopic"; + private static final String QUEUE_NAME="myUpgradeQueue"; + private static final String NON_DURABLE_QUEUE_NAME="queue-non-durable"; + private static final String PRIORITY_QUEUE_NAME="myPriorityQueue"; + private static final String QUEUE_WITH_DLQ_NAME="myQueueWithDLQ"; + + private String _storeLocation; + + @Override + public void setUp() throws Exception + { + assertNotNull("QPID_WORK must be set", QPID_WORK_ORIG); + Map virtualHostNodeAttributes = getBrokerConfiguration().getObjectAttributes(VirtualHostNode.class, TestBrokerConfiguration.ENTRY_NAME_VIRTUAL_HOST); + _storeLocation = Strings.expand((String)virtualHostNodeAttributes.get(BDBVirtualHostNode.STORE_PATH)); + + //Clear the two target directories if they exist. + File directory = new File(_storeLocation); + if (directory.exists() && directory.isDirectory()) + { + FileUtils.delete(directory, true); + } + directory.mkdirs(); + + // copy store files + InputStream src = getClass().getClassLoader().getResourceAsStream("upgrade/bdbstore-v4/test-store/00000000.jdb"); + FileUtils.copy(src, new File(_storeLocation, "00000000.jdb")); + + getBrokerConfiguration().addJmxManagementConfiguration(); + super.setUp(); + } + + /** + * Test that the selector applied to the DurableSubscription was successfully + * transfered to the new store, and functions as expected with continued use + * by monitoring message count while sending new messages to the topic and then + * consuming them. + */ + public void testSelectorDurability() throws Exception + { + JMXTestUtils jmxUtils = null; + try + { + jmxUtils = new JMXTestUtils(this, "guest", "guest"); + jmxUtils.open(); + } + catch (Exception e) + { + fail("Unable to establish JMX connection, test cannot proceed"); + } + + try + { + ManagedQueue dursubQueue = jmxUtils.getManagedQueue("clientid" + ":" + SELECTOR_SUB_NAME); + assertEquals("DurableSubscription backing queue should have 1 message on it initially", + new Integer(1), dursubQueue.getMessageCount()); + + // Create a connection and start it + TopicConnection connection = (TopicConnection) getConnection(); + connection.start(); + + // Send messages which don't match and do match the selector, checking message count + TopicSession pubSession = connection.createTopicSession(true, Session.SESSION_TRANSACTED); + Topic topic = pubSession.createTopic(SELECTOR_TOPIC_NAME); + TopicPublisher publisher = pubSession.createPublisher(topic); + + publishMessages(pubSession, publisher, topic, DeliveryMode.PERSISTENT, 1*1024, 1, "false"); + pubSession.commit(); + assertEquals("DurableSubscription backing queue should still have 1 message on it", + Integer.valueOf(1), dursubQueue.getMessageCount()); + + publishMessages(pubSession, publisher, topic, DeliveryMode.PERSISTENT, 1*1024, 1, "true"); + pubSession.commit(); + assertEquals("DurableSubscription backing queue should now have 2 messages on it", + Integer.valueOf(2), dursubQueue.getMessageCount()); + + TopicSubscriber durSub = pubSession.createDurableSubscriber(topic, SELECTOR_SUB_NAME,"testprop='true'", false); + Message m = durSub.receive(2000); + assertNotNull("Failed to receive an expected message", m); + m = durSub.receive(2000); + assertNotNull("Failed to receive an expected message", m); + pubSession.commit(); + + pubSession.close(); + } + finally + { + jmxUtils.close(); + } + } + + /** + * Test that the DurableSubscription without selector was successfully + * transfered to the new store, and functions as expected with continued use. + */ + public void testDurableSubscriptionWithoutSelector() throws Exception + { + JMXTestUtils jmxUtils = null; + try + { + jmxUtils = new JMXTestUtils(this, "guest", "guest"); + jmxUtils.open(); + } + catch (Exception e) + { + fail("Unable to establish JMX connection, test cannot proceed"); + } + + try + { + ManagedQueue dursubQueue = jmxUtils.getManagedQueue("clientid" + ":" + SUB_NAME); + assertEquals("DurableSubscription backing queue should have 1 message on it initially", + new Integer(1), dursubQueue.getMessageCount()); + + // Create a connection and start it + TopicConnection connection = (TopicConnection) getConnection(); + connection.start(); + + // Send new message matching the topic, checking message count + TopicSession session = connection.createTopicSession(true, Session.SESSION_TRANSACTED); + Topic topic = session.createTopic(TOPIC_NAME); + TopicPublisher publisher = session.createPublisher(topic); + + publishMessages(session, publisher, topic, DeliveryMode.PERSISTENT, 1*1024, 1, "indifferent"); + session.commit(); + assertEquals("DurableSubscription backing queue should now have 2 messages on it", + Integer.valueOf(2), dursubQueue.getMessageCount()); + + TopicSubscriber durSub = session.createDurableSubscriber(topic, SUB_NAME); + Message m = durSub.receive(2000); + assertNotNull("Failed to receive an expected message", m); + m = durSub.receive(2000); + assertNotNull("Failed to receive an expected message", m); + + session.commit(); + session.close(); + } + finally + { + jmxUtils.close(); + } + } + + /** + * Test that the backing queue for the durable subscription created was successfully + * detected and set as being exclusive during the upgrade process, and that the + * regular queue was not. + */ + public void testQueueExclusivity() throws Exception + { + JMXTestUtils jmxUtils = null; + try + { + jmxUtils = new JMXTestUtils(this, "guest", "guest"); + jmxUtils.open(); + } + catch (Exception e) + { + fail("Unable to establish JMX connection, test cannot proceed"); + } + + try + { + ManagedQueue queue = jmxUtils.getManagedQueue(QUEUE_NAME); + assertFalse("Queue should not have been marked as Exclusive during upgrade", queue.isExclusive()); + + ManagedQueue dursubQueue = jmxUtils.getManagedQueue("clientid" + ":" + SUB_NAME); + assertTrue("DurableSubscription backing queue should have been marked as Exclusive during upgrade", dursubQueue.isExclusive()); + } + finally + { + jmxUtils.close(); + } + } + + /** + * Test that the upgraded queue continues to function properly when used + * for persistent messaging and restarting the broker. + * + * Sends the new messages to the queue BEFORE consuming those which were + * sent before the upgrade. In doing so, this also serves to test that + * the queue bindings were successfully transitioned during the upgrade. + */ + public void testBindingAndMessageDurabability() throws Exception + { + // Create a connection and start it + TopicConnection connection = (TopicConnection) getConnection(); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createQueue(QUEUE_NAME); + MessageProducer messageProducer = session.createProducer(queue); + + // Send a new message + sendMessages(session, messageProducer, queue, DeliveryMode.PERSISTENT, 256*1024, 1); + + session.close(); + + // Restart the broker + restartBroker(); + + // Drain the queue of all messages + connection = (TopicConnection) getConnection(); + connection.start(); + consumeQueueMessages(connection, true); + } + + /** + * Test that all of the committed persistent messages previously sent to + * the broker are properly received following update of the MetaData and + * Content entries during the store upgrade process. + */ + public void testConsumptionOfUpgradedMessages() throws Exception + { + // Create a connection and start it + Connection connection = getConnection(); + connection.start(); + + consumeDurableSubscriptionMessages(connection, true); + consumeDurableSubscriptionMessages(connection, false); + consumeQueueMessages(connection, false); + } + + /** + * Tests store migration containing messages for non-existing queue. + * + * @throws Exception + */ + public void testMigrationOfMessagesForNonDurableQueues() throws Exception + { + // Create a connection and start it + Connection connection = getConnection(); + connection.start(); + + // consume a message for non-existing store + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createQueue(NON_DURABLE_QUEUE_NAME); + MessageConsumer messageConsumer = session.createConsumer(queue); + + for (int i = 1; i <= 3; i++) + { + Message message = messageConsumer.receive(1000); + assertNotNull("Message was not migrated!", message); + assertTrue("Unexpected message received!", message instanceof TextMessage); + assertEquals("ID property did not match", i, message.getIntProperty("ID")); + } + } + + /** + * Tests store upgrade has maintained the priority queue configuration, + * such that sending messages with priorities out-of-order and then consuming + * them gets the messages back in priority order. + */ + public void testPriorityQueue() throws Exception + { + // Create a connection and start it + Connection connection = getConnection(); + connection.start(); + + // send some messages to the priority queue + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createQueue(PRIORITY_QUEUE_NAME); + MessageProducer producer = session.createProducer(queue); + + producer.setPriority(4); + producer.send(createMessage(1, false, session, producer)); + producer.setPriority(1); + producer.send(createMessage(2, false, session, producer)); + producer.setPriority(9); + producer.send(createMessage(3, false, session, producer)); + session.close(); + + //consume the messages, expected order: msg 3, msg 1, msg 2. + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(queue); + + Message msg = consumer.receive(1500); + assertNotNull("expected message was not received", msg); + assertEquals(3, msg.getIntProperty("msg")); + msg = consumer.receive(1500); + assertNotNull("expected message was not received", msg); + assertEquals(1, msg.getIntProperty("msg")); + msg = consumer.receive(1500); + assertNotNull("expected message was not received", msg); + assertEquals(2, msg.getIntProperty("msg")); + } + + /** + * + * TODO (QPID-5650) Resolve so this test can be reenabled. + * + * Test that the queue configured to have a DLQ was recovered and has the alternate exchange + * and max delivery count, the DLE exists, the DLQ exists with no max delivery count, the + * DLQ is bound to the DLE, and that the DLQ does not itself have a DLQ. + * + * DLQs are NOT enabled at the virtualhost level, we are testing recovery of the arguments + * that turned it on for this specific queue. + */ + public void xtestRecoveryOfQueueWithDLQ() throws Exception + { + JMXTestUtils jmxUtils = null; + try + { + jmxUtils = new JMXTestUtils(this, "guest", "guest"); + jmxUtils.open(); + } + catch (Exception e) + { + fail("Unable to establish JMX connection, test cannot proceed"); + } + + try + { + //verify the DLE exchange exists, has the expected type, and a single binding for the DLQ + ManagedExchange exchange = jmxUtils.getManagedExchange(QUEUE_WITH_DLQ_NAME + "_DLE"); + assertEquals("Wrong exchange type", "fanout", exchange.getExchangeType()); + TabularDataSupport bindings = (TabularDataSupport) exchange.bindings(); + assertEquals(1, bindings.size()); + for(Object o : bindings.values()) + { + CompositeData binding = (CompositeData) o; + + String bindingKey = (String) binding.get(ManagedExchange.BINDING_KEY); + String[] queueNames = (String[]) binding.get(ManagedExchange.QUEUE_NAMES); + + //Because its a fanout exchange, we just return a single '*' key with all bound queues + assertEquals("unexpected binding key", "*", bindingKey); + assertEquals("unexpected number of queues bound", 1, queueNames.length); + assertEquals("unexpected queue name", QUEUE_WITH_DLQ_NAME + "_DLQ", queueNames[0]); + } + + //verify the queue exists, has the expected alternate exchange and max delivery count + ManagedQueue queue = jmxUtils.getManagedQueue(QUEUE_WITH_DLQ_NAME); + assertEquals("Queue does not have the expected AlternateExchange", QUEUE_WITH_DLQ_NAME + "_DLE", queue.getAlternateExchange()); + assertEquals("Unexpected maximum delivery count", Integer.valueOf(2), queue.getMaximumDeliveryCount()); + + ManagedQueue dlQqueue = jmxUtils.getManagedQueue(QUEUE_WITH_DLQ_NAME + "_DLQ"); + assertNull("Queue should not have an AlternateExchange", dlQqueue.getAlternateExchange()); + assertEquals("Unexpected maximum delivery count", Integer.valueOf(0), dlQqueue.getMaximumDeliveryCount()); + + String dlqDlqObjectNameString = jmxUtils.getQueueObjectNameString("test", QUEUE_WITH_DLQ_NAME + "_DLQ" + "_DLQ"); + assertFalse("a DLQ should not exist for the DLQ itself", jmxUtils.doesManagedObjectExist(dlqDlqObjectNameString)); + } + finally + { + jmxUtils.close(); + } + } + + private void consumeDurableSubscriptionMessages(Connection connection, boolean selector) throws Exception + { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = null; + TopicSubscriber durSub = null; + + if(selector) + { + topic = session.createTopic(SELECTOR_TOPIC_NAME); + durSub = session.createDurableSubscriber(topic, SELECTOR_SUB_NAME,"testprop='true'", false); + } + else + { + topic = session.createTopic(TOPIC_NAME); + durSub = session.createDurableSubscriber(topic, SUB_NAME); + } + + + // Retrieve the matching message + Message m = durSub.receive(2000); + assertNotNull("Failed to receive an expected message", m); + if(selector) + { + assertEquals("Selector property did not match", "true", m.getStringProperty("testprop")); + } + assertEquals("ID property did not match", 1, m.getIntProperty("ID")); + assertEquals("Message content was not as expected", generateString(1024) , ((TextMessage)m).getText()); + + // Verify that no more messages are received + m = durSub.receive(1000); + assertNull("No more messages should have been recieved", m); + + durSub.close(); + session.close(); + } + + private void consumeQueueMessages(Connection connection, boolean extraMessage) throws Exception + { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = session.createQueue(QUEUE_NAME); + + MessageConsumer consumer = session.createConsumer(queue); + Message m; + + // Retrieve the initial pre-upgrade messages + for (int i=1; i <= 5 ; i++) + { + m = consumer.receive(2000); + assertNotNull("Failed to receive an expected message", m); + assertEquals("ID property did not match", i, m.getIntProperty("ID")); + assertEquals("Message content was not as expected", STRING_1024_256, ((TextMessage)m).getText()); + } + for (int i=1; i <= 5 ; i++) + { + m = consumer.receive(2000); + assertNotNull("Failed to receive an expected message", m); + assertEquals("ID property did not match", i, m.getIntProperty("ID")); + assertEquals("Message content was not as expected", STRING_1024, ((TextMessage)m).getText()); + } + + if(extraMessage) + { + //verify that the extra message is received + m = consumer.receive(2000); + assertNotNull("Failed to receive an expected message", m); + assertEquals("ID property did not match", 1, m.getIntProperty("ID")); + assertEquals("Message content was not as expected", STRING_1024_256, ((TextMessage)m).getText()); + } + + // Verify that no more messages are received + m = consumer.receive(1000); + assertNull("No more messages should have been recieved", m); + + consumer.close(); + session.close(); + } + + private Message createMessage(int msgId, boolean first, Session producerSession, MessageProducer producer) throws JMSException + { + Message send = producerSession.createTextMessage("Message: " + msgId); + send.setIntProperty("msg", msgId); + + return send; + } + + /** + * Generates a string of a given length consisting of the sequence 0,1,2,..,9,0,1,2. + * + * @param length number of characters in the string + * @return string sequence of the given length + */ + private static String generateString(int length) + { + char[] base_chars = new char[]{'0','1','2','3','4','5','6','7','8','9'}; + char[] chars = new char[length]; + for (int i = 0; i < (length); i++) + { + chars[i] = base_chars[i % 10]; + } + return new String(chars); + } + + private static void sendMessages(Session session, MessageProducer messageProducer, + Destination dest, int deliveryMode, int length, int numMesages) throws JMSException + { + for (int i = 1; i <= numMesages; i++) + { + Message message = session.createTextMessage(generateString(length)); + message.setIntProperty("ID", i); + messageProducer.send(message, deliveryMode, Message.DEFAULT_PRIORITY, Message.DEFAULT_TIME_TO_LIVE); + } + } + + private static void publishMessages(Session session, TopicPublisher publisher, + Destination dest, int deliveryMode, int length, int numMesages, String selectorProperty) throws JMSException + { + for (int i = 1; i <= numMesages; i++) + { + Message message = session.createTextMessage(generateString(length)); + message.setIntProperty("ID", i); + message.setStringProperty("testprop", selectorProperty); + publisher.publish(message, deliveryMode, Message.DEFAULT_PRIORITY, Message.DEFAULT_TIME_TO_LIVE); + } + } +} diff --git a/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostNodeRestTest.java b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostNodeRestTest.java new file mode 100644 index 0000000000..301375d0fb --- /dev/null +++ b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostNodeRestTest.java @@ -0,0 +1,455 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store.berkeleydb.replication; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import com.sleepycat.je.Durability; +import com.sleepycat.je.EnvironmentConfig; +import com.sleepycat.je.rep.ReplicatedEnvironment; +import com.sleepycat.je.rep.ReplicationConfig; +import org.apache.qpid.server.model.RemoteReplicationNode; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.model.VirtualHostNode; +import org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHost; +import org.apache.qpid.server.virtualhostnode.AbstractVirtualHostNode; +import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHARemoteReplicationNode; +import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHAVirtualHostNode; +import org.apache.qpid.systest.rest.Asserts; +import org.apache.qpid.systest.rest.QpidRestTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class BDBHAVirtualHostNodeRestTest extends QpidRestTestCase +{ + private static final String NODE1 = "node1"; + private static final String NODE2 = "node2"; + private static final String NODE3 = "node3"; + + private int _node1HaPort; + private int _node2HaPort; + private int _node3HaPort; + + private String _hostName; + private String _baseNodeRestUrl; + + @Override + public void setUp() throws Exception + { + setTestSystemProperty(ReplicatedEnvironmentFacade.REMOTE_NODE_MONITOR_INTERVAL_PROPERTY_NAME, "1000"); + + super.setUp(); + _hostName = getTestName(); + _baseNodeRestUrl = "virtualhostnode/"; + + _node1HaPort = findFreePort(); + _node2HaPort = getNextAvailable(_node1HaPort + 1); + _node3HaPort = getNextAvailable(_node2HaPort + 1); + + + } + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + TestBrokerConfiguration config = getBrokerConfiguration(); + config.removeObjectConfiguration(VirtualHostNode.class, TEST2_VIRTUALHOST); + config.removeObjectConfiguration(VirtualHostNode.class, TEST3_VIRTUALHOST); + } + + public void testCreate3NodeGroup() throws Exception + { + createHANode(NODE1, _node1HaPort, _node1HaPort); + assertNode(NODE1, _node1HaPort, _node1HaPort, NODE1); + createHANode(NODE2, _node2HaPort, _node1HaPort); + assertNode(NODE2, _node2HaPort, _node1HaPort, NODE1); + createHANode(NODE3, _node3HaPort, _node1HaPort); + assertNode(NODE3, _node3HaPort, _node1HaPort, NODE1); + assertRemoteNodes(NODE1, NODE2, NODE3); + } + + public void testMutateStateOfOneNode() throws Exception + { + createHANode(NODE1, _node1HaPort, _node1HaPort); + createHANode(NODE2, _node2HaPort, _node1HaPort); + createHANode(NODE3, _node3HaPort, _node1HaPort); + + String node1Url = _baseNodeRestUrl + NODE1; + String node2Url = _baseNodeRestUrl + NODE2; + String node3Url = _baseNodeRestUrl + NODE3; + + assertActualAndDesiredStates(node1Url, "ACTIVE", "ACTIVE"); + assertActualAndDesiredStates(node2Url, "ACTIVE", "ACTIVE"); + assertActualAndDesiredStates(node3Url, "ACTIVE", "ACTIVE"); + + mutateDesiredState(node1Url, "STOPPED"); + + assertActualAndDesiredStates(node1Url, "STOPPED", "STOPPED"); + assertActualAndDesiredStates(node2Url, "ACTIVE", "ACTIVE"); + assertActualAndDesiredStates(node3Url, "ACTIVE", "ACTIVE"); + + List> remoteNodes = getRestTestHelper().getJsonAsList("replicationnode/" + NODE2); + assertEquals("Unexpected number of remote nodes on " + NODE2, 2, remoteNodes.size()); + + Map remoteNode1 = findRemoteNodeByName(remoteNodes, NODE1); + + assertEquals("Node 1 observed from node 2 is in the wrong state", + "UNAVAILABLE", remoteNode1.get(BDBHARemoteReplicationNode.STATE)); + assertEquals("Node 1 observed from node 2 has the wrong role", + "UNKNOWN", remoteNode1.get(BDBHARemoteReplicationNode.ROLE)); + + } + + public void testNewMasterElectedWhenVirtualHostIsStopped() throws Exception + { + createHANode(NODE1, _node1HaPort, _node1HaPort); + createHANode(NODE2, _node2HaPort, _node1HaPort); + createHANode(NODE3, _node3HaPort, _node1HaPort); + + String node1Url = _baseNodeRestUrl + NODE1; + String node2Url = _baseNodeRestUrl + NODE2; + String node3Url = _baseNodeRestUrl + NODE3; + + assertActualAndDesiredStates(node1Url, "ACTIVE", "ACTIVE"); + assertActualAndDesiredStates(node2Url, "ACTIVE", "ACTIVE"); + assertActualAndDesiredStates(node3Url, "ACTIVE", "ACTIVE"); + + // Put virtualhost in STOPPED state + String virtualHostRestUrl = "virtualhost/" + NODE1 + "/" + _hostName; + assertActualAndDesiredStates(virtualHostRestUrl, "ACTIVE", "ACTIVE"); + mutateDesiredState(virtualHostRestUrl, "STOPPED"); + assertActualAndDesiredStates(virtualHostRestUrl, "STOPPED", "STOPPED"); + + // Now stop node 1 to cause an election between nodes 2 & 3 + mutateDesiredState(node1Url, "STOPPED"); + assertActualAndDesiredStates(node1Url, "STOPPED", "STOPPED"); + + Map newMasterData = awaitNewMaster(node2Url, node3Url); + + //Check the virtual host of the new master is in the stopped state + String newMasterVirtualHostRestUrl = "virtualhost/" + newMasterData.get(BDBHAVirtualHostNode.NAME) + "/" + _hostName; + assertActualAndDesiredStates(newMasterVirtualHostRestUrl, "STOPPED", "STOPPED"); + } + + public void testDeleteReplicaNode() throws Exception + { + createHANode(NODE1, _node1HaPort, _node1HaPort); + createHANode(NODE2, _node2HaPort, _node1HaPort); + createHANode(NODE3, _node3HaPort, _node1HaPort); + + assertRemoteNodes(NODE1, NODE2, NODE3); + + List> data = getRestTestHelper().getJsonAsList("replicationnode/" + NODE1); + assertEquals("Unexpected number of remote nodes on " + NODE1, 2, data.size()); + + int responseCode = getRestTestHelper().submitRequest(_baseNodeRestUrl + NODE2, "DELETE"); + assertEquals("Unexpected response code on deletion of virtual host node " + NODE2, 200, responseCode); + + int counter = 0; + while (data.size() != 1 && counter<50) + { + data = getRestTestHelper().getJsonAsList("replicationnode/" + NODE1); + if (data.size() != 1) + { + Thread.sleep(100l); + } + counter++; + } + assertEquals("Unexpected number of remote nodes on " + NODE1, 1, data.size()); + } + + public void testDeleteMasterNode() throws Exception + { + createHANode(NODE1, _node1HaPort, _node1HaPort); + createHANode(NODE2, _node2HaPort, _node1HaPort); + createHANode(NODE3, _node3HaPort, _node1HaPort); + + assertNode(NODE1, _node1HaPort, _node1HaPort, NODE1); + assertRemoteNodes(NODE1, NODE2, NODE3); + + // change priority to make Node2 a master + int responseCode = getRestTestHelper().submitRequest(_baseNodeRestUrl + NODE2, "PUT", Collections.singletonMap(BDBHAVirtualHostNode.PRIORITY, 100)); + assertEquals("Unexpected response code on priority update of virtual host node " + NODE2, 200, responseCode); + + List> data = getRestTestHelper().getJsonAsList("replicationnode/" + NODE2); + assertEquals("Unexpected number of remote nodes on " + NODE2, 2, data.size()); + + // delete master + responseCode = getRestTestHelper().submitRequest(_baseNodeRestUrl + NODE1, "DELETE"); + assertEquals("Unexpected response code on deletion of virtual host node " + NODE1, 200, responseCode); + + // wait for new master + waitForAttributeChanged(_baseNodeRestUrl + NODE2 + "?depth=0", BDBHAVirtualHostNode.ROLE, "MASTER"); + + // delete remote node + responseCode = getRestTestHelper().submitRequest("replicationnode/" + NODE2 + "/" + NODE1, "DELETE"); + assertEquals("Unexpected response code on deletion of remote node " + NODE1, 200, responseCode); + + int counter = 0; + while (data.size() != 1 && counter<50) + { + data = getRestTestHelper().getJsonAsList("replicationnode/" + NODE2); + if (data.size() != 1) + { + Thread.sleep(100l); + } + counter++; + } + assertEquals("Unexpected number of remote nodes on " + NODE2, 1, data.size()); + } + + public void testIntruderBDBHAVHNNotAllowedNoConnect() throws Exception + { + createHANode(NODE1, _node1HaPort, _node1HaPort); + assertNode(NODE1, _node1HaPort, _node1HaPort, NODE1); + + // add permitted node + Map node3Data = createNodeAttributeMap(NODE3, _node3HaPort, _node1HaPort); + getRestTestHelper().submitRequest(_baseNodeRestUrl + NODE3, "PUT", node3Data, 201); + assertNode(NODE3, _node3HaPort, _node1HaPort, NODE1); + assertRemoteNodes(NODE1, NODE3); + + int intruderPort = getNextAvailable(_node3HaPort + 1); + + // try to add not permitted node + Map nodeData = createNodeAttributeMap(NODE2, intruderPort, _node1HaPort); + getRestTestHelper().submitRequest(_baseNodeRestUrl + NODE2, "PUT", nodeData, 409); + + assertRemoteNodes(NODE1, NODE3); + } + + public void testIntruderProtection() throws Exception + { + createHANode(NODE1, _node1HaPort, _node1HaPort); + assertNode(NODE1, _node1HaPort, _node1HaPort, NODE1); + + Map nodeData = getRestTestHelper().getJsonAsSingletonList(_baseNodeRestUrl + NODE1); + String node1StorePath = (String)nodeData.get(BDBHAVirtualHostNode.STORE_PATH); + long transactionId = ((Number)nodeData.get(BDBHAVirtualHostNode.LAST_KNOWN_REPLICATION_TRANSACTION_ID)).longValue(); + + // add permitted node + Map node3Data = createNodeAttributeMap(NODE3, _node3HaPort, _node1HaPort); + getRestTestHelper().submitRequest(_baseNodeRestUrl + NODE3, "PUT", node3Data, 201); + assertNode(NODE3, _node3HaPort, _node1HaPort, NODE1); + assertRemoteNodes(NODE1, NODE3); + + // Ensure PINGDB is created + // in order to exclude hanging of environment + // when environment.close is called whilst PINGDB is created. + // On node joining, a record is updated in PINGDB + // if lastTransactionId is incremented then node ping task was executed + int counter = 0; + long newTransactionId = transactionId; + while(newTransactionId == transactionId && counter<50) + { + nodeData = getRestTestHelper().getJsonAsSingletonList(_baseNodeRestUrl + NODE1); + newTransactionId = ((Number)nodeData.get(BDBHAVirtualHostNode.LAST_KNOWN_REPLICATION_TRANSACTION_ID)).longValue(); + if (newTransactionId != transactionId) + { + break; + } + counter++; + Thread.sleep(100l); + } + + //connect intruder node + String nodeName = NODE2; + String nodeHostPort = "localhost:" + getNextAvailable(_node3HaPort + 1); + File environmentPathFile = new File(node1StorePath, nodeName); + environmentPathFile.mkdirs(); + ReplicationConfig replicationConfig = new ReplicationConfig((String)nodeData.get(BDBHAVirtualHostNode.GROUP_NAME), nodeName, nodeHostPort); + replicationConfig.setHelperHosts((String)nodeData.get(BDBHAVirtualHostNode.ADDRESS)); + EnvironmentConfig envConfig = new EnvironmentConfig(); + envConfig.setAllowCreate(true); + envConfig.setTransactional(true); + envConfig.setDurability(Durability.parse((String)nodeData.get(BDBHAVirtualHostNode.DURABILITY))); + + ReplicatedEnvironment intruder = null; + try + { + intruder = new ReplicatedEnvironment(environmentPathFile, replicationConfig, envConfig); + } + finally + { + if (intruder != null) + { + intruder.close(); + } + } + waitForAttributeChanged(_baseNodeRestUrl + NODE1, VirtualHostNode.STATE, State.ERRORED.name()); + waitForAttributeChanged(_baseNodeRestUrl + NODE3, VirtualHostNode.STATE, State.ERRORED.name()); + } + + private void createHANode(String nodeName, int nodePort, int helperPort) throws Exception + { + Map nodeData = createNodeAttributeMap(nodeName, nodePort, helperPort); + + int responseCode = getRestTestHelper().submitRequest(_baseNodeRestUrl + nodeName, "PUT", nodeData); + assertEquals("Unexpected response code for virtual host node " + nodeName + " creation request", 201, responseCode); + String hostExpectedState = nodePort == helperPort ? State.ACTIVE.name(): State.UNAVAILABLE.name(); + waitForAttributeChanged("virtualhost/" + nodeName + "/" + _hostName, BDBHAVirtualHost.STATE, hostExpectedState); + } + + private Map createNodeAttributeMap(String nodeName, int nodePort, int helperPort) throws Exception + { + Map nodeData = new HashMap(); + nodeData.put(BDBHAVirtualHostNode.NAME, nodeName); + nodeData.put(BDBHAVirtualHostNode.TYPE, "BDB_HA"); + nodeData.put(BDBHAVirtualHostNode.GROUP_NAME, _hostName); + nodeData.put(BDBHAVirtualHostNode.ADDRESS, "localhost:" + nodePort); + nodeData.put(BDBHAVirtualHostNode.HELPER_ADDRESS, "localhost:" + helperPort); + nodeData.put(BDBHAVirtualHostNode.HELPER_NODE_NAME, NODE1); + Map context = new HashMap<>(); + nodeData.put(BDBHAVirtualHostNode.CONTEXT, context); + String bluePrint = GroupCreator.getBlueprint("localhost", _node1HaPort, _node2HaPort, _node3HaPort); + context.put(AbstractVirtualHostNode.VIRTUALHOST_BLUEPRINT_CONTEXT_VAR, bluePrint); + return nodeData; + } + + private void assertNode(String nodeName, int nodePort, int nodeHelperPort, String masterNode) throws Exception + { + boolean isMaster = nodeName.equals(masterNode); + String expectedRole = isMaster? "MASTER" : "REPLICA"; + waitForAttributeChanged(_baseNodeRestUrl + nodeName + "?depth=0", BDBHAVirtualHostNode.ROLE, expectedRole); + + Map nodeData = getRestTestHelper().getJsonAsSingletonList(_baseNodeRestUrl + nodeName + "?depth=0"); + assertEquals("Unexpected name", nodeName, nodeData.get(BDBHAVirtualHostNode.NAME)); + assertEquals("Unexpected type", "BDB_HA", nodeData.get(BDBHAVirtualHostNode.TYPE)); + assertEquals("Unexpected address", "localhost:" + nodePort, nodeData.get(BDBHAVirtualHostNode.ADDRESS)); + assertEquals("Unexpected helper address", "localhost:" + nodeHelperPort, nodeData.get(BDBHAVirtualHostNode.HELPER_ADDRESS)); + assertEquals("Unexpected group name", _hostName, nodeData.get(BDBHAVirtualHostNode.GROUP_NAME)); + assertEquals("Unexpected role", expectedRole, nodeData.get(BDBHAVirtualHostNode.ROLE)); + + Integer lastKnownTransactionId = (Integer) nodeData.get(BDBHAVirtualHostNode.LAST_KNOWN_REPLICATION_TRANSACTION_ID); + assertNotNull("Unexpected lastKnownReplicationId", lastKnownTransactionId); + assertTrue("Unexpected lastKnownReplicationId " + lastKnownTransactionId, lastKnownTransactionId > 0); + + Long joinTime = (Long) nodeData.get(BDBHAVirtualHostNode.JOIN_TIME); + assertNotNull("Unexpected joinTime", joinTime); + assertTrue("Unexpected joinTime " + joinTime, joinTime > 0); + + if (isMaster) + { + waitForAttributeChanged("virtualhost/" + masterNode + "/" + _hostName + "?depth=0", VirtualHost.STATE, State.ACTIVE.name()); + } + + } + + private void assertRemoteNodes(String masterNode, String... replicaNodes) throws Exception + { + List clusterNodes = new ArrayList(Arrays.asList(replicaNodes)); + clusterNodes.add(masterNode); + + for (String clusterNodeName : clusterNodes) + { + List remotes = new ArrayList(clusterNodes); + remotes.remove(clusterNodeName); + for (String remote : remotes) + { + String remoteUrl = "replicationnode/" + clusterNodeName + "/" + remote; + Map nodeData = waitForAttributeChanged(remoteUrl, BDBHARemoteReplicationNode.ROLE, remote.equals(masterNode) ? "MASTER" : "REPLICA"); + assertRemoteNodeData(remote, nodeData); + } + } + } + + private void assertRemoteNodeData(String name, Map nodeData) + { + assertEquals("Remote node " + name + " has unexpected name", name, nodeData.get(BDBHAVirtualHostNode.NAME)); + + Integer lastKnownTransactionId = (Integer) nodeData.get(BDBHAVirtualHostNode.LAST_KNOWN_REPLICATION_TRANSACTION_ID); + assertNotNull("Node " + name + " has unexpected lastKnownReplicationId", lastKnownTransactionId); + assertTrue("Node " + name + " has unexpected lastKnownReplicationId " + lastKnownTransactionId, lastKnownTransactionId > 0); + + Long joinTime = (Long) nodeData.get(BDBHAVirtualHostNode.JOIN_TIME); + assertNotNull("Node " + name + " has unexpected joinTime", joinTime); + assertTrue("Node " + name + " has unexpected joinTime " + joinTime, joinTime > 0); + } + + private void assertActualAndDesiredStates(final String restUrl, + final String expectedDesiredState, + final String expectedActualState) throws IOException + { + Map objectData = getRestTestHelper().getJsonAsSingletonList(restUrl); + Asserts.assertActualAndDesiredState(expectedDesiredState, expectedActualState, objectData); + } + + private void mutateDesiredState(final String restUrl, final String newState) throws IOException + { + Map newAttributes = new HashMap(); + newAttributes.put(VirtualHostNode.DESIRED_STATE, newState); + + getRestTestHelper().submitRequest(restUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); + } + + private Map findRemoteNodeByName(final List> remoteNodes, final String nodeName) + { + Map foundNode = null; + for (Map remoteNode : remoteNodes) + { + if (nodeName.equals(remoteNode.get(RemoteReplicationNode.NAME))) + { + foundNode = remoteNode; + break; + } + } + assertNotNull("Could not find node with name " + nodeName + " amongst remote nodes."); + return foundNode; + } + + private Map awaitNewMaster(final String... nodeUrls) + throws IOException, InterruptedException + { + Map newMasterData = null; + int counter = 0; + while (newMasterData == null && counter < 50) + { + for(String nodeUrl: nodeUrls) + { + Map nodeData = getRestTestHelper().getJsonAsSingletonList(nodeUrl); + if ("MASTER".equals(nodeData.get(BDBHAVirtualHostNode.ROLE))) + { + newMasterData = nodeData; + break; + } + } + if (newMasterData == null) + { + Thread.sleep(100l); + counter++; + } + } + assertNotNull("Could not find new master", newMasterData); + return newMasterData; + } + + +} diff --git a/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostRestTest.java b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostRestTest.java new file mode 100644 index 0000000000..07ce033a55 --- /dev/null +++ b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostRestTest.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.server.store.berkeleydb.replication; + +import static org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHost.LOCAL_TRANSACTION_SYNCHRONIZATION_POLICY; +import static org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHost.REMOTE_TRANSACTION_SYNCHRONIZATION_POLICY; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.model.VirtualHostNode; +import org.apache.qpid.server.virtualhostnode.AbstractVirtualHostNode; +import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHAVirtualHostNode; +import org.apache.qpid.systest.rest.Asserts; +import org.apache.qpid.systest.rest.QpidRestTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.util.FileUtils; + +public class BDBHAVirtualHostRestTest extends QpidRestTestCase +{ + private String _hostName; + private File _storeBaseDir; + private int _nodeHaPort; + private Object _nodeName; + private String _virtualhostUrl; + private String _bluePrint; + + @Override + public void setUp() throws Exception + { + setTestSystemProperty(ReplicatedEnvironmentFacade.REMOTE_NODE_MONITOR_INTERVAL_PROPERTY_NAME, "1000"); + _hostName = "ha"; + _nodeName = "node1"; + _storeBaseDir = new File(TMP_FOLDER, "store-" + _hostName + "-" + System.currentTimeMillis()); + _nodeHaPort = getNextAvailable(getRestTestHelper().getHttpPort() + 1); + _virtualhostUrl = "virtualhost/" + _nodeName + "/" + _hostName; + _bluePrint = GroupCreator.getBlueprint("localhost", _nodeHaPort); + + super.setUp(); + } + + @Override + public void tearDown() throws Exception + { + try + { + super.tearDown(); + } + finally + { + if (_storeBaseDir != null) + { + FileUtils.delete(_storeBaseDir, true); + } + } + } + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + TestBrokerConfiguration config = getBrokerConfiguration(); + config.removeObjectConfiguration(VirtualHostNode.class, TEST2_VIRTUALHOST); + config.removeObjectConfiguration(VirtualHostNode.class, TEST3_VIRTUALHOST); + + Map nodeAttributes = new HashMap(); + nodeAttributes.put(BDBHAVirtualHostNode.NAME, _nodeName); + nodeAttributes.put(BDBHAVirtualHostNode.TYPE, "BDB_HA"); + nodeAttributes.put(BDBHAVirtualHostNode.STORE_PATH, _storeBaseDir.getPath() + File.separator + _nodeName); + nodeAttributes.put(BDBHAVirtualHostNode.GROUP_NAME, _hostName); + nodeAttributes.put(BDBHAVirtualHostNode.ADDRESS, "localhost:" + _nodeHaPort); + nodeAttributes.put(BDBHAVirtualHostNode.HELPER_ADDRESS, "localhost:" + _nodeHaPort); + nodeAttributes.put(BDBHAVirtualHostNode.HELPER_NODE_NAME, _nodeName); + Map context = new HashMap(); + context.put(AbstractVirtualHostNode.VIRTUALHOST_BLUEPRINT_CONTEXT_VAR, _bluePrint); + + nodeAttributes.put(BDBHAVirtualHostNode.CONTEXT, context); + config.addObjectConfiguration(VirtualHostNode.class, nodeAttributes); + } + + public void testSetLocalTransactionSynchronizationPolicy() throws Exception + { + Map hostAttributes = waitForAttributeChanged(_virtualhostUrl, VirtualHost.STATE, State.ACTIVE.name()); + assertEquals("Unexpected synchronization policy before change", "SYNC", hostAttributes.get(LOCAL_TRANSACTION_SYNCHRONIZATION_POLICY)); + + Map newPolicy = Collections.singletonMap(LOCAL_TRANSACTION_SYNCHRONIZATION_POLICY, "NO_SYNC"); + getRestTestHelper().submitRequest(_virtualhostUrl, "PUT", newPolicy, HttpServletResponse.SC_OK); + + hostAttributes = getRestTestHelper().getJsonAsSingletonList(_virtualhostUrl); + assertEquals("Unexpected synchronization policy after change", "NO_SYNC", hostAttributes.get(LOCAL_TRANSACTION_SYNCHRONIZATION_POLICY)); + } + + public void testSetRemoteTransactionSynchronizationPolicy() throws Exception + { + Map hostAttributes = waitForAttributeChanged(_virtualhostUrl, VirtualHost.STATE, State.ACTIVE.name()); + assertEquals("Unexpected synchronization policy before change", "NO_SYNC", hostAttributes.get(REMOTE_TRANSACTION_SYNCHRONIZATION_POLICY)); + + Map newPolicy = Collections.singletonMap(REMOTE_TRANSACTION_SYNCHRONIZATION_POLICY, "SYNC"); + getRestTestHelper().submitRequest(_virtualhostUrl, "PUT", newPolicy, HttpServletResponse.SC_OK); + + hostAttributes = getRestTestHelper().getJsonAsSingletonList(_virtualhostUrl); + assertEquals("Unexpected synchronization policy after change", "SYNC", hostAttributes.get(REMOTE_TRANSACTION_SYNCHRONIZATION_POLICY)); + } + + public void testMutateState() throws Exception + { + waitForAttributeChanged(_virtualhostUrl, VirtualHost.STATE, "ACTIVE"); + assertActualAndDesireStates(_virtualhostUrl, "ACTIVE", "ACTIVE"); + + Map newAttributes = Collections.singletonMap(VirtualHost.DESIRED_STATE, "STOPPED"); + getRestTestHelper().submitRequest(_virtualhostUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); + + waitForAttributeChanged(_virtualhostUrl, VirtualHost.STATE, "STOPPED"); + assertActualAndDesireStates(_virtualhostUrl, "STOPPED", "STOPPED"); + + newAttributes = Collections.singletonMap(VirtualHost.DESIRED_STATE, "ACTIVE"); + getRestTestHelper().submitRequest(_virtualhostUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); + + waitForAttributeChanged(_virtualhostUrl, VirtualHost.STATE, "ACTIVE"); + assertActualAndDesireStates(_virtualhostUrl, "ACTIVE", "ACTIVE"); + } + + private void assertActualAndDesireStates(final String restUrl, + final String expectedDesiredState, + final String expectedActualState) throws IOException + { + Map virtualhost = getRestTestHelper().getJsonAsSingletonList(restUrl); + Asserts.assertActualAndDesiredState(expectedDesiredState, expectedActualState, virtualhost); + } + +} diff --git a/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/GroupCreator.java b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/GroupCreator.java new file mode 100644 index 0000000000..e78ef34759 --- /dev/null +++ b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/GroupCreator.java @@ -0,0 +1,535 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store.berkeleydb.replication; + +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.concurrent.Callable; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQConnectionURL; +import org.apache.qpid.jms.ConnectionURL; +import org.apache.qpid.server.management.plugin.HttpManagement; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.model.VirtualHostNode; +import org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHost; +import org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHostImpl; +import org.apache.qpid.server.virtualhostnode.AbstractVirtualHostNode; +import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHARemoteReplicationNode; +import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHAVirtualHostNode; +import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHAVirtualHostNodeImpl; +import org.apache.qpid.systest.rest.RestTestHelper; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.url.URLSyntaxException; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.SerializationConfig; +import org.junit.Assert; + +import com.sleepycat.je.rep.ReplicationConfig; + +public class GroupCreator +{ + protected static final Logger LOGGER = Logger.getLogger(GroupCreator.class); + + private static final String MANY_BROKER_URL_FORMAT = "amqp://guest:guest@/%s?brokerlist='%s'&failover='roundrobin?cyclecount='%d''"; + private static final String BROKER_PORTION_FORMAT = "tcp://localhost:%d?connectdelay='%d',retries='%d'"; + + private static final int FAILOVER_CYCLECOUNT = 10; + private static final int FAILOVER_RETRIES = 1; + private static final int FAILOVER_CONNECTDELAY = 1000; + + private static final String SINGLE_BROKER_URL_WITH_RETRY_FORMAT = "amqp://guest:guest@/%s?brokerlist='tcp://localhost:%d?connectdelay='%d',retries='%d''"; + private static final String SINGLE_BROKER_URL_WITHOUT_RETRY_FORMAT = "amqp://guest:guest@/%s?brokerlist='tcp://localhost:%d'"; + + private static final int RETRIES = 60; + private static final int CONNECTDELAY = 75; + + private final QpidBrokerTestCase _testcase; + private final Map _brokerPortToBdbPortMap = new TreeMap(); + private final String _virtualHostName; + + private final String _ipAddressOfBroker; + private final String _groupName ; + private final int _numberOfNodes; + private int _bdbHelperPort; + private int _primaryBrokerPort; + + public GroupCreator(QpidBrokerTestCase testcase, String virtualHostName, int numberOfNodes) + { + _testcase = testcase; + _virtualHostName = virtualHostName; + _groupName = virtualHostName; + _ipAddressOfBroker = getIpAddressOfBrokerHost(); + _numberOfNodes = numberOfNodes; + _bdbHelperPort = 0; + } + + public void configureClusterNodes() throws Exception + { + int brokerPort = _testcase.findFreePort(); + + int[] bdbPorts = new int[_numberOfNodes]; + for (int i = 0; i < _numberOfNodes; i++) + { + int bdbPort = _testcase.getNextAvailable(brokerPort + 1); + bdbPorts[i] = bdbPort; + _brokerPortToBdbPortMap.put(brokerPort, bdbPort); + brokerPort = _testcase.getNextAvailable(bdbPort + 1); + } + + String bluePrintJson = getBlueprint(_ipAddressOfBroker, bdbPorts); + + String helperName = null; + for (Map.Entry entry: _brokerPortToBdbPortMap.entrySet()) + { + brokerPort = entry.getKey(); + int bdbPort = entry.getValue(); + LOGGER.debug("Cluster broker port " + brokerPort + ", bdb replication port " + bdbPort); + if (_bdbHelperPort == 0) + { + _bdbHelperPort = bdbPort; + } + + String nodeName = getNodeNameForNodeAt(bdbPort); + if (helperName == null) + { + helperName = nodeName; + } + + Map virtualHostNodeAttributes = new HashMap(); + virtualHostNodeAttributes.put(BDBHAVirtualHostNode.STORE_PATH, System.getProperty("QPID_WORK") + File.separator + brokerPort); + virtualHostNodeAttributes.put(BDBHAVirtualHostNode.GROUP_NAME, _groupName); + virtualHostNodeAttributes.put(BDBHAVirtualHostNode.NAME, nodeName); + virtualHostNodeAttributes.put(BDBHAVirtualHostNode.ADDRESS, getNodeHostPortForNodeAt(bdbPort)); + virtualHostNodeAttributes.put(BDBHAVirtualHostNode.HELPER_ADDRESS, getHelperHostPort()); + virtualHostNodeAttributes.put(BDBHAVirtualHostNode.TYPE, BDBHAVirtualHostNodeImpl.VIRTUAL_HOST_NODE_TYPE); + virtualHostNodeAttributes.put(BDBHAVirtualHostNode.HELPER_NODE_NAME, helperName); + + Map context = new HashMap<>(); + context.put(ReplicationConfig.INSUFFICIENT_REPLICAS_TIMEOUT, "2 s"); + context.put(ReplicationConfig.ELECTIONS_PRIMARY_RETRIES, "0"); + context.put(AbstractVirtualHostNode.VIRTUALHOST_BLUEPRINT_CONTEXT_VAR, bluePrintJson); + virtualHostNodeAttributes.put(BDBHAVirtualHostNode.CONTEXT, context); + + TestBrokerConfiguration brokerConfiguration = _testcase.getBrokerConfiguration(brokerPort); + brokerConfiguration.addJmxManagementConfiguration(); + brokerConfiguration.addHttpManagementConfiguration(); + brokerConfiguration.setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); + brokerConfiguration.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.PORT, _testcase.getHttpManagementPort(brokerPort)); + brokerConfiguration.setObjectAttributes(VirtualHostNode.class, _virtualHostName, virtualHostNodeAttributes); + + } + _primaryBrokerPort = getPrimaryBrokerPort(); + } + + public void setDesignatedPrimaryOnFirstBroker(boolean designatedPrimary) throws Exception + { + if (_numberOfNodes != 2) + { + throw new IllegalArgumentException("Only two nodes groups have the concept of primary"); + } + TestBrokerConfiguration config = _testcase.getBrokerConfiguration(_primaryBrokerPort); + String nodeName = getNodeNameForNodeAt(_brokerPortToBdbPortMap.get(_primaryBrokerPort)); + config.setObjectAttribute(VirtualHostNode.class, nodeName, BDBHAVirtualHostNode.DESIGNATED_PRIMARY, designatedPrimary); + config.setSaved(false); + } + + private int getPrimaryBrokerPort() + { + return _brokerPortToBdbPortMap.keySet().iterator().next(); + } + + public void startNode(final int brokerPortNumber) throws Exception + { + _testcase.startBroker(brokerPortNumber); + } + + public void startCluster() throws Exception + { + for (final Integer brokerPortNumber : _brokerPortToBdbPortMap.keySet()) + { + startNode(brokerPortNumber); + } + } + + public void startClusterParallel() throws Exception + { + final ExecutorService executor = Executors.newFixedThreadPool(_brokerPortToBdbPortMap.size()); + try + { + List> brokers = new CopyOnWriteArrayList>(); + for (final Integer brokerPortNumber : _brokerPortToBdbPortMap.keySet()) + { + final TestBrokerConfiguration brokerConfig = _testcase.getBrokerConfiguration(brokerPortNumber); + Future future = executor.submit(new Callable() + { + public Object call() + { + try + { + _testcase.startBroker(brokerPortNumber, brokerConfig); + return "OK"; + } + catch (Exception e) + { + return e; + } + } + }); + brokers.add(future); + } + for (Future future : brokers) + { + Object result = future.get(30, TimeUnit.SECONDS); + LOGGER.debug("Node startup result:" + result); + if (result instanceof Exception) + { + throw (Exception) result; + } + else if (!"OK".equals(result)) + { + throw new Exception("One of the cluster nodes is not started"); + } + } + } + catch (Exception e) + { + stopCluster(); + throw e; + } + finally + { + executor.shutdown(); + } + + } + + public void stopNode(final int brokerPortNumber) + { + _testcase.killBroker(brokerPortNumber); + } + + public void stopCluster() throws Exception + { + for (final Integer brokerPortNumber : _brokerPortToBdbPortMap.keySet()) + { + try + { + stopNode(brokerPortNumber); + } + catch(Exception e) + { + LOGGER.warn("Failed to stop node on port:" + brokerPortNumber); + } + } + } + + public int getBrokerPortNumberFromConnection(Connection connection) + { + final AMQConnection amqConnection = (AMQConnection)connection; + return amqConnection.getActiveBrokerDetails().getPort(); + } + + public int getPortNumberOfAnInactiveBroker(final Connection activeConnection) + { + final Set allBrokerPorts = _testcase.getBrokerPortNumbers(); + LOGGER.debug("Broker ports:" + allBrokerPorts); + final int activeBrokerPort = getBrokerPortNumberFromConnection(activeConnection); + allBrokerPorts.remove(activeBrokerPort); + LOGGER.debug("Broker ports:" + allBrokerPorts); + final int inactiveBrokerPort = allBrokerPorts.iterator().next(); + return inactiveBrokerPort; + } + + public int getBdbPortForBrokerPort(final int brokerPortNumber) + { + return _brokerPortToBdbPortMap.get(brokerPortNumber); + } + + public Set getBdbPortNumbers() + { + return new HashSet(_brokerPortToBdbPortMap.values()); + } + + public ConnectionURL getConnectionUrlForAllClusterNodes() throws Exception + { + return getConnectionUrlForAllClusterNodes(FAILOVER_CONNECTDELAY, FAILOVER_RETRIES, FAILOVER_CYCLECOUNT); + } + + public ConnectionURL getConnectionUrlForAllClusterNodes(int connectDelay, int retries, final int cyclecount) throws Exception + { + final StringBuilder brokerList = new StringBuilder(); + + for(Iterator itr = _brokerPortToBdbPortMap.keySet().iterator(); itr.hasNext(); ) + { + int brokerPortNumber = itr.next(); + + brokerList.append(String.format(BROKER_PORTION_FORMAT, brokerPortNumber, connectDelay, retries)); + if (itr.hasNext()) + { + brokerList.append(";"); + } + } + + return new AMQConnectionURL(String.format(MANY_BROKER_URL_FORMAT, _virtualHostName, brokerList, cyclecount)); + } + + public AMQConnectionURL getConnectionUrlForSingleNodeWithoutRetry(final int brokerPortNumber) throws URLSyntaxException + { + return getConnectionUrlForSingleNode(brokerPortNumber, false); + } + + public AMQConnectionURL getConnectionUrlForSingleNodeWithRetry(final int brokerPortNumber) throws URLSyntaxException + { + return getConnectionUrlForSingleNode(brokerPortNumber, true); + } + + private AMQConnectionURL getConnectionUrlForSingleNode(final int brokerPortNumber, boolean retryAllowed) throws URLSyntaxException + { + final String url; + if (retryAllowed) + { + url = String.format(SINGLE_BROKER_URL_WITH_RETRY_FORMAT, _virtualHostName, brokerPortNumber, CONNECTDELAY, RETRIES); + } + else + { + url = String.format(SINGLE_BROKER_URL_WITHOUT_RETRY_FORMAT, _virtualHostName, brokerPortNumber); + } + + return new AMQConnectionURL(url); + } + + public String getGroupName() + { + return _groupName; + } + + public String getNodeNameForNodeAt(final int bdbPort) + { + return "node" + _testcase.getName() + bdbPort; + } + + public String getNodeHostPortForNodeAt(final int bdbPort) + { + return _ipAddressOfBroker + ":" + bdbPort; + } + + public String getHelperHostPort() + { + if (_bdbHelperPort == 0) + { + throw new IllegalStateException("Helper port not yet assigned."); + } + + return _ipAddressOfBroker + ":" + _bdbHelperPort; + } + + public void setHelperHostPort(int bdbHelperPort) + { + _bdbHelperPort = bdbHelperPort; + } + + public int getBrokerPortNumberOfPrimary() + { + if (_numberOfNodes != 2) + { + throw new IllegalArgumentException("Only two nodes groups have the concept of primary"); + } + + return _primaryBrokerPort; + } + + public int getBrokerPortNumberOfSecondaryNode() + { + final Set portNumbers = getBrokerPortNumbersForNodes(); + portNumbers.remove(getBrokerPortNumberOfPrimary()); + return portNumbers.iterator().next(); + } + + public Set getBrokerPortNumbersForNodes() + { + return new HashSet(_brokerPortToBdbPortMap.keySet()); + } + + + public String getIpAddressOfBrokerHost() + { + String brokerHost = _testcase.getBroker().getHost(); + try + { + return InetAddress.getByName(brokerHost).getHostAddress(); + } + catch (UnknownHostException e) + { + throw new RuntimeException("Could not determine IP address of host : " + brokerHost, e); + } + } + + public void modifyClusterNodeBdbAddress(int brokerPortNumberToBeMoved, int newBdbPort) + { + TestBrokerConfiguration config = _testcase.getBrokerConfiguration(brokerPortNumberToBeMoved); + String nodeName = getNodeNameForNodeAt(_brokerPortToBdbPortMap.get(brokerPortNumberToBeMoved)); + + Map objectAttributes = config.getObjectAttributes(VirtualHostNode.class, nodeName); + + String oldBdbHostPort = (String)objectAttributes.get(BDBHAVirtualHostNode.ADDRESS); + String[] oldHostAndPort = StringUtils.split(oldBdbHostPort, ":"); + String oldHost = oldHostAndPort[0]; + String newBdbHostPort = oldHost + ":" + newBdbPort; + config.setObjectAttribute(VirtualHostNode.class, nodeName, BDBHAVirtualHostNode.ADDRESS, newBdbHostPort); + config.setSaved(false); + } + + public String getNodeNameForBrokerPort(final int brokerPort) + { + return getNodeNameForNodeAt(_brokerPortToBdbPortMap.get(brokerPort)); + } + + public void setNodeAttributes(int brokerPort, Map attributeMap) + throws Exception + { + setNodeAttributes(brokerPort, brokerPort, attributeMap); + } + + public void setNodeAttributes(int localNodePort, int remoteNodePort, Map attributeMap) + throws Exception + { + RestTestHelper restHelper = createRestTestHelper(localNodePort); + String url = getNodeRestUrl(localNodePort, remoteNodePort); + int status = restHelper.submitRequest(url, "PUT", attributeMap); + if (status != 200) + { + throw new Exception("Unexpected http status when updating " + getNodeNameForBrokerPort(remoteNodePort) + " attribute(s) : " + status); + } + } + + private String getNodeRestUrl(int localNodePort, int remoteNodePort) + { + String remoteNodeName = getNodeNameForBrokerPort(remoteNodePort); + String localNodeName = getNodeNameForBrokerPort(localNodePort); + String url = null; + if (localNodePort == remoteNodePort) + { + url = "/api/latest/virtualhostnode/" + localNodeName; + } + else + { + url = "/api/latest/replicationnode/" + localNodeName + "/" + remoteNodeName; + } + return url; + } + + public Map getNodeAttributes(int brokerPort) throws IOException + { + return getNodeAttributes(brokerPort, brokerPort); + } + + public Map getNodeAttributes(int localNodePort, int remoteNodePort) throws IOException + { + RestTestHelper restHelper = createRestTestHelper(localNodePort); + List> results= restHelper.getJsonAsList(getNodeRestUrl(localNodePort, remoteNodePort)); + int size = results.size(); + if (size == 0) + { + return Collections.emptyMap(); + } + else if (size == 1) + { + return results.get(0); + } + else + { + throw new RuntimeException("Unexpected number of nodes " + size); + } + } + + public void awaitNodeToAttainRole(int brokerPort, String desiredRole) throws Exception + { + awaitNodeToAttainRole(brokerPort, brokerPort, desiredRole); + } + + public void awaitNodeToAttainRole(int localNodePort, int remoteNodePort, String desiredRole) throws Exception + { + final long startTime = System.currentTimeMillis(); + Map data = Collections.emptyMap(); + + while(!desiredRole.equals(data.get(BDBHARemoteReplicationNode.ROLE)) && (System.currentTimeMillis() - startTime) < 30000) + { + LOGGER.debug("Awaiting node '" + getNodeNameForBrokerPort(remoteNodePort) + "' to transit into " + desiredRole + " role"); + data = getNodeAttributes(localNodePort, remoteNodePort); + if (!desiredRole.equals(data.get(BDBHARemoteReplicationNode.ROLE))) + { + Thread.sleep(1000); + } + } + LOGGER.debug("Node '" + getNodeNameForBrokerPort(remoteNodePort) + "' role is " + data.get(BDBHARemoteReplicationNode.ROLE)); + Assert.assertEquals("Node is in unexpected role", desiredRole, data.get(BDBHARemoteReplicationNode.ROLE)); + } + + public RestTestHelper createRestTestHelper(int brokerPort) + { + int httpPort = _testcase.getHttpManagementPort(brokerPort); + RestTestHelper helper = new RestTestHelper(httpPort); + helper.setUsernameAndPassword("webadmin", "webadmin"); + return helper; + } + + public static String getBlueprint(String hostName, int... ports) throws Exception + { + List permittedNodes = new ArrayList(); + for (int port:ports) + { + permittedNodes.add(hostName + ":" + port); + } + Map bluePrint = new HashMap<>(); + bluePrint.put(VirtualHost.TYPE, BDBHAVirtualHostImpl.VIRTUAL_HOST_TYPE); + bluePrint.put(BDBHAVirtualHost.PERMITTED_NODES, permittedNodes); + + StringWriter writer = new StringWriter(); + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); + mapper.writeValue(writer, bluePrint); + return writer.toString(); + } +} diff --git a/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/JMXManagementTest.java b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/JMXManagementTest.java new file mode 100644 index 0000000000..c6f005c0e7 --- /dev/null +++ b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/JMXManagementTest.java @@ -0,0 +1,321 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store.berkeleydb.replication; + +import static com.sleepycat.je.rep.ReplicatedEnvironment.State.DETACHED; +import static com.sleepycat.je.rep.ReplicatedEnvironment.State.MASTER; +import static com.sleepycat.je.rep.ReplicatedEnvironment.State.REPLICA; +import static com.sleepycat.je.rep.ReplicatedEnvironment.State.UNKNOWN; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.jms.Connection; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularData; + +import org.apache.log4j.Logger; +import org.apache.qpid.jms.ConnectionURL; +import org.apache.qpid.management.common.mbeans.ManagedBroker; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.store.berkeleydb.jmx.ManagedBDBHAMessageStore; +import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHAVirtualHostNode; +import org.apache.qpid.systest.rest.RestTestHelper; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.junit.Assert; + +/** + * System test verifying the ability to control a cluster via the Management API. + * + * @see MultiNodeTest + */ +public class JMXManagementTest extends QpidBrokerTestCase +{ + protected static final Logger LOGGER = Logger.getLogger(JMXManagementTest.class); + + private static final Set NON_MASTER_STATES = new HashSet(Arrays.asList(REPLICA.toString(), DETACHED.toString(), UNKNOWN.toString()));; + private static final String VIRTUAL_HOST = "test"; + + private static final String MANAGED_OBJECT_QUERY = "org.apache.qpid:type=BDBHAMessageStore,name=" + ObjectName.quote(VIRTUAL_HOST); + private static final int NUMBER_OF_NODES = 4; + + private final GroupCreator _clusterCreator = new GroupCreator(this, VIRTUAL_HOST, NUMBER_OF_NODES); + private final JMXTestUtils _jmxUtils = new JMXTestUtils(this); + + private ConnectionURL _brokerFailoverUrl; + + @Override + protected void setUp() throws Exception + { + _brokerType = BrokerType.SPAWNED; + + _clusterCreator.configureClusterNodes(); + _brokerFailoverUrl = _clusterCreator.getConnectionUrlForAllClusterNodes(); + _clusterCreator.startCluster(); + + super.setUp(); + } + + @Override + protected void tearDown() throws Exception + { + try + { + _jmxUtils.close(); + } + finally + { + super.tearDown(); + } + } + + @Override + public void startBroker() throws Exception + { + // Don't start default broker provided by QBTC. + } + + public void testReadonlyMBeanAttributes() throws Exception + { + final int brokerPortNumber = getBrokerPortNumbers().iterator().next(); + final int bdbPortNumber = _clusterCreator.getBdbPortForBrokerPort(brokerPortNumber); + + ManagedBDBHAMessageStore storeBean = getStoreBeanForNodeAtBrokerPort(brokerPortNumber); + assertEquals("Unexpected store group name", _clusterCreator.getGroupName(), storeBean.getGroupName()); + assertEquals("Unexpected store node name", _clusterCreator.getNodeNameForNodeAt(bdbPortNumber), storeBean.getNodeName()); + assertEquals("Unexpected store node host port",_clusterCreator.getNodeHostPortForNodeAt(bdbPortNumber), storeBean.getNodeHostPort()); + assertEquals("Unexpected store helper host port", _clusterCreator.getHelperHostPort(), storeBean.getHelperHostPort()); + // As we have chosen an arbitrary broker from the cluster, we cannot predict its state + assertNotNull("Store state must not be null", storeBean.getNodeState()); + } + + public void testStateOfActiveBrokerIsMaster() throws Exception + { + final Connection activeConnection = getConnection(_brokerFailoverUrl); + final int activeBrokerPortNumber = _clusterCreator.getBrokerPortNumberFromConnection(activeConnection); + + ManagedBDBHAMessageStore storeBean = getStoreBeanForNodeAtBrokerPort(activeBrokerPortNumber); + assertEquals("Unexpected store state", MASTER.toString(), storeBean.getNodeState()); + } + + public void testStateOfNonActiveBrokerIsNotMaster() throws Exception + { + final Connection activeConnection = getConnection(_brokerFailoverUrl); + final int inactiveBrokerPortNumber = _clusterCreator.getPortNumberOfAnInactiveBroker(activeConnection); + ManagedBDBHAMessageStore storeBean = getStoreBeanForNodeAtBrokerPort(inactiveBrokerPortNumber); + final String nodeState = storeBean.getNodeState(); + assertTrue("Unexpected store state : " + nodeState, NON_MASTER_STATES.contains(nodeState)); + } + + public void testGroupMembers() throws Exception + { + final int brokerPortNumber = getBrokerPortNumbers().iterator().next(); + + ManagedBDBHAMessageStore storeBean = getStoreBeanForNodeAtBrokerPort(brokerPortNumber); + awaitAllNodesJoiningGroup(storeBean, NUMBER_OF_NODES); + + final TabularData groupMembers = storeBean.getAllNodesInGroup(); + assertNotNull(groupMembers); + + for(int bdbPortNumber : _clusterCreator.getBdbPortNumbers()) + { + final String nodeName = _clusterCreator.getNodeNameForNodeAt(bdbPortNumber); + final String nodeHostPort = _clusterCreator.getNodeHostPortForNodeAt(bdbPortNumber); + + CompositeData row = groupMembers.get(new Object[] {nodeName}); + assertNotNull("Table does not contain row for node name " + nodeName, row); + assertEquals(nodeHostPort, row.get(ManagedBDBHAMessageStore.GRP_MEM_COL_NODE_HOST_PORT)); + } + } + + public void testRemoveRemoteNodeFromGroup() throws Exception + { + final Iterator brokerPortNumberIterator = getBrokerPortNumbers().iterator(); + final int brokerPortNumberToMakeObservation = brokerPortNumberIterator.next(); + final int brokerPortNumberToBeRemoved = brokerPortNumberIterator.next(); + final ManagedBDBHAMessageStore storeBean = getStoreBeanForNodeAtBrokerPort(brokerPortNumberToMakeObservation); + awaitAllNodesJoiningGroup(storeBean, NUMBER_OF_NODES); + + final String removedNodeName = _clusterCreator.getNodeNameForNodeAt(_clusterCreator.getBdbPortForBrokerPort(brokerPortNumberToBeRemoved)); + _clusterCreator.stopNode(brokerPortNumberToBeRemoved); + + storeBean.removeNodeFromGroup(removedNodeName); + + long limitTime = System.currentTimeMillis() + 5000; + while((NUMBER_OF_NODES == storeBean.getAllNodesInGroup().size()) && System.currentTimeMillis() < limitTime) + { + Thread.sleep(100l); + } + + int numberOfDataRowsAfterRemoval = storeBean.getAllNodesInGroup().size(); + assertEquals("Unexpected number of data rows after test", NUMBER_OF_NODES - 1, numberOfDataRowsAfterRemoval); + } + + public void testVirtualHostOperationsDeniedForNonMasterNode() throws Exception + { + final Connection activeConnection = getConnection(_brokerFailoverUrl); + final int inactiveBrokerPortNumber = _clusterCreator.getPortNumberOfAnInactiveBroker(activeConnection); + + ManagedBroker inactiveBroker = getManagedBrokerBeanForNodeAtBrokerPort(inactiveBrokerPortNumber); + + try + { + inactiveBroker.createNewQueue(getTestQueueName(), null, true); + fail("Exception not thrown"); + } + catch (Exception e) + { + String message = e.getMessage(); + assertEquals("The virtual host state of UNAVAILABLE does not permit this operation.", message); + } + + try + { + inactiveBroker.createNewExchange(getName(), "direct", true); + fail("Exception not thrown"); + } + catch (Exception e) + { + String message = e.getMessage(); + assertEquals("The virtual host state of UNAVAILABLE does not permit this operation.", message); + } + } + + public void testSetDesignatedPrimary() throws Exception + { + int brokerPort = _clusterCreator.getBrokerPortNumbersForNodes().iterator().next(); + final ManagedBDBHAMessageStore storeBean = getStoreBeanForNodeAtBrokerPort(brokerPort); + assertFalse("Unexpected designated primary before change", storeBean.getDesignatedPrimary()); + storeBean.setDesignatedPrimary(true); + long limit = System.currentTimeMillis() + 5000; + while(!storeBean.getDesignatedPrimary() && System.currentTimeMillis() < limit) + { + Thread.sleep(100l); + } + assertTrue("Unexpected designated primary after change", storeBean.getDesignatedPrimary()); + } + + public void testVirtualHostMbeanOnMasterTransfer() throws Exception + { + Connection connection = getConnection(_brokerFailoverUrl); + int activeBrokerPort = _clusterCreator.getBrokerPortNumberFromConnection(connection); + LOGGER.info("Active connection port " + activeBrokerPort); + connection.close(); + + Set ports = _clusterCreator.getBrokerPortNumbersForNodes(); + ports.remove(activeBrokerPort); + + int inactiveBrokerPort = ports.iterator().next(); + LOGGER.info("Update role attribute on inactive broker on port " + inactiveBrokerPort); + + ManagedBroker inactiveVirtualHostMBean = getManagedBrokerBeanForNodeAtBrokerPort(inactiveBrokerPort); + + try + { + inactiveVirtualHostMBean.createNewQueue(getTestQueueName(), null, true); + fail("Exception not thrown"); + } + catch (Exception e) + { + String message = e.getMessage(); + assertEquals("The virtual host state of UNAVAILABLE does not permit this operation.", message); + } + + Map attributes = _clusterCreator.getNodeAttributes(inactiveBrokerPort); + assertEquals("Inactive broker has unexpected role", "REPLICA", attributes.get(BDBHAVirtualHostNode.ROLE)); + _clusterCreator.setNodeAttributes(inactiveBrokerPort, Collections.singletonMap(BDBHAVirtualHostNode.ROLE, "MASTER")); + + _clusterCreator.awaitNodeToAttainRole(inactiveBrokerPort, "MASTER"); + + awaitVirtualHostAtNode(inactiveBrokerPort); + + ManagedBroker activeVirtualHostMBean = getManagedBrokerBeanForNodeAtBrokerPort(inactiveBrokerPort); + activeVirtualHostMBean.createNewQueue(getTestQueueName() + inactiveBrokerPort, null, true); + } + + public void awaitVirtualHostAtNode(int brokerPort) throws Exception + { + final long startTime = System.currentTimeMillis(); + Map data = Collections.emptyMap(); + String nodeName = _clusterCreator.getNodeNameForBrokerPort(brokerPort); + RestTestHelper restHelper = _clusterCreator.createRestTestHelper(brokerPort); + while(!State.ACTIVE.name().equals(data.get(VirtualHost.STATE)) && (System.currentTimeMillis() - startTime) < 30000) + { + LOGGER.debug("Awaiting virtual host '" + nodeName + "' to transit into active state"); + List> results= restHelper.getJsonAsList("virtualhost/" + nodeName + "/" + VIRTUAL_HOST); + if (results.size()== 1) + { + data = results.get(0); + } + + if (!State.ACTIVE.name().equals(data.get(VirtualHost.STATE))) + { + Thread.sleep(1000); + } + } + Assert.assertEquals("Virtual host is not active", State.ACTIVE.name(), data.get(VirtualHost.STATE)); + LOGGER.debug("Virtual host '" + nodeName + "' is in active state"); + } + + private ManagedBDBHAMessageStore getStoreBeanForNodeAtBrokerPort(final int brokerPortNumber) throws Exception + { + _jmxUtils.open(brokerPortNumber); + + return _jmxUtils.getManagedObject(ManagedBDBHAMessageStore.class, MANAGED_OBJECT_QUERY); + } + + private ManagedBroker getManagedBrokerBeanForNodeAtBrokerPort(final int brokerPortNumber) throws Exception + { + _jmxUtils.open(brokerPortNumber); + + return _jmxUtils.getManagedBroker(VIRTUAL_HOST); + } + + private void awaitAllNodesJoiningGroup(ManagedBDBHAMessageStore storeBean, int expectedNumberOfNodes) throws Exception + { + long totalTimeWaited = 0l; + long waitInterval = 100l; + long maxWaitTime = 10000; + + int currentNumberOfNodes = storeBean.getAllNodesInGroup().size(); + while (expectedNumberOfNodes > currentNumberOfNodes || totalTimeWaited > maxWaitTime) + { + LOGGER.debug("Still awaiting nodes to join group; expecting " + + expectedNumberOfNodes + " node(s) but only have " + currentNumberOfNodes + + " after " + totalTimeWaited + " ms."); + + totalTimeWaited += waitInterval; + Thread.sleep(waitInterval); + + currentNumberOfNodes = storeBean.getAllNodesInGroup().size(); + } + + assertEquals("Unexpected number of nodes in group after " + totalTimeWaited + " ms", + expectedNumberOfNodes ,currentNumberOfNodes); + } +} diff --git a/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/MultiNodeTest.java b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/MultiNodeTest.java new file mode 100644 index 0000000000..d6ba419de1 --- /dev/null +++ b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/MultiNodeTest.java @@ -0,0 +1,371 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store.berkeleydb.replication; + +import java.io.File; +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +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 org.apache.log4j.Logger; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.jms.ConnectionListener; +import org.apache.qpid.jms.ConnectionURL; +import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHAVirtualHostNode; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.test.utils.TestUtils; + +/** + * The HA black box tests test the BDB cluster as a opaque unit. Client connects to + * the cluster via a failover url + */ +public class MultiNodeTest extends QpidBrokerTestCase +{ + protected static final Logger LOGGER = Logger.getLogger(MultiNodeTest.class); + + private static final String VIRTUAL_HOST = "test"; + private static final int NUMBER_OF_NODES = 3; + + private final GroupCreator _groupCreator = new GroupCreator(this, VIRTUAL_HOST, NUMBER_OF_NODES); + + private FailoverAwaitingListener _failoverListener; + + /** Used when expectation is client will (re)-connect */ + private ConnectionURL _positiveFailoverUrl; + + /** Used when expectation is client will not (re)-connect */ + private ConnectionURL _negativeFailoverUrl; + + @Override + protected void setUp() throws Exception + { + _brokerType = BrokerType.SPAWNED; + + assertTrue(isJavaBroker()); + assertTrue(isBrokerStorePersistent()); + + setSystemProperty("java.util.logging.config.file", "etc" + File.separator + "log.properties"); + + _groupCreator.configureClusterNodes(); + + _positiveFailoverUrl = _groupCreator.getConnectionUrlForAllClusterNodes(); + _negativeFailoverUrl = _groupCreator.getConnectionUrlForAllClusterNodes(200, 0, 2); + + _groupCreator.startCluster(); + _failoverListener = new FailoverAwaitingListener(); + + super.setUp(); + } + + @Override + public void startBroker() throws Exception + { + // Don't start default broker provided by QBTC. + } + + public void testLossOfMasterNodeCausesClientToFailover() throws Exception + { + final Connection connection = getConnection(_positiveFailoverUrl); + + ((AMQConnection)connection).setConnectionListener(_failoverListener); + + final int activeBrokerPort = _groupCreator.getBrokerPortNumberFromConnection(connection); + LOGGER.info("Active connection port " + activeBrokerPort); + + _groupCreator.stopNode(activeBrokerPort); + LOGGER.info("Node is stopped"); + _failoverListener.awaitFailoverCompletion(20000); + LOGGER.info("Listener has finished"); + // any op to ensure connection remains + connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + public void testLossOfReplicaNodeDoesNotCauseClientToFailover() throws Exception + { + final Connection connection = getConnection(_positiveFailoverUrl); + + ((AMQConnection)connection).setConnectionListener(_failoverListener); + final int activeBrokerPort = _groupCreator.getBrokerPortNumberFromConnection(connection); + LOGGER.info("Active connection port " + activeBrokerPort); + final int inactiveBrokerPort = _groupCreator.getPortNumberOfAnInactiveBroker(connection); + + LOGGER.info("Stopping inactive broker on port " + inactiveBrokerPort); + + _groupCreator.stopNode(inactiveBrokerPort); + + _failoverListener.assertNoFailoverCompletionWithin(2000); + + assertProducingConsuming(connection); + } + + public void testLossOfQuorumCausesClientDisconnection() throws Exception + { + final Connection connection = getConnection(_negativeFailoverUrl); + + ((AMQConnection)connection).setConnectionListener(_failoverListener); + + Set ports = _groupCreator.getBrokerPortNumbersForNodes(); + + final int activeBrokerPort = _groupCreator.getBrokerPortNumberFromConnection(connection); + ports.remove(activeBrokerPort); + + // Stop all other nodes + for (Integer p : ports) + { + _groupCreator.stopNode(p); + } + + try + { + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Destination destination = session.createQueue(getTestQueueName()); + session.createConsumer(destination).close(); + fail("Exception not thrown - creating durable queue should fail without quorum"); + } + catch(JMSException jms) + { + // PASS + } + + // New connections should now fail as vhost will be unavailable + try + { + getConnection(_negativeFailoverUrl); + fail("Exception not thrown"); + } + catch (JMSException je) + { + // PASS + } + } + + public void testPersistentMessagesAvailableAfterFailover() throws Exception + { + final Connection connection = getConnection(_positiveFailoverUrl); + + ((AMQConnection)connection).setConnectionListener(_failoverListener); + + final int activeBrokerPort = _groupCreator.getBrokerPortNumberFromConnection(connection); + + Session producingSession = connection.createSession(true, Session.SESSION_TRANSACTED); + Destination queue = producingSession.createQueue(getTestQueueName()); + producingSession.createConsumer(queue).close(); + sendMessage(producingSession, queue, 10); + + _groupCreator.stopNode(activeBrokerPort); + LOGGER.info("Old master (broker port " + activeBrokerPort + ") is stopped"); + + _failoverListener.awaitFailoverCompletion(20000); + LOGGER.info("Failover has finished"); + + final int activeBrokerPortAfterFailover = _groupCreator.getBrokerPortNumberFromConnection(connection); + LOGGER.info("New master (broker port " + activeBrokerPort + ") after failover"); + + Session consumingSession = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer consumer = consumingSession.createConsumer(queue); + + connection.start(); + for(int i = 0; i < 10; i++) + { + Message m = consumer.receive(RECEIVE_TIMEOUT); + assertNotNull("Message " + i + " is not received", m); + assertEquals("Unexpected message received", i, m.getIntProperty(INDEX)); + } + consumingSession.commit(); + } + + public void testTransferMasterFromLocalNode() throws Exception + { + final Connection connection = getConnection(_positiveFailoverUrl); + + ((AMQConnection)connection).setConnectionListener(_failoverListener); + + final int activeBrokerPort = _groupCreator.getBrokerPortNumberFromConnection(connection); + LOGGER.info("Active connection port " + activeBrokerPort); + + final int inactiveBrokerPort = _groupCreator.getPortNumberOfAnInactiveBroker(connection); + LOGGER.info("Update role attribute on inactive broker on port " + inactiveBrokerPort); + + Map attributes = _groupCreator.getNodeAttributes(inactiveBrokerPort); + assertEquals("Inactive broker has unexpected role", "REPLICA", attributes.get(BDBHAVirtualHostNode.ROLE)); + _groupCreator.setNodeAttributes(inactiveBrokerPort, + Collections.singletonMap(BDBHAVirtualHostNode.ROLE, "MASTER")); + + _failoverListener.awaitFailoverCompletion(20000); + LOGGER.info("Listener has finished"); + + attributes = _groupCreator.getNodeAttributes(inactiveBrokerPort); + assertEquals("Inactive broker has unexpected role", "MASTER", attributes.get(BDBHAVirtualHostNode.ROLE)); + + assertProducingConsuming(connection); + + _groupCreator.awaitNodeToAttainRole(activeBrokerPort, "REPLICA"); + } + + public void testTransferMasterFromRemoteNode() throws Exception + { + final Connection connection = getConnection(_positiveFailoverUrl); + + ((AMQConnection)connection).setConnectionListener(_failoverListener); + + final int activeBrokerPort = _groupCreator.getBrokerPortNumberFromConnection(connection); + LOGGER.info("Active connection port " + activeBrokerPort); + + final int inactiveBrokerPort = _groupCreator.getPortNumberOfAnInactiveBroker(connection); + LOGGER.info("Update role attribute on inactive broker on port " + inactiveBrokerPort); + + _groupCreator.awaitNodeToAttainRole(activeBrokerPort, inactiveBrokerPort, "REPLICA"); + Map attributes = _groupCreator.getNodeAttributes(activeBrokerPort, inactiveBrokerPort); + assertEquals("Inactive broker has unexpected role", "REPLICA", attributes.get(BDBHAVirtualHostNode.ROLE)); + + _groupCreator.setNodeAttributes(activeBrokerPort, inactiveBrokerPort, Collections.singletonMap(BDBHAVirtualHostNode.ROLE, "MASTER")); + + _failoverListener.awaitFailoverCompletion(20000); + LOGGER.info("Listener has finished"); + + attributes = _groupCreator.getNodeAttributes(inactiveBrokerPort); + assertEquals("Inactive broker has unexpected role", "MASTER", attributes.get(BDBHAVirtualHostNode.ROLE)); + + assertProducingConsuming(connection); + + _groupCreator.awaitNodeToAttainRole(activeBrokerPort, "REPLICA"); + } + + public void testQuorumOverride() throws Exception + { + final Connection connection = getConnection(_positiveFailoverUrl); + + Set ports = _groupCreator.getBrokerPortNumbersForNodes(); + + final int activeBrokerPort = _groupCreator.getBrokerPortNumberFromConnection(connection); + ports.remove(activeBrokerPort); + + // Stop all other nodes + for (Integer p : ports) + { + _groupCreator.stopNode(p); + } + + Map attributes = _groupCreator.getNodeAttributes(activeBrokerPort); + assertEquals("Broker has unexpected quorum override", new Integer(0), attributes.get(BDBHAVirtualHostNode.QUORUM_OVERRIDE)); + _groupCreator.setNodeAttributes(activeBrokerPort, Collections.singletonMap(BDBHAVirtualHostNode.QUORUM_OVERRIDE, 1)); + + attributes = _groupCreator.getNodeAttributes(activeBrokerPort); + assertEquals("Broker has unexpected quorum override", new Integer(1), attributes.get(BDBHAVirtualHostNode.QUORUM_OVERRIDE)); + + assertProducingConsuming(connection); + } + + public void testPriority() throws Exception + { + final Connection connection = getConnection(_positiveFailoverUrl); + + ((AMQConnection)connection).setConnectionListener(_failoverListener); + + final int activeBrokerPort = _groupCreator.getBrokerPortNumberFromConnection(connection); + LOGGER.info("Active connection port " + activeBrokerPort); + + int priority = 1; + Integer highestPriorityBrokerPort = null; + Set ports = _groupCreator.getBrokerPortNumbersForNodes(); + for (Integer port : ports) + { + if (activeBrokerPort != port.intValue()) + { + priority = priority + 1; + highestPriorityBrokerPort = port; + _groupCreator.setNodeAttributes(port, port, Collections.singletonMap(BDBHAVirtualHostNode.PRIORITY, priority)); + Map attributes = _groupCreator.getNodeAttributes(port, port); + assertEquals("Broker has unexpected priority", priority, attributes.get(BDBHAVirtualHostNode.PRIORITY)); + } + } + + LOGGER.info("Broker on port " + highestPriorityBrokerPort + " has the highest priority of " + priority); + + LOGGER.info("Shutting down the MASTER"); + _groupCreator.stopNode(activeBrokerPort); + + _failoverListener.awaitFailoverCompletion(20000); + LOGGER.info("Listener has finished"); + + Map attributes = _groupCreator.getNodeAttributes(highestPriorityBrokerPort, highestPriorityBrokerPort); + assertEquals("Inactive broker has unexpected role", "MASTER", attributes.get(BDBHAVirtualHostNode.ROLE)); + + assertProducingConsuming(connection); + } + + private final class FailoverAwaitingListener implements ConnectionListener + { + private final CountDownLatch _failoverCompletionLatch = new CountDownLatch(1); + + @Override + public boolean preResubscribe() + { + return true; + } + + @Override + public boolean preFailover(boolean redirect) + { + return true; + } + + public void awaitFailoverCompletion(long delay) throws InterruptedException + { + if (!_failoverCompletionLatch.await(delay, TimeUnit.MILLISECONDS)) + { + LOGGER.warn("Test thread dump:\n\n" + TestUtils.dumpThreads() + "\n"); + } + assertEquals("Failover did not occur", 0, _failoverCompletionLatch.getCount()); + } + + public void assertNoFailoverCompletionWithin(long delay) throws InterruptedException + { + _failoverCompletionLatch.await(delay, TimeUnit.MILLISECONDS); + assertEquals("Failover occurred unexpectedly", 1L, _failoverCompletionLatch.getCount()); + } + + @Override + public void failoverComplete() + { + _failoverCompletionLatch.countDown(); + } + + @Override + public void bytesSent(long count) + { + } + + @Override + public void bytesReceived(long count) + { + } + } + +} diff --git a/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/TwoNodeTest.java b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/TwoNodeTest.java new file mode 100644 index 0000000000..0f8a1609de --- /dev/null +++ b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/TwoNodeTest.java @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store.berkeleydb.replication; + +import java.io.File; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.management.ObjectName; + +import org.apache.qpid.jms.ConnectionURL; +import org.apache.qpid.server.store.berkeleydb.jmx.ManagedBDBHAMessageStore; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class TwoNodeTest extends QpidBrokerTestCase +{ + private static final String VIRTUAL_HOST = "test"; + + private static final String MANAGED_OBJECT_QUERY = "org.apache.qpid:type=BDBHAMessageStore,name=" + ObjectName.quote(VIRTUAL_HOST); + private static final int NUMBER_OF_NODES = 2; + + private final GroupCreator _groupCreator = new GroupCreator(this, VIRTUAL_HOST, NUMBER_OF_NODES); + private final JMXTestUtils _jmxUtils = new JMXTestUtils(this); + + private ConnectionURL _brokerFailoverUrl; + + @Override + protected void setUp() throws Exception + { + _brokerType = BrokerType.SPAWNED; + + assertTrue(isJavaBroker()); + assertTrue(isBrokerStorePersistent()); + + super.setUp(); + } + + @Override + protected void tearDown() throws Exception + { + try + { + _jmxUtils.close(); + } + finally + { + super.tearDown(); + } + } + + @Override + public void startBroker() throws Exception + { + // Don't start default broker provided by QBTC. + } + + private void startCluster(boolean designedPrimary) throws Exception + { + setSystemProperty("java.util.logging.config.file", "etc" + File.separator + "log.properties"); + _groupCreator.configureClusterNodes(); + _groupCreator.setDesignatedPrimaryOnFirstBroker(designedPrimary); + _brokerFailoverUrl = _groupCreator.getConnectionUrlForAllClusterNodes(); + _groupCreator.startCluster(); + } + + public void testMasterDesignatedPrimaryCanBeRestartedWithoutReplica() throws Exception + { + startCluster(true); + final Connection initialConnection = getConnection(_brokerFailoverUrl); + int masterPort = _groupCreator.getBrokerPortNumberFromConnection(initialConnection); + assertProducingConsuming(initialConnection); + initialConnection.close(); + _groupCreator.stopCluster(); + _groupCreator.startNode(masterPort); + final Connection secondConnection = getConnection(_brokerFailoverUrl); + assertProducingConsuming(secondConnection); + secondConnection.close(); + } + + public void testClusterRestartWithoutDesignatedPrimary() throws Exception + { + startCluster(false); + final Connection initialConnection = getConnection(_brokerFailoverUrl); + assertProducingConsuming(initialConnection); + initialConnection.close(); + _groupCreator.stopCluster(); + _groupCreator.startClusterParallel(); + final Connection secondConnection = getConnection(_brokerFailoverUrl); + assertProducingConsuming(secondConnection); + secondConnection.close(); + } + + public void testDesignatedPrimaryContinuesAfterSecondaryStopped() throws Exception + { + startCluster(true); + _groupCreator.stopNode(_groupCreator.getBrokerPortNumberOfSecondaryNode()); + final Connection connection = getConnection(_brokerFailoverUrl); + assertNotNull("Expected to get a valid connection to primary", connection); + assertProducingConsuming(connection); + } + + public void testPersistentOperationsFailOnNonDesignatedPrimaryAfterSecondaryStopped() throws Exception + { + startCluster(false); + _groupCreator.stopNode(_groupCreator.getBrokerPortNumberOfSecondaryNode()); + + try + { + Connection connection = getConnection(_brokerFailoverUrl); + assertProducingConsuming(connection); + fail("Exception not thrown"); + } + catch(JMSException e) + { + // JMSException should be thrown either on getConnection, or produce/consume + // depending on whether the relative timing of the node discovering that the + // secondary has gone. + } + } + + public void testSecondaryDoesNotBecomePrimaryWhenDesignatedPrimaryStopped() throws Exception + { + startCluster(true); + _groupCreator.stopNode(_groupCreator.getBrokerPortNumberOfPrimary()); + + try + { + getConnection(_brokerFailoverUrl); + fail("Connection not expected"); + } + catch (JMSException e) + { + // PASS + } + } + + public void testInitialDesignatedPrimaryStateOfNodes() throws Exception + { + startCluster(true); + final ManagedBDBHAMessageStore primaryStoreBean = getStoreBeanForNodeAtBrokerPort(_groupCreator.getBrokerPortNumberOfPrimary()); + assertTrue("Expected primary node to be set as designated primary", primaryStoreBean.getDesignatedPrimary()); + + final ManagedBDBHAMessageStore secondaryStoreBean = getStoreBeanForNodeAtBrokerPort(_groupCreator.getBrokerPortNumberOfSecondaryNode()); + assertFalse("Expected secondary node to NOT be set as designated primary", secondaryStoreBean.getDesignatedPrimary()); + } + + public void testSecondaryDesignatedAsPrimaryAfterOriginalPrimaryStopped() throws Exception + { + startCluster(true); + final ManagedBDBHAMessageStore storeBean = getStoreBeanForNodeAtBrokerPort(_groupCreator.getBrokerPortNumberOfSecondaryNode()); + _groupCreator.stopNode(_groupCreator.getBrokerPortNumberOfPrimary()); + + assertFalse("Expected node to NOT be set as designated primary", storeBean.getDesignatedPrimary()); + storeBean.setDesignatedPrimary(true); + + long limit = System.currentTimeMillis() + 5000; + while( !storeBean.getDesignatedPrimary() && System.currentTimeMillis() < limit) + { + Thread.sleep(100); + } + assertTrue("Expected node to now be set as designated primary", storeBean.getDesignatedPrimary()); + + final Connection connection = getConnection(_brokerFailoverUrl); + assertNotNull("Expected to get a valid connection to new primary", connection); + assertProducingConsuming(connection); + } + + private ManagedBDBHAMessageStore getStoreBeanForNodeAtBrokerPort( + final int activeBrokerPortNumber) throws Exception + { + _jmxUtils.open(activeBrokerPortNumber); + + ManagedBDBHAMessageStore storeBean = _jmxUtils.getManagedObject(ManagedBDBHAMessageStore.class, MANAGED_OBJECT_QUERY); + return storeBean; + } + +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessage.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessage.java index c3fd0ba428..7801cf3d42 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessage.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessage.java @@ -62,9 +62,8 @@ public class InternalMessage extends AbstractServerMessageImpl() - { - @Override - public InternalMessageMetaData getMetaData() + return new StoredMessage() { - return metaData; - } + @Override + public InternalMessageMetaData getMetaData() + { + return metaData; + } - @Override - public long getMessageNumber() - { - return messageNumber; - } + @Override + public long getMessageNumber() + { + return messageNumber; + } - @Override - public void addContent(final int offsetInMessage, final ByteBuffer src) - { - throw new UnsupportedOperationException(); - } + @Override + public void addContent(final int offsetInMessage, final ByteBuffer src) + { + throw new UnsupportedOperationException(); + } - @Override - public int getContent(final int offsetInMessage, final ByteBuffer dst) - { - ByteBuffer buffer = ByteBuffer.wrap(bytes); - buffer.position(offsetInMessage); - buffer = buffer.slice(); - if(dst.remaining() < buffer.remaining()) + @Override + public int getContent(final int offsetInMessage, final ByteBuffer dst) { - buffer.limit(dst.remaining()); + ByteBuffer buffer = ByteBuffer.wrap(bytes); + buffer.position(offsetInMessage); + buffer = buffer.slice(); + if (dst.remaining() < buffer.remaining()) + { + buffer.limit(dst.remaining()); + } + int pos = dst.position(); + dst.put(buffer); + return dst.position() - pos; } - int pos = dst.position(); - dst.put(buffer); - return dst.position()-pos; - } - @Override - public ByteBuffer getContent(final int offsetInMessage, final int size) - { - return ByteBuffer.wrap(bytes,offsetInMessage,size); - } + @Override + public ByteBuffer getContent(final int offsetInMessage, final int size) + { + return ByteBuffer.wrap(bytes, offsetInMessage, size); + } - @Override - public void remove() - { - throw new UnsupportedOperationException(); - } + @Override + public void remove() + { + throw new UnsupportedOperationException(); + } - @Override - public boolean isInMemory() - { - return true; - } + @Override + public boolean isInMemory() + { + return true; + } - @Override - public boolean flowToDisk() - { - return false; - } - }; + @Override + public boolean flowToDisk() + { + return false; + } + }; + } } catch (IOException e) { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessageMetaDataType.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessageMetaDataType.java index 613d4d15d8..7fc13fb40b 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessageMetaDataType.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/message/internal/InternalMessageMetaDataType.java @@ -46,9 +46,8 @@ public class InternalMessageMetaDataType implements MessageMetaDataType> extends o String STORE_PATH = "storePath"; - @ManagedAttribute(mandatory = true) + @ManagedAttribute(mandatory = true, defaultValue = "${qpid.work_dir}${file.separator}${this:name}${file.separator}config") String getStorePath(); } diff --git a/qpid/java/broker-core/src/main/resources/initial-config.json b/qpid/java/broker-core/src/main/resources/initial-config.json index 74aedd14af..9f1f779559 100644 --- a/qpid/java/broker-core/src/main/resources/initial-config.json +++ b/qpid/java/broker-core/src/main/resources/initial-config.json @@ -55,9 +55,8 @@ "virtualhostnodes" : [ { "name" : "default", "type" : "JSON", - "storePath" : "${qpid.work_dir}${file.separator}default${file.separator}config", "context" : { - "virtualhostBlueprint" : "{ \"type\" : \"DERBY\", \"storePath\" : \"${json:qpid.work_dir}${json:file.separator}default${json:file.separator}messages\" }" + "virtualhostBlueprint" : "{ \"type\" : \"DERBY\" }" } } ], "plugins" : [ { diff --git a/qpid/java/broker-plugins/derby-store/src/main/java/org/apache/qpid/server/virtualhost/derby/DerbyVirtualHost.java b/qpid/java/broker-plugins/derby-store/src/main/java/org/apache/qpid/server/virtualhost/derby/DerbyVirtualHost.java index 9411d7906d..4935d5e707 100644 --- a/qpid/java/broker-plugins/derby-store/src/main/java/org/apache/qpid/server/virtualhost/derby/DerbyVirtualHost.java +++ b/qpid/java/broker-plugins/derby-store/src/main/java/org/apache/qpid/server/virtualhost/derby/DerbyVirtualHost.java @@ -29,7 +29,7 @@ public interface DerbyVirtualHost> extends Virtual { String STORE_PATH = "storePath"; - @ManagedAttribute(mandatory = true) + @ManagedAttribute(mandatory = true, defaultValue = "${qpid.work_dir}${file.separator}${this:name}${file.separator}messages") String getStorePath(); @ManagedAttribute(mandatory = true, defaultValue = "0") diff --git a/qpid/java/broker-plugins/derby-store/src/main/java/org/apache/qpid/server/virtualhostnode/derby/DerbyVirtualHostNode.java b/qpid/java/broker-plugins/derby-store/src/main/java/org/apache/qpid/server/virtualhostnode/derby/DerbyVirtualHostNode.java index 3b31f4e7e0..81a9167924 100644 --- a/qpid/java/broker-plugins/derby-store/src/main/java/org/apache/qpid/server/virtualhostnode/derby/DerbyVirtualHostNode.java +++ b/qpid/java/broker-plugins/derby-store/src/main/java/org/apache/qpid/server/virtualhostnode/derby/DerbyVirtualHostNode.java @@ -26,6 +26,6 @@ public interface DerbyVirtualHostNode> extends { String STORE_PATH = "storePath"; - @ManagedAttribute(mandatory = true) + @ManagedAttribute(mandatory = true, defaultValue = "${qpid.work_dir}${file.separator}${this:name}${file.separator}config") String getStorePath(); } diff --git a/qpid/java/broker-plugins/derby-store/src/main/java/resources/virtualhostnode/derby/add.html b/qpid/java/broker-plugins/derby-store/src/main/java/resources/virtualhostnode/derby/add.html index fa4f0d64f1..0ec1e89c24 100644 --- a/qpid/java/broker-plugins/derby-store/src/main/java/resources/virtualhostnode/derby/add.html +++ b/qpid/java/broker-plugins/derby-store/src/main/java/resources/virtualhostnode/derby/add.html @@ -20,15 +20,13 @@ -->
-
Store path*:
+
Store path:
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java index 613218f2fc..d29144f09b 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java @@ -111,6 +111,9 @@ public class HttpManagement extends AbstractPluginAdapter implem @ManagedAttributeField private int _sessionTimeout; + @ManagedAttributeField + private boolean _compressResponses; + private boolean _allowPortActivation; @ManagedObjectFactoryConstructor @@ -476,6 +479,12 @@ public class HttpManagement extends AbstractPluginAdapter implem return _httpBasicAuthenticationEnabled; } + @Override + public boolean isCompressResponses() + { + return _compressResponses; + } + @Override public AuthenticationProvider getAuthenticationProvider(SocketAddress localAddress) { diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java index aff9f3a7e2..9eef1a6e5c 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementConfiguration.java @@ -29,6 +29,7 @@ import org.apache.qpid.server.model.Plugin; public interface HttpManagementConfiguration> extends Plugin { + @ManagedAttribute( defaultValue = "true" ) boolean isHttpsSaslAuthenticationEnabled(); @@ -44,6 +45,13 @@ public interface HttpManagementConfiguration getBroker(ServletContext servletContext) { return (Broker) servletContext.getAttribute(ATTR_BROKER); @@ -219,5 +230,42 @@ public class HttpManagementUtil return null; } + public static Writer getOutputWriter(final HttpServletRequest request, final HttpServletResponse response) + throws IOException + { + return getOutputWriter(request, response, getManagementConfiguration(request.getServletContext())); + } + + public static Writer getOutputWriter(final HttpServletRequest request, final HttpServletResponse response, HttpManagementConfiguration managementConfiguration) + throws IOException + { + Writer writer; + writer = new BufferedWriter(new OutputStreamWriter(getOutputStream(request,response, managementConfiguration))); + return writer; + } + + public static OutputStream getOutputStream(final HttpServletRequest request, final HttpServletResponse response) + throws IOException + { + return getOutputStream(request, response, getManagementConfiguration(request.getServletContext())); + } + + public static OutputStream getOutputStream(final HttpServletRequest request, final HttpServletResponse response, HttpManagementConfiguration managementConfiguration) + throws IOException + { + OutputStream outputStream; + if(managementConfiguration.isCompressResponses() + && Collections.list(request.getHeaderNames()).contains(ACCEPT_ENCODING_HEADER) + && request.getHeader(ACCEPT_ENCODING_HEADER).contains(GZIP_CONTENT_ENCODING)) + { + outputStream = new GZIPOutputStream(response.getOutputStream()); + response.setHeader(CONTENT_ENCODING_HEADER, GZIP_CONTENT_ENCODING); + } + else + { + outputStream = response.getOutputStream(); + } + return outputStream; + } } diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/DefinedFileServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/DefinedFileServlet.java index e6ae47dcff..d8f8e4e4b0 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/DefinedFileServlet.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/DefinedFileServlet.java @@ -18,14 +18,16 @@ package org.apache.qpid.server.management.plugin.servlet; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import javax.servlet.ServletConfig; import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.qpid.server.management.plugin.HttpManagementUtil; + public class DefinedFileServlet extends HttpServlet { @@ -57,23 +59,25 @@ public class DefinedFileServlet extends HttpServlet @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - final ServletOutputStream output = response.getOutputStream(); - InputStream fileInput = getClass().getResourceAsStream("/resources/"+_filename); - - if(fileInput != null) + try (OutputStream output = HttpManagementUtil.getOutputStream(request, response)) { - byte[] buffer = new byte[1024]; - response.setStatus(HttpServletResponse.SC_OK); - int read = 0; + InputStream fileInput = getClass().getResourceAsStream("/resources/" + _filename); - while((read = fileInput.read(buffer)) > 0) + if (fileInput != null) { - output.write(buffer, 0, read); + byte[] buffer = new byte[1024]; + response.setStatus(HttpServletResponse.SC_OK); + int read = 0; + + while ((read = fileInput.read(buffer)) > 0) + { + output.write(buffer, 0, read); + } + } + else + { + response.sendError(HttpServletResponse.SC_NOT_FOUND, "unknown file: " + _filename); } - } - else - { - response.sendError(HttpServletResponse.SC_NOT_FOUND, "unknown file: "+ _filename); } } } diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/FileServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/FileServlet.java index 618aaed319..3eab80dbd8 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/FileServlet.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/FileServlet.java @@ -22,17 +22,19 @@ package org.apache.qpid.server.management.plugin.servlet; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.net.URL; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.qpid.server.management.plugin.HttpManagementUtil; + public class FileServlet extends HttpServlet { private static final String RESOURCES_PREFIX = "/resources"; @@ -97,7 +99,7 @@ public class FileServlet extends HttpServlet { byte[] buffer = new byte[1024]; int read = 0; - ServletOutputStream output = response.getOutputStream(); + OutputStream output = HttpManagementUtil.getOutputStream(request, response); try { while((read = fileInput.read(buffer)) != -1) diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java index a9e80db3bf..c05814bb9c 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java @@ -21,7 +21,8 @@ package org.apache.qpid.server.management.plugin.servlet.rest; import java.io.IOException; -import java.io.PrintWriter; +import java.io.OutputStream; +import java.io.Writer; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; @@ -32,16 +33,18 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import org.apache.log4j.Logger; -import org.apache.qpid.server.management.plugin.HttpManagementConfiguration; -import org.apache.qpid.server.management.plugin.HttpManagementUtil; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.util.ConnectionScopedRuntimeException; import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.map.JsonMappingException; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.SerializationConfig; +import org.apache.qpid.server.management.plugin.HttpManagementConfiguration; +import org.apache.qpid.server.management.plugin.HttpManagementUtil; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.util.ConnectionScopedRuntimeException; + public abstract class AbstractServlet extends HttpServlet { private static final Logger LOGGER = Logger.getLogger(AbstractServlet.class); @@ -137,6 +140,18 @@ public abstract class AbstractServlet extends HttpServlet ); } + public Writer getOutputWriter(final HttpServletRequest request, final HttpServletResponse response) + throws IOException + { + return HttpManagementUtil.getOutputWriter(request, response, _managementConfiguration); + } + + public OutputStream getOutputStream(final HttpServletRequest request, final HttpServletResponse response) + throws IOException + { + return HttpManagementUtil.getOutputStream(request, response, _managementConfiguration); + } + /** * Performs the PUT action as the logged-in {@link Subject}. * Subclasses commonly override this method @@ -247,7 +262,7 @@ public abstract class AbstractServlet extends HttpServlet } } - protected void sendJsonResponse(Object object, HttpServletResponse response) throws IOException, + protected void sendJsonResponse(Object object, HttpServletRequest request, HttpServletResponse response) throws IOException, JsonGenerationException, JsonMappingException { response.setStatus(HttpServletResponse.SC_OK); @@ -257,7 +272,7 @@ public abstract class AbstractServlet extends HttpServlet response.setDateHeader ("Expires", 0); response.setContentType("application/json"); - final PrintWriter writer = response.getWriter(); + final Writer writer = getOutputWriter(request, response); ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); mapper.writeValue(writer, object); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/HelperServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/HelperServlet.java index 367ed5a2a9..cb41fd9203 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/HelperServlet.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/HelperServlet.java @@ -20,7 +20,6 @@ */ package org.apache.qpid.server.management.plugin.servlet.rest; -import java.io.BufferedWriter; import java.io.IOException; import java.io.Writer; import java.util.Enumeration; @@ -31,14 +30,15 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.SerializationConfig; + import org.apache.qpid.server.management.plugin.servlet.rest.action.ListAccessControlProviderAttributes; import org.apache.qpid.server.management.plugin.servlet.rest.action.ListAuthenticationProviderAttributes; import org.apache.qpid.server.management.plugin.servlet.rest.action.ListBrokerAttribute; import org.apache.qpid.server.management.plugin.servlet.rest.action.ListGroupProviderAttributes; import org.apache.qpid.server.management.plugin.servlet.rest.action.ListTimeZones; import org.apache.qpid.server.model.Broker; -import org.codehaus.jackson.map.ObjectMapper; -import org.codehaus.jackson.map.SerializationConfig; public class HelperServlet extends AbstractServlet { @@ -122,7 +122,7 @@ public class HelperServlet extends AbstractServlet return; } response.setContentType("application/json"); - final Writer writer = new BufferedWriter(response.getWriter()); + final Writer writer = getOutputWriter(request, response); _mapper.writeValue(writer, output); response.setStatus(HttpServletResponse.SC_OK); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogFileListingServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogFileListingServlet.java index 8b88e51e9c..a7889e4890 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogFileListingServlet.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogFileListingServlet.java @@ -18,7 +18,7 @@ package org.apache.qpid.server.management.plugin.servlet.rest; import java.io.IOException; -import java.io.PrintWriter; +import java.io.Writer; import java.util.Collections; import java.util.List; @@ -27,11 +27,12 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.LogManager; -import org.apache.qpid.server.management.plugin.log.LogFileDetails; -import org.apache.qpid.server.management.plugin.log.LogFileHelper; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.SerializationConfig; +import org.apache.qpid.server.management.plugin.log.LogFileDetails; +import org.apache.qpid.server.management.plugin.log.LogFileHelper; + public class LogFileListingServlet extends AbstractServlet { private static final long serialVersionUID = 1L; @@ -56,7 +57,7 @@ public class LogFileListingServlet extends AbstractServlet response.setContentType("application/json"); response.setStatus(HttpServletResponse.SC_OK); - final PrintWriter writer = response.getWriter(); + final Writer writer = getOutputWriter(request, response); ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); mapper.writeValue(writer, logFiles); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java index 35523ddf0f..b9d58c8868 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java @@ -17,18 +17,21 @@ package org.apache.qpid.server.management.plugin.servlet.rest; import java.io.IOException; -import java.io.PrintWriter; +import java.io.Writer; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; + import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.qpid.server.logging.LogRecorder; + import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.SerializationConfig; +import org.apache.qpid.server.logging.LogRecorder; + public class LogRecordsServlet extends AbstractServlet { private static final long serialVersionUID = 2L; @@ -77,7 +80,7 @@ public class LogRecordsServlet extends AbstractServlet } } - final PrintWriter writer = response.getWriter(); + final Writer writer = getOutputWriter(request,response); ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); mapper.writeValue(writer, logRecords); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LoggedOnUserPreferencesServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LoggedOnUserPreferencesServlet.java index 29cc881be7..25d109ba29 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LoggedOnUserPreferencesServlet.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LoggedOnUserPreferencesServlet.java @@ -33,11 +33,12 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.codehaus.jackson.map.ObjectMapper; + import org.apache.qpid.server.management.plugin.HttpManagementUtil; import org.apache.qpid.server.model.AuthenticationProvider; import org.apache.qpid.server.model.PreferencesProvider; import org.apache.qpid.server.security.auth.AuthenticatedPrincipal; -import org.codehaus.jackson.map.ObjectMapper; public class LoggedOnUserPreferencesServlet extends AbstractServlet { @@ -59,7 +60,7 @@ public class LoggedOnUserPreferencesServlet extends AbstractServlet { preferences = Collections.emptyMap(); } - sendJsonResponse(preferences, response); + sendJsonResponse(preferences, request, response); } /* @@ -88,7 +89,7 @@ public class LoggedOnUserPreferencesServlet extends AbstractServlet { preferences = Collections.emptyMap(); } - sendJsonResponse(preferences, response); + sendJsonResponse(preferences, request, response); } /* @@ -115,7 +116,7 @@ public class LoggedOnUserPreferencesServlet extends AbstractServlet { preferences = Collections.emptyMap(); } - sendJsonResponse(preferences, response); + sendJsonResponse(preferences, request, response); } private String getAuthenticatedUserName(HttpServletRequest request) diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java index ef33a240a9..db58e49eeb 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java @@ -60,7 +60,7 @@ public class MessageContentServlet extends AbstractServlet { response.setContentType(finder.getMimeType()); response.setContentLength((int) finder.getSize()); - response.getOutputStream().write(finder.getContent()); + getOutputStream(request, response).write(finder.getContent()); } diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java index 8c77876e1a..8de74d189b 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java @@ -18,7 +18,7 @@ package org.apache.qpid.server.management.plugin.servlet.rest; import java.io.IOException; -import java.io.PrintWriter; +import java.io.Writer; import java.security.AccessControlException; import java.util.ArrayList; import java.util.HashMap; @@ -85,7 +85,7 @@ public class MessageServlet extends AbstractServlet response.setDateHeader ("Expires", 0); response.setContentType("application/json"); - final PrintWriter writer = response.getWriter(); + final Writer writer = getOutputWriter(request,response); ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); mapper.writeValue(writer, messageFinder.getMessageObject()); @@ -119,7 +119,7 @@ public class MessageServlet extends AbstractServlet response.setHeader("Pragma","no-cache"); response.setDateHeader ("Expires", 0); - final PrintWriter writer = response.getWriter(); + final Writer writer = getOutputWriter(request,response); ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); mapper.writeValue(writer, messages); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MetaDataServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MetaDataServlet.java index 55c2bf6901..c84eb3200b 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MetaDataServlet.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MetaDataServlet.java @@ -20,7 +20,6 @@ */ package org.apache.qpid.server.management.plugin.servlet.rest; -import java.io.BufferedWriter; import java.io.IOException; import java.io.Writer; import java.util.Collection; @@ -69,7 +68,7 @@ public class MetaDataServlet extends AbstractServlet classToDataMap.put(clazz.getSimpleName(), processCategory(clazz)); } - final Writer writer = new BufferedWriter(response.getWriter()); + final Writer writer = getOutputWriter(request, response); ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); mapper.writeValue(writer, classToDataMap); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java index 57b3df8050..d96802cc8b 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java @@ -16,7 +16,6 @@ */ package org.apache.qpid.server.management.plugin.servlet.rest; -import java.io.BufferedWriter; import java.io.IOException; import java.io.Writer; import java.security.AccessControlException; @@ -327,7 +326,7 @@ public class RestServlet extends AbstractServlet depth, actuals, includeSystemContext)); } - final Writer writer = new BufferedWriter(response.getWriter()); + Writer writer = getOutputWriter(request, response); ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); mapper.writeValue(writer, output); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java index 81d67caf96..3dcd4a3978 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java @@ -21,7 +21,7 @@ package org.apache.qpid.server.management.plugin.servlet.rest; import java.io.IOException; -import java.io.PrintWriter; +import java.io.Writer; import java.net.SocketAddress; import java.security.Principal; import java.security.SecureRandom; @@ -100,7 +100,7 @@ public class SaslServlet extends AbstractServlet outputObject.put("mechanisms", (Object) mechanisms); - final PrintWriter writer = response.getWriter(); + final Writer writer = getOutputWriter(request, response); ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); @@ -268,7 +268,7 @@ public class SaslServlet extends AbstractServlet Map outputObject = new LinkedHashMap(); outputObject.put("challenge", new String(Base64.encodeBase64(challenge))); - final PrintWriter writer = response.getWriter(); + final Writer writer = getOutputWriter(request, response); ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); @@ -290,7 +290,7 @@ public class SaslServlet extends AbstractServlet outputObject.put("id", id); outputObject.put("challenge", new String(Base64.encodeBase64(challenge))); - final PrintWriter writer = response.getWriter(); + final Writer writer = getOutputWriter(request, response); ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java index 907610c8d2..7508aa2d0b 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java @@ -17,7 +17,7 @@ package org.apache.qpid.server.management.plugin.servlet.rest; import java.io.IOException; -import java.io.PrintWriter; +import java.io.Writer; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; @@ -55,7 +55,7 @@ public class StructureServlet extends AbstractServlet Map structure = generateStructure(getBroker(), Broker.class); - final PrintWriter writer = response.getWriter(); + final Writer writer = getOutputWriter(request, response); ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); mapper.writeValue(writer, structure); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/UserPreferencesServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/UserPreferencesServlet.java index 01657b131d..b782022986 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/UserPreferencesServlet.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/UserPreferencesServlet.java @@ -35,6 +35,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; + import org.apache.qpid.server.model.AuthenticationProvider; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.PreferencesProvider; @@ -53,15 +54,15 @@ public class UserPreferencesServlet extends AbstractServlet String[] pathElements = getPathInfoElements(request); if (pathElements != null && pathElements.length > 1) { - getUserPreferences(pathElements[0], pathElements[1], response); + getUserPreferences(pathElements[0], pathElements[1], request, response); } else { - getUserList(pathElements, response); + getUserList(pathElements, request, response); } } - private void getUserPreferences(String authenticationProviderName, String userId, HttpServletResponse response) + private void getUserPreferences(String authenticationProviderName, String userId, HttpServletRequest request, HttpServletResponse response) throws IOException { try @@ -83,10 +84,10 @@ public class UserPreferencesServlet extends AbstractServlet } preferences = preferencesProvider.getPreferences(userId); - sendJsonResponse(preferences, response); + sendJsonResponse(preferences, request, response); } - private void getUserList(String[] pathElements, HttpServletResponse response) throws IOException + private void getUserList(String[] pathElements, HttpServletRequest request, HttpServletResponse response) throws IOException { List> users = null; try @@ -98,7 +99,7 @@ public class UserPreferencesServlet extends AbstractServlet LOGGER.debug("Bad preferences request", e); response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage()); } - sendJsonResponse(users, response); + sendJsonResponse(users, request, response); } private PreferencesProvider getPreferencesProvider(String authenticationProviderName) diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js index 8cc3e76b58..51a6c761f1 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js @@ -349,10 +349,14 @@ define(["dojo/_base/xhr", gotoButton: true, maxPageStep: 4, position: "bottom" - }, - indirectSelection: true + } }}; + function isActiveVH(item) + { + return item && item.virtualhosts && item.virtualhosts[0].state=="ACTIVE"; + } + that.vhostsGrid = new UpdatableStore(that.brokerData.virtualhostnodes, query(".broker-virtualhosts")[0], [ @@ -373,20 +377,27 @@ define(["dojo/_base/xhr", formatter: function(item){ return item && item.virtualhosts? item.virtualhosts[0].type: "N/A"; } - }, - { name: "Connections", field: "_item", width: "10%", + }, + { name: "Connections", field: "_item", width: "8%", formatter: function(item){ - return item && item.virtualhosts? item.virtualhosts[0].statistics.connectionCount: 0; + return isActiveVH(item)? item.virtualhosts[0].statistics.connectionCount: "N/A"; } }, - { name: "Queues", field: "_item", width: "10%", + { name: "Queues", field: "_item", width: "8%", formatter: function(item){ - return item && item.virtualhosts? item.virtualhosts[0].statistics.queueCount: 0; + return isActiveVH(item)? item.virtualhosts[0].statistics.queueCount: "N/A"; } }, - { name: "Exchanges", field: "_item", width: "10%", + { name: "Exchanges", field: "_item", width: "8%", formatter: function(item){ - return item && item.virtualhosts? item.virtualhosts[0].statistics.exchangeCount: 0; + return isActiveVH(item)? item.virtualhosts[0].statistics.exchangeCount: "N/A"; + } + }, + { + name: "Default", field: "_item", width: "6%", + formatter: function(item){ + var val = item && item.virtualhosts? item.virtualhosts[0].name: null; + return ""; } } ], function(obj) { @@ -424,6 +435,7 @@ define(["dojo/_base/xhr", if (data.length == 1) { that.showVirtualHost(data[0], brokerObj); + that.vhostsGrid.grid.selection.clear(); } }); @@ -434,6 +446,7 @@ define(["dojo/_base/xhr", { var item = data[0]; that.controller.show("virtualhostnode", item.name, brokerObj, item.id); + that.vhostsGrid.grid.selection.clear(); } } ); @@ -457,6 +470,7 @@ define(["dojo/_base/xhr", var item = data[0]; util.sendRequest("api/latest/virtualhostnode/" + encodeURIComponent(item.name), "PUT", {desiredState: "ACTIVE"}); + that.vhostsGrid.grid.selection.clear(); } }); @@ -473,6 +487,7 @@ define(["dojo/_base/xhr", { util.sendRequest("api/latest/virtualhostnode/" + encodeURIComponent(item.name), "PUT", {desiredState: "STOPPED"}); + that.vhostsGrid.grid.selection.clear(); } } }); @@ -486,6 +501,7 @@ define(["dojo/_base/xhr", var host = item.virtualhosts[0]; util.sendRequest("api/latest/virtualhost/" + encodeURIComponent(item.name) + "/" + encodeURIComponent(host.name), "PUT", {desiredState: "ACTIVE"}); + that.vhostsGrid.grid.selection.clear(); } }); @@ -501,11 +517,12 @@ define(["dojo/_base/xhr", { util.sendRequest("api/latest/virtualhost/" + encodeURIComponent(item.name) + "/" + encodeURIComponent(host.name), "PUT", {desiredState: "STOPPED"}); + that.vhostsGrid.grid.selection.clear(); } } }); - - gridProperties.selectionMode="extended"; + gridProperties.selectionMode = "extended"; + gridProperties.plugins.indirectSelection = true; that.portsGrid = new UpdatableStore(that.brokerData.ports, query(".broker-ports")[0], diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementhttp.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementhttp.js index efe6f4eeff..07c5c25171 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementhttp.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/plugin/managementhttp.js @@ -123,7 +123,16 @@ define(["dojo/_base/xhr", name: "sessionTimeout" }); } + }, { + name: "compressResponses", + createWidget: function(plugin) { + return new dijit.form.CheckBox({ + required: false, + checked: plugin.compressResponses, + label: "Compress responses:", + name: "compressResponses"}); } + } ]; var data = this.managementHttpUpdater.pluginData; util.showSetAttributesDialog( @@ -143,6 +152,8 @@ define(["dojo/_base/xhr", this.sessionTimeout = query(".sessionTimeout", node)[0]; this.httpsSaslAuthenticationEnabled = query(".httpsSaslAuthenticationEnabled", node)[0]; this.httpSaslAuthenticationEnabled = query(".httpSaslAuthenticationEnabled", node)[0]; + this.compressResponses = query(".compressResponses", node)[0]; + } ManagementHttpUpdater.prototype.update = function(syncRequest) @@ -161,6 +172,7 @@ define(["dojo/_base/xhr", that.httpsBasicAuthenticationEnabled.innerHTML = showBoolean(that.pluginData.httpsBasicAuthenticationEnabled); that.httpsSaslAuthenticationEnabled.innerHTML = showBoolean(that.pluginData.httpsSaslAuthenticationEnabled); that.httpSaslAuthenticationEnabled.innerHTML = showBoolean(that.pluginData.httpSaslAuthenticationEnabled); + that.compressResponses.innerHTML = showBoolean(that.pluginData.compressResponses); that.sessionTimeout.innerHTML = that.pluginData.sessionTimeout; }); diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/plugin/showManagementHttp.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/plugin/showManagementHttp.html index e91120e43b..b12869981d 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/plugin/showManagementHttp.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/plugin/showManagementHttp.html @@ -40,6 +40,10 @@
Session timeout (s):
+
+
Compress content:
+
+

diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/sizemonitoring/add.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/sizemonitoring/add.html index 7cf789e520..88ca0b3807 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/sizemonitoring/add.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/sizemonitoring/add.html @@ -19,15 +19,13 @@
-
Message store path*:
+
Message store path:
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/sizemonitoring/edit.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/sizemonitoring/edit.html index 9e240a83c4..60b8faef56 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/sizemonitoring/edit.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhost/sizemonitoring/edit.html @@ -20,15 +20,13 @@
-
Message store path*:
+
Message store path:
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhostnode/filebased/edit.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhostnode/filebased/edit.html index a132444268..2f0d72fe9a 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhostnode/filebased/edit.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhostnode/filebased/edit.html @@ -20,15 +20,13 @@
-
Configuration store path*:
+
Configuration store path:
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhostnode/json/add.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhostnode/json/add.html index 622eb17b63..ec3ef79fa0 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhostnode/json/add.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/virtualhostnode/json/add.html @@ -20,15 +20,13 @@ -->
-
Store path*:
+
Store path:
diff --git a/qpid/java/client/example/src/main/java/org/apache/qpid/example/Hello.java b/qpid/java/client/example/src/main/java/org/apache/qpid/example/Hello.java index 949ee4dac6..7e956698d1 100644 --- a/qpid/java/client/example/src/main/java/org/apache/qpid/example/Hello.java +++ b/qpid/java/client/example/src/main/java/org/apache/qpid/example/Hello.java @@ -21,10 +21,18 @@ package org.apache.qpid.example; -import javax.jms.*; +import java.io.InputStream; +import java.util.Properties; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; import javax.naming.Context; import javax.naming.InitialContext; -import java.util.Properties; public class Hello @@ -42,9 +50,10 @@ public class Hello private void runTest() { - try { + try (InputStream resourceAsStream = this.getClass().getResourceAsStream("hello.properties")) + { Properties properties = new Properties(); - properties.load(this.getClass().getResourceAsStream("hello.properties")); + properties.load(resourceAsStream); Context context = new InitialContext(properties); ConnectionFactory connectionFactory = (ConnectionFactory) context.lookup("qpidConnectionfactory"); diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/AbstractRunner.java b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/AbstractRunner.java index 9e865010f8..1192a2729a 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/AbstractRunner.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/disttest/AbstractRunner.java @@ -42,10 +42,10 @@ public class AbstractRunner { Context context = null; - try + try(FileInputStream inStream = new FileInputStream(getJndiConfig())) { final Properties properties = new Properties(); - properties.load(new FileInputStream(getJndiConfig())); + properties.load(inStream); context = new InitialContext(properties); } catch (Exception e) @@ -71,4 +71,4 @@ public class AbstractRunner { return _cliOptions; } -} \ No newline at end of file +} diff --git a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/ConfigFileTestHelper.java b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/ConfigFileTestHelper.java deleted file mode 100644 index a4f4cab018..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/ConfigFileTestHelper.java +++ /dev/null @@ -1,48 +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.systest.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 ConfigFileTestHelper -{ - public static Reader getConfigFileReader(Class testClass, String resourceName) - { - InputStream inputStream = testClass.getResourceAsStream(resourceName); - if(inputStream == null) - { - throw new RuntimeException("Can't find resource " + resourceName + " using classloader of class " + testClass); - } - Reader reader = new InputStreamReader(inputStream); - return reader; - } - - public static Config getConfigFromResource(Class testClass, String resourceName) - { - ConfigReader configReader = new ConfigReader(); - Config config = configReader.readConfig(getConfigFileReader(testClass, resourceName)); - return config; - } -} diff --git a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/DistributedTestSystemTestBase.java b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/DistributedTestSystemTestBase.java deleted file mode 100644 index 96daf64526..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/DistributedTestSystemTestBase.java +++ /dev/null @@ -1,72 +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.systest.disttest; - -import java.util.Properties; - -import javax.jms.Connection; -import javax.jms.ConnectionFactory; -import javax.jms.JMSException; -import javax.naming.Context; -import javax.naming.InitialContext; -import javax.naming.NamingException; - -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class DistributedTestSystemTestBase extends QpidBrokerTestCase -{ - protected Context _context; - - protected Connection _connection; - - @Override - protected void setUp() throws Exception - { - super.setUp(); - - final Properties properties = new Properties(); - properties.load(DistributedTestSystemTestBase.class.getResourceAsStream("perftests.systests.properties")); - _context = new InitialContext(properties); - - _connection = getConnection(); - _connection.start(); - } - - @Override - protected void tearDown() throws Exception - { - // no need to close connections - this is done by superclass - - super.tearDown(); - } - - public Context getContext() - { - return _context; - } - - @Override - public Connection getConnection() throws JMSException, NamingException - { - final ConnectionFactory connectionFactory = (ConnectionFactory) _context.lookup("connectionfactory"); - final Connection connection = connectionFactory.createConnection(); - _connections.add(connection); - return connection; - } -} diff --git a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/QpidQueueCreatorTest.java b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/QpidQueueCreatorTest.java deleted file mode 100644 index 59396d46c0..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/QpidQueueCreatorTest.java +++ /dev/null @@ -1,100 +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.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.controller.config.QueueConfig; -import org.apache.qpid.disttest.jms.QpidQueueCreator; - -public class QpidQueueCreatorTest extends DistributedTestSystemTestBase -{ - private static final Map EMPTY_ATTRIBUTES = Collections.emptyMap(); - - private static final boolean QUEUE_DURABILITY = true; - - private Connection _connection; - private QpidQueueCreator _creator; - private Session _session; - private List _configs; - private String _queueName; - - @Override - public void setUp() throws Exception - { - super.setUp(); - _connection = getConnection(); - _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - _creator = new QpidQueueCreator(); - _configs = new ArrayList(); - _queueName = "direct://amq.direct//" + getTestQueueName() + "?durable='" + QUEUE_DURABILITY + "'"; - } - - public void testCreateQueueWithoutAttributes() throws Exception - { - _configs.add(new QueueConfig(_queueName, QUEUE_DURABILITY, EMPTY_ATTRIBUTES)); - - assertQueueBound(_queueName, false); - - _creator.createQueues(_connection, _session, _configs); - - assertQueueBound(_queueName, true); - } - - public void testCreateWithAttributes() throws Exception - { - Map attributes = new HashMap(); - attributes.put("x-qpid-priorities", Integer.valueOf(5)); - _configs.add(new QueueConfig(_queueName, QUEUE_DURABILITY, attributes)); - - assertQueueBound(_queueName, false); - - _creator.createQueues(_connection, _session, _configs); - - assertQueueBound(_queueName, true); - } - - public void testDeleteQueues() throws Exception - { - _configs.add(new QueueConfig(_queueName, QUEUE_DURABILITY, EMPTY_ATTRIBUTES)); - - assertQueueBound(_queueName, false); - - _creator.createQueues(_connection, _session, _configs); - assertQueueBound(_queueName, true); - - _creator.deleteQueues(_connection, _session, _configs); - assertQueueBound(_queueName, false); - } - - private void assertQueueBound(String queueName, boolean isBound) throws Exception - { - AMQDestination destination = (AMQDestination)_session.createQueue(queueName); - assertEquals("Queue is not in expected bound state", isBound, ((AMQSession)_session).isQueueBound(destination)); - } -} diff --git a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/SystemTestConstants.java b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/SystemTestConstants.java deleted file mode 100644 index b06ab0c735..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/SystemTestConstants.java +++ /dev/null @@ -1,28 +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.systest.disttest; - -public abstract class SystemTestConstants -{ - public static final long REGISTRATION_TIMEOUT = 20000; - public static final long COMMAND_RESPONSE_TIMEOUT = 30000; - public static final long TEST_RESULT_TIMEOUT = 20000; - -} diff --git a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/BasicDistributedClientTest.java b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/BasicDistributedClientTest.java deleted file mode 100644 index d599bdc5c4..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/BasicDistributedClientTest.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.systest.disttest.clientonly; - -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.Session; - -import org.apache.qpid.disttest.client.Client; -import org.apache.qpid.disttest.client.ClientState; -import org.apache.qpid.disttest.jms.ClientJmsDelegate; -import org.apache.qpid.disttest.jms.JmsMessageAdaptor; -import org.apache.qpid.disttest.message.Command; -import org.apache.qpid.disttest.message.CommandType; -import org.apache.qpid.disttest.message.CreateConnectionCommand; -import org.apache.qpid.disttest.message.CreateSessionCommand; -import org.apache.qpid.disttest.message.NoOpCommand; -import org.apache.qpid.disttest.message.RegisterClientCommand; -import org.apache.qpid.disttest.message.Response; -import org.apache.qpid.disttest.message.StopClientCommand; -import org.apache.qpid.systest.disttest.DistributedTestSystemTestBase; - -public class BasicDistributedClientTest extends DistributedTestSystemTestBase -{ - private Session _session = null; - private MessageProducer _clientQueueProducer; - private Client _client; - private ControllerQueue _controllerQueue; - private ClientJmsDelegate _clientJmsDelegate = null; - - @Override - protected void setUp() throws Exception - { - super.setUp(); - - _controllerQueue = new ControllerQueue(_connection, _context); - _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - _clientJmsDelegate = new ClientJmsDelegate(_context); - _client = new Client(_clientJmsDelegate); - _client.start(); - } - - @Override - protected void tearDown() throws Exception - { - try - { - _controllerQueue.close(); - if (_session != null) - { - _session.close(); - } - } - finally - { - super.tearDown(); - } - } - - public void testClientSendsRegistrationMessage() throws Exception - { - final RegisterClientCommand regClientCommand = _controllerQueue.getNext(); - - assertNotNull("Client must have a non-null name", regClientCommand.getClientName()); - assertEquals("Unexpected client name", _clientJmsDelegate.getClientName(), regClientCommand.getClientName()); - assertNotNull("Client queue name should not be null", regClientCommand.getClientQueueName()); - } - - public void testClientSendsCommandResponses() throws Exception - { - final RegisterClientCommand registrationCommand = _controllerQueue.getNext(); - createClientQueueProducer(registrationCommand); - - sendCommandToClient(new NoOpCommand()); - - final Response responseCommand = _controllerQueue.getNext(); - assertEquals("Incorrect client message type", CommandType.RESPONSE, responseCommand.getType()); - } - - public void testClientCanBeStoppedViaCommand() throws Exception - { - assertEquals("Expected client to be in STARTED state", ClientState.READY, _client.getState()); - - final RegisterClientCommand registrationCommand = _controllerQueue.getNext(); - createClientQueueProducer(registrationCommand); - - final Command stopClientCommand = new StopClientCommand(); - sendCommandToClient(stopClientCommand); - - _client.waitUntilStopped(1000); - - Response response = _controllerQueue.getNext(); - assertNotNull(response); - assertFalse("response shouldn't contain error", response.hasError()); - - assertEquals("Expected client to be in STOPPED state", ClientState.STOPPED, _client.getState()); - } - - public void testClientCanCreateTestConnection() throws Exception - { - assertEquals("Unexpected number of test connections", 0, _clientJmsDelegate.getNoOfTestConnections()); - - final RegisterClientCommand registration = _controllerQueue.getNext(); - createClientQueueProducer(registration); - - final CreateConnectionCommand createConnectionCommand = new CreateConnectionCommand(); - createConnectionCommand.setConnectionName("newTestConnection"); - createConnectionCommand.setConnectionFactoryName("connectionfactory"); - - sendCommandToClient(createConnectionCommand); - Response response = _controllerQueue.getNext(); - - assertFalse("Response message should not have indicated an error", response.hasError()); - assertEquals("Unexpected number of test connections", 1, _clientJmsDelegate.getNoOfTestConnections()); - } - - public void testClientCanCreateTestSession() throws Exception - { - assertEquals("Unexpected number of test sessions", 0, _clientJmsDelegate.getNoOfTestSessions()); - - final RegisterClientCommand registration = _controllerQueue.getNext(); - createClientQueueProducer(registration); - - final CreateConnectionCommand createConnectionCommand = new CreateConnectionCommand(); - createConnectionCommand.setConnectionName("newTestConnection"); - createConnectionCommand.setConnectionFactoryName("connectionfactory"); - - sendCommandToClient(createConnectionCommand); - Response response = _controllerQueue.getNext(); - assertFalse("Response message should not have indicated an error", response.hasError()); - - final CreateSessionCommand createSessionCommand = new CreateSessionCommand(); - createSessionCommand.setConnectionName("newTestConnection"); - createSessionCommand.setSessionName("newTestSession"); - createSessionCommand.setAcknowledgeMode(Session.AUTO_ACKNOWLEDGE); - - sendCommandToClient(createSessionCommand); - response = _controllerQueue.getNext(); - - assertFalse("Response message should not have indicated an error", response.hasError()); - assertEquals("Unexpected number of test sessions", 1, _clientJmsDelegate.getNoOfTestSessions()); - } - - private void sendCommandToClient(final Command command) throws JMSException - { - final Message message = JmsMessageAdaptor.commandToMessage(_session, command); - _clientQueueProducer.send(message); - } - - private void createClientQueueProducer( - final RegisterClientCommand registration) throws JMSException - { - final Destination clientCommandQueue = createDestinationFromRegistration(registration); - _clientQueueProducer = _session.createProducer(clientCommandQueue); - } - - private Queue createDestinationFromRegistration( - final RegisterClientCommand registrationCommand) - throws JMSException - { - String clientQueueName = registrationCommand.getClientQueueName(); - assertNotNull("Null client queue in register message", clientQueueName); - return _session.createQueue(clientQueueName); - } -} diff --git a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/ConsumerParticipantTest.java b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/ConsumerParticipantTest.java deleted file mode 100644 index a3c0430865..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/ConsumerParticipantTest.java +++ /dev/null @@ -1,156 +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.systest.disttest.clientonly; - -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; - -import org.apache.qpid.disttest.client.Client; -import org.apache.qpid.disttest.client.ConsumerParticipant; -import org.apache.qpid.disttest.client.ParticipantExecutor; -import org.apache.qpid.disttest.message.CreateConsumerCommand; -import org.apache.qpid.disttest.message.ParticipantResult; -import org.apache.qpid.systest.disttest.DistributedTestSystemTestBase; -import org.apache.qpid.systest.disttest.clientonly.ProducerParticipantTest.TestClientJmsDelegate; - -public class ConsumerParticipantTest extends DistributedTestSystemTestBase -{ - private MessageProducer _producer; - private Session _session; - private TestClientJmsDelegate _delegate; - private Client _client; - private ControllerQueue _controllerQueue; - - @Override - protected void setUp() throws Exception - { - super.setUp(); - - _controllerQueue = new ControllerQueue(_connection, _context); - _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - _producer = _session.createProducer(getTestQueue()); - - _delegate = new TestClientJmsDelegate(getContext()); - _client = new Client(_delegate); - } - - - @Override - protected void tearDown() throws Exception - { - _controllerQueue.close(); - super.tearDown(); - } - - public void testConsumeNumberOfMessagesSynchronously() throws Exception - { - runTest(Session.AUTO_ACKNOWLEDGE, 10, 0, true); - } - - public void testConsumeNumberOfMessagesAsynchronously() throws Exception - { - runTest(Session.AUTO_ACKNOWLEDGE, 10, 0, false); - } - - public void testSelectors() throws Exception - { - final CreateConsumerCommand command = new CreateConsumerCommand(); - command.setNumberOfMessages(10); - command.setSessionName("testSession"); - command.setDestinationName(getTestQueueName()); - command.setSelector("id=1"); - Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - _delegate.addConnection("name-does-not-matter", _connection); - _delegate.addSession(command.getSessionName(), session); - - ConsumerParticipant consumerParticipant = new ConsumerParticipant(_delegate, command); - _delegate.createConsumer(command); - - for (int i = 0; i < 20; i++) - { - Message message = _session.createMessage(); - if (i % 2 == 0) - { - message.setIntProperty("id", 0); - } - else - { - message.setIntProperty("id", 1); - } - _producer.send(message); - } - - new ParticipantExecutor(consumerParticipant).start(_client); - - ParticipantResult results = _controllerQueue.getNext(); - assertNotNull("No results message recieved", results); - assertEquals("Unexpected number of messages received", 10, results.getNumberOfMessagesProcessed()); - - Session testQueueConsumerSession = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - final MessageConsumer testQueueConsumer = testQueueConsumerSession.createConsumer(getTestQueue()); - for (int i = 0; i < 10; i++) - { - Message message = testQueueConsumer.receive(2000); - assertNotNull("Message is not received: " + message, message); - assertEquals("Unexpected id value", 0, message.getIntProperty("id")); - } - Message message = testQueueConsumer.receive(2000); - assertNull("Unexpected message remaining on test queue: " + message, message); - - _connection.stop(); - } - - protected void runTest(int acknowledgeMode, int numberOfMessages, int batchSize, boolean synchronous) throws Exception - { - final CreateConsumerCommand command = new CreateConsumerCommand(); - command.setNumberOfMessages(numberOfMessages); - command.setBatchSize(batchSize); - command.setSessionName("testSession"); - command.setDestinationName(getTestQueueName()); - command.setSynchronous(synchronous); - - Session session = _connection.createSession(Session.SESSION_TRANSACTED == acknowledgeMode, acknowledgeMode); - - _delegate.addConnection("name-does-not-matter", _connection); - _delegate.addSession(command.getSessionName(), session); - - ConsumerParticipant consumerParticipant = new ConsumerParticipant(_delegate, command); - _delegate.createConsumer(command); - - for (int i = 0; i < numberOfMessages; i++) - { - _producer.send(_session.createMessage()); - } - - new ParticipantExecutor(consumerParticipant).start(_client); - - ParticipantResult results = _controllerQueue.getNext(); - assertNotNull("No results message recieved", results); - - Session testQueueConsumerSession = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - final MessageConsumer testQueueConsumer = testQueueConsumerSession.createConsumer(getTestQueue()); - Message message = testQueueConsumer.receive(2000); - assertNull("Unexpected message remaining on test queue: " + message, message); - - _connection.stop(); - } -} diff --git a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/ControllerQueue.java b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/ControllerQueue.java deleted file mode 100644 index 2a108721b0..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/ControllerQueue.java +++ /dev/null @@ -1,110 +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.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 org.junit.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 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 responses) throws JMSException - { - Command nextResponse = getNext(); - responses.put(nextResponse.getType(), nextResponse); - } - - @SuppressWarnings("unchecked") - public T getNext() throws JMSException - { - return (T)getNext(true); - } - - public T getNext(boolean assertMessageExists) throws JMSException - { - final Message message = _controllerQueueMessageConsumer.receive(2000); - if(assertMessageExists) - { - Assert.assertNotNull("No message received from control queue", message); - } - - if(message == null) - { - return null; - } - - T command = (T) JmsMessageAdaptor.messageToCommand(message); - - return command; - } - - public void close() throws Exception - { - _controllerQueueMessageConsumer.close(); - _controllerQueueSession.close(); - } -} diff --git a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/DistributedClientTest.java b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/DistributedClientTest.java deleted file mode 100644 index 5b5a60ac43..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/DistributedClientTest.java +++ /dev/null @@ -1,325 +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.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.client.AMQSession; -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 Exception - { - 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 responses = new HashMap(); - _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 Exception - { - final Message message = JmsMessageAdaptor.commandToMessage(_session, command); - _clientQueueProducer.send(message); - ((AMQSession)_session).sync(); - } - - private void sendCommandAndValidateResponse(final Command command, boolean shouldSucceed) throws Exception - { - sendCommandToClient(command); - Response response = _controllerQueue.getNext(); - validateResponse(command.getType(), response, shouldSucceed); - } - - private void sendCommandAndValidateResponse(final Command command) throws Exception - { - 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 Exception - { - 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 Exception - { - createTestProducer(sessionName, producerName, destinationName, true); - } - - private void createTestConsumer(String sessionName, String consumerName, String destinationName, boolean shouldSucceed) throws Exception - { - 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 Exception - { - createTestConsumer(sessionName, consumerName, destinationName, true); - } - - private void validateResponse(CommandType originatingCommandType, Response response, boolean shouldSucceed) throws JMSException - { - assertEquals("Response is a reply to the wrong command: " + response, - originatingCommandType, - response.getInReplyToCommandType()); - - boolean shouldHaveError = !shouldSucceed; - assertEquals("Response message " + response + " should have indicated hasError=" + shouldHaveError, - shouldHaveError, - response.hasError()); - } - - private void createClientQueueProducer(final RegisterClientCommand registration) throws JMSException - { - final Destination clientCommandQueue = createDestinationFromRegistration(registration); - _clientQueueProducer = _session.createProducer(clientCommandQueue); - } - - private Queue createDestinationFromRegistration(final RegisterClientCommand registrationCommand) throws JMSException - { - String clientQueueName = registrationCommand.getClientQueueName(); - assertNotNull("Null client queue in register message", clientQueueName); - return _session.createQueue(clientQueueName); - } - - private static void assertState(Client client, ClientState expectedState) - { - ClientState clientState = client.getState(); - assertEquals("Client should be in state: " + expectedState + " but is in state " + clientState, expectedState, clientState); - } -} diff --git a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/MessageProviderTest.java b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/MessageProviderTest.java deleted file mode 100644 index dcbff6518b..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/MessageProviderTest.java +++ /dev/null @@ -1,119 +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.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 messageProperties = new HashMap(); - messageProperties.put("test", new SimplePropertyValue("testValue")); - messageProperties.put("priority", new SimplePropertyValue(new Integer(9))); - messageProviderCommand.setMessageProperties(messageProperties); - _delegate.createMessageProvider(messageProviderCommand); - - final CreateProducerCommand producerCommand = new CreateProducerCommand(); - producerCommand.setNumberOfMessages(1); - producerCommand.setDeliveryMode(DeliveryMode.PERSISTENT); - producerCommand.setPriority(6); - producerCommand.setParticipantName("test"); - producerCommand.setMessageSize(10); - producerCommand.setSessionName("testSession"); - producerCommand.setDestinationName(getTestQueueName()); - producerCommand.setMessageProviderName(messageProviderCommand.getProviderName()); - - Session session = _connection.createSession(true, Session.SESSION_TRANSACTED); - _delegate.addConnection("name-does-not-matter", _connection); - _delegate.addSession(producerCommand.getSessionName(), session); - _delegate.createProducer(producerCommand); - - Message message = _delegate.sendNextMessage(producerCommand); - session.commit(); - assertMessage(message); - - _connection.start(); - Message receivedMessage = _consumer.receive(1000l); - assertMessage(receivedMessage); - } - - protected void assertMessage(Message message) throws JMSException - { - assertNotNull("Message should not be null", message); - assertEquals("Unexpected test property", "testValue", message.getStringProperty("test")); - assertEquals("Unexpected priority property", 9, message.getJMSPriority()); - assertTrue("Unexpected message type", message instanceof TextMessage); - String text = ((TextMessage)message).getText(); - assertNotNull("Message text should not be null", text); - assertNotNull("Unexpected message size ", text.length()); - } -} diff --git a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/ProducerParticipantTest.java b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/ProducerParticipantTest.java deleted file mode 100644 index 54bb9efa98..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/clientonly/ProducerParticipantTest.java +++ /dev/null @@ -1,132 +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.systest.disttest.clientonly; - -import javax.jms.Connection; -import javax.jms.DeliveryMode; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.Session; -import javax.jms.TextMessage; -import javax.naming.Context; - -import org.apache.qpid.disttest.client.Client; -import org.apache.qpid.disttest.client.ParticipantExecutor; -import org.apache.qpid.disttest.client.ProducerParticipant; -import org.apache.qpid.disttest.jms.ClientJmsDelegate; -import org.apache.qpid.disttest.message.CreateProducerCommand; -import org.apache.qpid.disttest.message.ParticipantResult; -import org.apache.qpid.systest.disttest.DistributedTestSystemTestBase; - -public class ProducerParticipantTest extends DistributedTestSystemTestBase -{ - private MessageConsumer _consumer; - private TestClientJmsDelegate _delegate; - private Client _client; - private ControllerQueue _controllerQueue; - - @Override - protected void setUp() throws Exception - { - super.setUp(); - - _controllerQueue = new ControllerQueue(_connection, _context); - Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - _consumer = session.createConsumer(getTestQueue()); - - _delegate = new TestClientJmsDelegate(getContext()); - _client = new Client(_delegate); - } - - - - @Override - protected void tearDown() throws Exception - { - _controllerQueue.close(); - super.tearDown(); - } - - - - public void testProduceNumberOfMessages() throws Exception - { - runTest(Session.AUTO_ACKNOWLEDGE, 100, 10, 0, 0); - } - - protected void runTest(int acknowledgeMode, int messageSize, int numberOfMessages, int batchSize, long publishInterval) throws Exception - { - final CreateProducerCommand command = new CreateProducerCommand(); - command.setNumberOfMessages(numberOfMessages); - command.setDeliveryMode(DeliveryMode.PERSISTENT); - command.setParticipantName("test"); - command.setMessageSize(messageSize); - command.setBatchSize(batchSize); - command.setInterval(publishInterval); - command.setSessionName("testSession"); - command.setDestinationName(getTestQueueName()); - - Session session = _connection.createSession(Session.SESSION_TRANSACTED == acknowledgeMode, acknowledgeMode); - - _delegate.addConnection("name-does-not-matter", _connection); - _delegate.addSession(command.getSessionName(), session); - _delegate.createProducer(command); - - final ProducerParticipant producer = new ProducerParticipant(_delegate, command); - - new ParticipantExecutor(producer).start(_client); - - _connection.start(); - for (int i = 0; i < numberOfMessages; i++) - { - final Message m = _consumer.receive(1000l); - assertNotNull("Expected message [" + i + "] is not received", m); - assertTrue("Unexpected message", m instanceof TextMessage); - } - Message m = _consumer.receive(500l); - assertNull("Unexpected message", m); - - ParticipantResult results = _controllerQueue.getNext(); - - assertNotNull("no results", results); - assertFalse(results.getStartInMillis() == 0); - assertFalse(results.getEndInMillis() == 0); - } - - static class TestClientJmsDelegate extends ClientJmsDelegate - { - - public TestClientJmsDelegate(Context context) - { - super(context); - } - - @Override - public void addSession(final String sessionName, final Session newSession) - { - super.addSession(sessionName, newSession); - } - - @Override - public void addConnection(final String connectionName, final Connection newConnection) - { - super.addConnection(connectionName, newConnection); - } - } -} diff --git a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/ControllerAndClientTest.java b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/ControllerAndClientTest.java deleted file mode 100644 index 75d0941c57..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/ControllerAndClientTest.java +++ /dev/null @@ -1,263 +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.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.Collection; -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.systest.disttest.ConfigFileTestHelper; -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 resultList = runTestsForTwoClients("producerAndConsumerInSeparateClients.json", 1); - - TestResult testResult1 = resultList.get(0); - assertEquals("Unexpected test name", "Test 1", testResult1.getName()); - List test1ParticipantResults = testResult1.getParticipantResults(); - assertEquals("Unexpected number of participant results for test 1", 2, test1ParticipantResults.size()); - assertParticipantNames(test1ParticipantResults, "participantConsumer1", "participantProducer1"); - ConsumerParticipantResult result = null; - for (ParticipantResult participantResult : test1ParticipantResults) - { - if (participantResult instanceof ConsumerParticipantResult) - { - result = (ConsumerParticipantResult)participantResult; - break; - } - } - assertNotNull("Consumer results not recived", result); - Collection latencies = result.getMessageLatencies(); - assertNotNull("Latency results are not collected", latencies); - assertEquals("Unexpected latency results", 1, latencies.size()); - } - - 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 = ConfigFileTestHelper.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 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 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 resultList = runTestsForTwoClients("producerAndThreeConsumersInSeparateClients.json", 1); - - TestResult testResult1 = resultList.get(0); - List 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 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 test1ParticipantResults = testResult.getParticipantResults(); - assertEquals("Unexpected number of participant results for test", 2, test1ParticipantResults.size()); - - ParticipantResult producer1 = test1ParticipantResults.get(1); - - assertEquals(expectedMessageSize, producer1.getPayloadSize()); - assertEquals(iterationNumber, producer1.getIterationNumber()); - } - - public void testTwoTests() throws Exception - { - List resultList = runTestsForTwoClients("testWithTwoTests.json", 2); - - assertEquals("Test 1", resultList.get(0).getName()); - assertEquals("Test 2", resultList.get(1).getName()); - } - - private List runTestsForTwoClients(String jsonConfigFile, int expectedNumberOfTests) throws NamingException, InterruptedException - { - final Config config = ConfigFileTestHelper.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 allTestResults = (List)results.getTestResults(); - assertEquals("Unexpected number of test results", expectedNumberOfTests, allTestResults.size()); - - return allTestResults; - } - - - private void assertParticipantNames(List 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/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/iteratingFeature.json b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/iteratingFeature.json deleted file mode 100644 index 89123302b7..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/iteratingFeature.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "_tests":[ - { - "_name": "Test iteration feature", - "_iterations":[ - { - "_messageSize": 100, - "_numberOfMessages": 10 - }, - { - "_messageSize": 200, - "_numberOfMessages": 5 - } - ], - "_queues":[ - { - "_name": "direct://amq.direct//testQueue" - } - ], - "_clients":[ - { - "_name": "producingClient", - "_connections":[ - { - "_name": "connection1", - "_factory": "connectionfactory", - "_sessions": [ - { - "_sessionName": "session1", - "_producers": [ - { - "_name": "participantProducer1", - "_destinationName": "direct://amq.direct//testQueue" - } - ] - } - ] - } - ] - }, - { - "_name": "consumingClient", - "_connections":[ - { - "_name": "connection1", - "_factory": "connectionfactory", - "_sessions": [ - { - "_sessionName": "session1", - "_consumers": [ - { - "_name": "participantConsumer1", - "_destinationName": "direct://amq.direct//testQueue" - } - ] - } - ] - } - ] - } - ] - }] -} \ No newline at end of file diff --git a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/produceClient.json b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/produceClient.json deleted file mode 100644 index 605e5cb585..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/produceClient.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "_tests":[ - { - "_name": "Test 1"; - "_clients":[ - { - "_name": "producingClient", - "_connections":[ - { - "_name": "connection1", - "_factory": "connectionfactory", - "_sessions": [ - { - "_sessionName": "session1", - "_producers": [ - { - "_name": "participantProducer1", - "_destinationName": "direct://amq.direct//producerClient", - "_numberOfMessages": 10; - "_messageProviderName": "testProvider1" - } - ] - } - ] - } - ]; - "_messageProviders":[ - { - "_name": "testProvider1"; - "_messageProperties": { - "priority": {"@def": "list"; "_items": [0,1,2,3,4,5,6,7,8,9]}; - "id": {"@def": "range"; "_upper": 10; "_type": "int"}; - "test": "test-value" - } - } - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndConsumerInSeparateClients.json b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndConsumerInSeparateClients.json deleted file mode 100644 index a008dc40d8..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndConsumerInSeparateClients.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "_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, - "_evaluateLatency": true - } - ] - } - ] - } - ] - } - ] - }] -} \ No newline at end of file diff --git a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndThreeConsumersInSeparateClients.json b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndThreeConsumersInSeparateClients.json deleted file mode 100644 index f94c4f0ae0..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/producerAndThreeConsumersInSeparateClients.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "_tests":[ - { - "_name": "ProducerAndThreeConsumersInSeparateClients"; - "_queues":[ - { - "_name": "direct://amq.direct//testQueue" - } - ]; - "_clients":[ - { - "_name": "producingClient", - "_connections":[ - { - "_name": "connection1", - "_factory": "connectionfactory", - "_sessions": [ - { - "_sessionName": "session1", - "_producers": [ - { - "_name": "participantProducer1", - "_destinationName": "direct://amq.direct//testQueue", - "_numberOfMessages": 9, - "_batchSize": 2, - "_interval": 50 - } - ] - } - ] - } - ] - }, - { - "_name": "consumingClient", - "_connections":[ - { - "_name": "connection1", - "_factory": "connectionfactory", - "_sessions": [ - { - "_sessionName": "session1", - "_consumers": [ - { - "_name": "participantConsumer1", - "_destinationName": "direct://amq.direct//testQueue", - "_numberOfMessages": 3 - } - ] - }, - { - "_sessionName": "session2", - "_consumers": [ - { - "_name": "participantConsumer2", - "_destinationName": "direct://amq.direct//testQueue", - "_numberOfMessages": 3 - } - ] - }, - { - "_sessionName": "session3", - "_consumers": [ - { - "_name": "participantConsumer3", - "_destinationName": "direct://amq.direct//testQueue", - "_numberOfMessages": 3 - } - ] - } - ] - } - ] - } - ] - }] -} \ No newline at end of file diff --git a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/testWithTwoTests.json b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/testWithTwoTests.json deleted file mode 100644 index 4abd7f4feb..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controllerandclient/testWithTwoTests.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "_tests":[ - { - "_name": "Test 1"; - "_queues":[ - { - "_name": "direct://amq.direct//testQueue" - } - ]; - "_clients":[ - { - "_name": "producingClient", - "_connections":[ - { - "_name": "connection1", - "_factory": "connectionfactory", - "_sessions": [ - { - "_sessionName": "session1", - "_producers": [ - { - "_name": "participantProducer1", - "_destinationName": "direct://amq.direct//testQueue", - "_numberOfMessages": 1 - } - ] - } - ] - } - ] - }, - { - "_name": "consumingClient", - "_connections":[ - { - "_name": "connection1", - "_factory": "connectionfactory", - "_sessions": [ - { - "_sessionName": "session1", - "_consumers": [ - { - "_name": "participantconsumer1", - "_destinationName": "direct://amq.direct//testQueue", - "_numberOfMessages": 1 - } - ] - } - ] - } - ] - } - ] - }, - { - "_name": "Test 2"; - "_queues":[ - { - "_name": "direct://amq.direct//testQueue2" - } - ]; - "_clients":[ - { - "_name": "producingClient", - "_connections":[ - { - "_name": "connection1", - "_factory": "connectionfactory", - "_sessions": [ - { - "_sessionName": "session1", - "_producers": [ - { - "_name": "participantProducer2", - "_destinationName": "direct://amq.direct//testQueue2", - "_numberOfMessages": 1 - } - ] - } - ] - } - ] - }, - { - "_name": "consumingClient", - "_connections":[ - { - "_name": "connection1", - "_factory": "connectionfactory", - "_sessions": [ - { - "_sessionName": "session1", - "_consumers": [ - { - "_name": "participantConsumer2", - "_destinationName": "direct://amq.direct//testQueue2", - "_numberOfMessages": 1 - } - ] - } - ] - } - ] - } - ] - }] -} \ No newline at end of file diff --git a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controlleronly/DistributedControllerTest.java b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controlleronly/DistributedControllerTest.java deleted file mode 100644 index 349ddb276e..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controlleronly/DistributedControllerTest.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.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.systest.disttest.ConfigFileTestHelper; -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 = ConfigFileTestHelper.getConfigFromResource(getClass(), "distributedControllerTest.json"); - _controller.setConfig(config); - - sendRegistration(CLIENT1); - _controller.awaitClientRegistrations(); - - final ArrayBlockingQueue commandList = new ArrayBlockingQueue(4); - final MessageConsumer clientConsumer = _session.createConsumer(_clientQueue); - final AtomicReference listenerException = new AtomicReference(); - 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 commandList) throws InterruptedException - { - Command command = commandList.poll(1l, TimeUnit.SECONDS); - assertNotNull("Command of type " + expectedType + " is not received", command); - assertEquals("Unexpected command type", expectedType, command.getType()); - } - - private void sendRegistration(final String clientId) throws JMSException - { - final MessageProducer registrationProducer = _session.createProducer(_controllerQueue); - - final Command command = new RegisterClientCommand(clientId, _clientQueue.getQueueName()); - final Message registrationMessage = JmsMessageAdaptor.commandToMessage(_session, command); - registrationProducer.send(registrationMessage); - LOGGER.debug("sent registrationMessage: " + registrationMessage); - } - -} diff --git a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controlleronly/distributedControllerTest.json b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controlleronly/distributedControllerTest.json deleted file mode 100644 index b49603ef23..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/controlleronly/distributedControllerTest.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "_tests":[ - { - "_name": "Test 1"; - "_clients":[ - { - "_name": "client1", - "_connections":[ - { - "_name": "connection1", - "_factory": "connectionfactory" - } - ] - } - ] - }] -} \ No newline at end of file diff --git a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/endtoend/EndToEndTest.java b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/endtoend/EndToEndTest.java deleted file mode 100644 index 010eec4982..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/endtoend/EndToEndTest.java +++ /dev/null @@ -1,100 +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.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.RUN_ID; -import static org.apache.qpid.disttest.ControllerRunner.TEST_CONFIG_PROP; -import static org.apache.qpid.disttest.ControllerRunner.WRITE_TO_DB; - -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 = "qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/endtoend/endtoend.json"; - private static final String JNDI_CONFIG_FILE = "qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/perftests.systests.properties"; - private static final String RUN1 = "run1"; - - 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, - WRITE_TO_DB + "=true", - RUN_ID + "=" + RUN1, - 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[3], 1); - - assertDataRowsHaveCorrectTestAndClientName("End To End 1", "", TestResultAggregator.ALL_PARTICIPANTS_NAME, csvLines[4], 1); - assertDataRowsHaveCorrectTestAndClientName("End To End 1", "", TestResultAggregator.ALL_CONSUMER_PARTICIPANTS_NAME, csvLines[2], 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[ParticipantAttribute.TEST_NAME.ordinal()]); - assertEquals("Unexpected client name in CSV line " + csvLine, clientName, cells[ParticipantAttribute.CONFIGURED_CLIENT_NAME.ordinal()]); - assertEquals("Unexpected participant name in CSV line " + csvLine, participantName, cells[ParticipantAttribute.PARTICIPANT_NAME.ordinal()]); - assertEquals("Unexpected number of messages processed in CSV line " + csvLine, String.valueOf(expectedNumberOfMessagesProcessed), cells[ParticipantAttribute.NUMBER_OF_MESSAGES_PROCESSED.ordinal()]); - - } - - 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/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/endtoend/endtoend.json b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/endtoend/endtoend.json deleted file mode 100644 index 1b7cc51265..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/endtoend/endtoend.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "_tests":[ - { - "_name": "End To End 1"; - "_queues":[ - { - "_name": "direct://amq.direct//testQueue" - } - ]; - "_clients":[ - { - "_name": "producingClient", - "_connections":[ - { - "_name": "connection1", - "_factory": "connectionfactory", - "_sessions": [ - { - "_sessionName": "session1", - "_producers": [ - { - "_name": "participantProducer1", - "_destinationName": "direct://amq.direct//testQueue", - "_numberOfMessages": 1 - } - ] - } - ]; - "_messageProviders":[ - { - "_name": "testProvider1"; - "_messageProperties": { - "priority": {"@def": "list"; "_items": [1,2,3,4,4]}; - "id": {"@def": "random"; "_upper": 10}; - "test": "test-value" - } - } - ] - } - ] - }, - { - "_name": "consumingClient", - "_connections":[ - { - "_name": "connection1", - "_factory": "connectionfactory", - "_sessions": [ - { - "_sessionName": "session1", - "_consumers": [ - { - "_name": "participantConsumer1", - "_destinationName": "direct://amq.direct//testQueue", - "_numberOfMessages": 1 - } - ] - } - ] - } - ] - } - ] - }] -} \ No newline at end of file diff --git a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/perftests.systests.properties b/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/perftests.systests.properties deleted file mode 100644 index 149e632048..0000000000 --- a/qpid/java/qpid-perftests-systests/src/main/java/org/apache/qpid/systest/disttest/perftests.systests.properties +++ /dev/null @@ -1,29 +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. - -# 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 - -jdbcDriverClass=org.apache.derby.jdbc.EmbeddedDriver -jdbcUrl=jdbc:derby:/tmp/tempDbDirectory/perftestResultsDb;create=true diff --git a/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/ConfigFileTestHelper.java b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/ConfigFileTestHelper.java new file mode 100644 index 0000000000..a4f4cab018 --- /dev/null +++ b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/ConfigFileTestHelper.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.systest.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 ConfigFileTestHelper +{ + public static Reader getConfigFileReader(Class testClass, String resourceName) + { + InputStream inputStream = testClass.getResourceAsStream(resourceName); + if(inputStream == null) + { + throw new RuntimeException("Can't find resource " + resourceName + " using classloader of class " + testClass); + } + Reader reader = new InputStreamReader(inputStream); + return reader; + } + + public static Config getConfigFromResource(Class testClass, String resourceName) + { + ConfigReader configReader = new ConfigReader(); + Config config = configReader.readConfig(getConfigFileReader(testClass, resourceName)); + return config; + } +} diff --git a/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/DistributedTestSystemTestBase.java b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/DistributedTestSystemTestBase.java new file mode 100644 index 0000000000..96daf64526 --- /dev/null +++ b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/DistributedTestSystemTestBase.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.systest.disttest; + +import java.util.Properties; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; + +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class DistributedTestSystemTestBase extends QpidBrokerTestCase +{ + protected Context _context; + + protected Connection _connection; + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + final Properties properties = new Properties(); + properties.load(DistributedTestSystemTestBase.class.getResourceAsStream("perftests.systests.properties")); + _context = new InitialContext(properties); + + _connection = getConnection(); + _connection.start(); + } + + @Override + protected void tearDown() throws Exception + { + // no need to close connections - this is done by superclass + + super.tearDown(); + } + + public Context getContext() + { + return _context; + } + + @Override + public Connection getConnection() throws JMSException, NamingException + { + final ConnectionFactory connectionFactory = (ConnectionFactory) _context.lookup("connectionfactory"); + final Connection connection = connectionFactory.createConnection(); + _connections.add(connection); + return connection; + } +} diff --git a/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/QpidQueueCreatorTest.java b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/QpidQueueCreatorTest.java new file mode 100644 index 0000000000..59396d46c0 --- /dev/null +++ b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/QpidQueueCreatorTest.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.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.controller.config.QueueConfig; +import org.apache.qpid.disttest.jms.QpidQueueCreator; + +public class QpidQueueCreatorTest extends DistributedTestSystemTestBase +{ + private static final Map EMPTY_ATTRIBUTES = Collections.emptyMap(); + + private static final boolean QUEUE_DURABILITY = true; + + private Connection _connection; + private QpidQueueCreator _creator; + private Session _session; + private List _configs; + private String _queueName; + + @Override + public void setUp() throws Exception + { + super.setUp(); + _connection = getConnection(); + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _creator = new QpidQueueCreator(); + _configs = new ArrayList(); + _queueName = "direct://amq.direct//" + getTestQueueName() + "?durable='" + QUEUE_DURABILITY + "'"; + } + + public void testCreateQueueWithoutAttributes() throws Exception + { + _configs.add(new QueueConfig(_queueName, QUEUE_DURABILITY, EMPTY_ATTRIBUTES)); + + assertQueueBound(_queueName, false); + + _creator.createQueues(_connection, _session, _configs); + + assertQueueBound(_queueName, true); + } + + public void testCreateWithAttributes() throws Exception + { + Map attributes = new HashMap(); + attributes.put("x-qpid-priorities", Integer.valueOf(5)); + _configs.add(new QueueConfig(_queueName, QUEUE_DURABILITY, attributes)); + + assertQueueBound(_queueName, false); + + _creator.createQueues(_connection, _session, _configs); + + assertQueueBound(_queueName, true); + } + + public void testDeleteQueues() throws Exception + { + _configs.add(new QueueConfig(_queueName, QUEUE_DURABILITY, EMPTY_ATTRIBUTES)); + + assertQueueBound(_queueName, false); + + _creator.createQueues(_connection, _session, _configs); + assertQueueBound(_queueName, true); + + _creator.deleteQueues(_connection, _session, _configs); + assertQueueBound(_queueName, false); + } + + private void assertQueueBound(String queueName, boolean isBound) throws Exception + { + AMQDestination destination = (AMQDestination)_session.createQueue(queueName); + assertEquals("Queue is not in expected bound state", isBound, ((AMQSession)_session).isQueueBound(destination)); + } +} diff --git a/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/SystemTestConstants.java b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/SystemTestConstants.java new file mode 100644 index 0000000000..b06ab0c735 --- /dev/null +++ b/qpid/java/qpid-perftests-systests/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 = 20000; + public static final long COMMAND_RESPONSE_TIMEOUT = 30000; + public static final long TEST_RESULT_TIMEOUT = 20000; + +} diff --git a/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/BasicDistributedClientTest.java b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/BasicDistributedClientTest.java new file mode 100644 index 0000000000..d599bdc5c4 --- /dev/null +++ b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/BasicDistributedClientTest.java @@ -0,0 +1,186 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.systest.disttest.clientonly; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.qpid.disttest.client.Client; +import org.apache.qpid.disttest.client.ClientState; +import org.apache.qpid.disttest.jms.ClientJmsDelegate; +import org.apache.qpid.disttest.jms.JmsMessageAdaptor; +import org.apache.qpid.disttest.message.Command; +import org.apache.qpid.disttest.message.CommandType; +import org.apache.qpid.disttest.message.CreateConnectionCommand; +import org.apache.qpid.disttest.message.CreateSessionCommand; +import org.apache.qpid.disttest.message.NoOpCommand; +import org.apache.qpid.disttest.message.RegisterClientCommand; +import org.apache.qpid.disttest.message.Response; +import org.apache.qpid.disttest.message.StopClientCommand; +import org.apache.qpid.systest.disttest.DistributedTestSystemTestBase; + +public class BasicDistributedClientTest extends DistributedTestSystemTestBase +{ + private Session _session = null; + private MessageProducer _clientQueueProducer; + private Client _client; + private ControllerQueue _controllerQueue; + private ClientJmsDelegate _clientJmsDelegate = null; + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + _controllerQueue = new ControllerQueue(_connection, _context); + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + _clientJmsDelegate = new ClientJmsDelegate(_context); + _client = new Client(_clientJmsDelegate); + _client.start(); + } + + @Override + protected void tearDown() throws Exception + { + try + { + _controllerQueue.close(); + if (_session != null) + { + _session.close(); + } + } + finally + { + super.tearDown(); + } + } + + public void testClientSendsRegistrationMessage() throws Exception + { + final RegisterClientCommand regClientCommand = _controllerQueue.getNext(); + + assertNotNull("Client must have a non-null name", regClientCommand.getClientName()); + assertEquals("Unexpected client name", _clientJmsDelegate.getClientName(), regClientCommand.getClientName()); + assertNotNull("Client queue name should not be null", regClientCommand.getClientQueueName()); + } + + public void testClientSendsCommandResponses() throws Exception + { + final RegisterClientCommand registrationCommand = _controllerQueue.getNext(); + createClientQueueProducer(registrationCommand); + + sendCommandToClient(new NoOpCommand()); + + final Response responseCommand = _controllerQueue.getNext(); + assertEquals("Incorrect client message type", CommandType.RESPONSE, responseCommand.getType()); + } + + public void testClientCanBeStoppedViaCommand() throws Exception + { + assertEquals("Expected client to be in STARTED state", ClientState.READY, _client.getState()); + + final RegisterClientCommand registrationCommand = _controllerQueue.getNext(); + createClientQueueProducer(registrationCommand); + + final Command stopClientCommand = new StopClientCommand(); + sendCommandToClient(stopClientCommand); + + _client.waitUntilStopped(1000); + + Response response = _controllerQueue.getNext(); + assertNotNull(response); + assertFalse("response shouldn't contain error", response.hasError()); + + assertEquals("Expected client to be in STOPPED state", ClientState.STOPPED, _client.getState()); + } + + public void testClientCanCreateTestConnection() throws Exception + { + assertEquals("Unexpected number of test connections", 0, _clientJmsDelegate.getNoOfTestConnections()); + + final RegisterClientCommand registration = _controllerQueue.getNext(); + createClientQueueProducer(registration); + + final CreateConnectionCommand createConnectionCommand = new CreateConnectionCommand(); + createConnectionCommand.setConnectionName("newTestConnection"); + createConnectionCommand.setConnectionFactoryName("connectionfactory"); + + sendCommandToClient(createConnectionCommand); + Response response = _controllerQueue.getNext(); + + assertFalse("Response message should not have indicated an error", response.hasError()); + assertEquals("Unexpected number of test connections", 1, _clientJmsDelegate.getNoOfTestConnections()); + } + + public void testClientCanCreateTestSession() throws Exception + { + assertEquals("Unexpected number of test sessions", 0, _clientJmsDelegate.getNoOfTestSessions()); + + final RegisterClientCommand registration = _controllerQueue.getNext(); + createClientQueueProducer(registration); + + final CreateConnectionCommand createConnectionCommand = new CreateConnectionCommand(); + createConnectionCommand.setConnectionName("newTestConnection"); + createConnectionCommand.setConnectionFactoryName("connectionfactory"); + + sendCommandToClient(createConnectionCommand); + Response response = _controllerQueue.getNext(); + assertFalse("Response message should not have indicated an error", response.hasError()); + + final CreateSessionCommand createSessionCommand = new CreateSessionCommand(); + createSessionCommand.setConnectionName("newTestConnection"); + createSessionCommand.setSessionName("newTestSession"); + createSessionCommand.setAcknowledgeMode(Session.AUTO_ACKNOWLEDGE); + + sendCommandToClient(createSessionCommand); + response = _controllerQueue.getNext(); + + assertFalse("Response message should not have indicated an error", response.hasError()); + assertEquals("Unexpected number of test sessions", 1, _clientJmsDelegate.getNoOfTestSessions()); + } + + private void sendCommandToClient(final Command command) throws JMSException + { + final Message message = JmsMessageAdaptor.commandToMessage(_session, command); + _clientQueueProducer.send(message); + } + + private void createClientQueueProducer( + final RegisterClientCommand registration) throws JMSException + { + final Destination clientCommandQueue = createDestinationFromRegistration(registration); + _clientQueueProducer = _session.createProducer(clientCommandQueue); + } + + private Queue createDestinationFromRegistration( + final RegisterClientCommand registrationCommand) + throws JMSException + { + String clientQueueName = registrationCommand.getClientQueueName(); + assertNotNull("Null client queue in register message", clientQueueName); + return _session.createQueue(clientQueueName); + } +} diff --git a/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ConsumerParticipantTest.java b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ConsumerParticipantTest.java new file mode 100644 index 0000000000..a3c0430865 --- /dev/null +++ b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ConsumerParticipantTest.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.systest.disttest.clientonly; + +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.qpid.disttest.client.Client; +import org.apache.qpid.disttest.client.ConsumerParticipant; +import org.apache.qpid.disttest.client.ParticipantExecutor; +import org.apache.qpid.disttest.message.CreateConsumerCommand; +import org.apache.qpid.disttest.message.ParticipantResult; +import org.apache.qpid.systest.disttest.DistributedTestSystemTestBase; +import org.apache.qpid.systest.disttest.clientonly.ProducerParticipantTest.TestClientJmsDelegate; + +public class ConsumerParticipantTest extends DistributedTestSystemTestBase +{ + private MessageProducer _producer; + private Session _session; + private TestClientJmsDelegate _delegate; + private Client _client; + private ControllerQueue _controllerQueue; + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + _controllerQueue = new ControllerQueue(_connection, _context); + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _producer = _session.createProducer(getTestQueue()); + + _delegate = new TestClientJmsDelegate(getContext()); + _client = new Client(_delegate); + } + + + @Override + protected void tearDown() throws Exception + { + _controllerQueue.close(); + super.tearDown(); + } + + public void testConsumeNumberOfMessagesSynchronously() throws Exception + { + runTest(Session.AUTO_ACKNOWLEDGE, 10, 0, true); + } + + public void testConsumeNumberOfMessagesAsynchronously() throws Exception + { + runTest(Session.AUTO_ACKNOWLEDGE, 10, 0, false); + } + + public void testSelectors() throws Exception + { + final CreateConsumerCommand command = new CreateConsumerCommand(); + command.setNumberOfMessages(10); + command.setSessionName("testSession"); + command.setDestinationName(getTestQueueName()); + command.setSelector("id=1"); + Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + _delegate.addConnection("name-does-not-matter", _connection); + _delegate.addSession(command.getSessionName(), session); + + ConsumerParticipant consumerParticipant = new ConsumerParticipant(_delegate, command); + _delegate.createConsumer(command); + + for (int i = 0; i < 20; i++) + { + Message message = _session.createMessage(); + if (i % 2 == 0) + { + message.setIntProperty("id", 0); + } + else + { + message.setIntProperty("id", 1); + } + _producer.send(message); + } + + new ParticipantExecutor(consumerParticipant).start(_client); + + ParticipantResult results = _controllerQueue.getNext(); + assertNotNull("No results message recieved", results); + assertEquals("Unexpected number of messages received", 10, results.getNumberOfMessagesProcessed()); + + Session testQueueConsumerSession = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageConsumer testQueueConsumer = testQueueConsumerSession.createConsumer(getTestQueue()); + for (int i = 0; i < 10; i++) + { + Message message = testQueueConsumer.receive(2000); + assertNotNull("Message is not received: " + message, message); + assertEquals("Unexpected id value", 0, message.getIntProperty("id")); + } + Message message = testQueueConsumer.receive(2000); + assertNull("Unexpected message remaining on test queue: " + message, message); + + _connection.stop(); + } + + protected void runTest(int acknowledgeMode, int numberOfMessages, int batchSize, boolean synchronous) throws Exception + { + final CreateConsumerCommand command = new CreateConsumerCommand(); + command.setNumberOfMessages(numberOfMessages); + command.setBatchSize(batchSize); + command.setSessionName("testSession"); + command.setDestinationName(getTestQueueName()); + command.setSynchronous(synchronous); + + Session session = _connection.createSession(Session.SESSION_TRANSACTED == acknowledgeMode, acknowledgeMode); + + _delegate.addConnection("name-does-not-matter", _connection); + _delegate.addSession(command.getSessionName(), session); + + ConsumerParticipant consumerParticipant = new ConsumerParticipant(_delegate, command); + _delegate.createConsumer(command); + + for (int i = 0; i < numberOfMessages; i++) + { + _producer.send(_session.createMessage()); + } + + new ParticipantExecutor(consumerParticipant).start(_client); + + ParticipantResult results = _controllerQueue.getNext(); + assertNotNull("No results message recieved", results); + + Session testQueueConsumerSession = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageConsumer testQueueConsumer = testQueueConsumerSession.createConsumer(getTestQueue()); + Message message = testQueueConsumer.receive(2000); + assertNull("Unexpected message remaining on test queue: " + message, message); + + _connection.stop(); + } +} diff --git a/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ControllerQueue.java b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ControllerQueue.java new file mode 100644 index 0000000000..2a108721b0 --- /dev/null +++ b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ControllerQueue.java @@ -0,0 +1,110 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.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 org.junit.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 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 responses) throws JMSException + { + Command nextResponse = getNext(); + responses.put(nextResponse.getType(), nextResponse); + } + + @SuppressWarnings("unchecked") + public T getNext() throws JMSException + { + return (T)getNext(true); + } + + public T getNext(boolean assertMessageExists) throws JMSException + { + final Message message = _controllerQueueMessageConsumer.receive(2000); + if(assertMessageExists) + { + Assert.assertNotNull("No message received from control queue", message); + } + + if(message == null) + { + return null; + } + + T command = (T) JmsMessageAdaptor.messageToCommand(message); + + return command; + } + + public void close() throws Exception + { + _controllerQueueMessageConsumer.close(); + _controllerQueueSession.close(); + } +} diff --git a/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/DistributedClientTest.java b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/DistributedClientTest.java new file mode 100644 index 0000000000..5b5a60ac43 --- /dev/null +++ b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/DistributedClientTest.java @@ -0,0 +1,325 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.client.AMQSession; +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 Exception + { + 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 responses = new HashMap(); + _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 Exception + { + final Message message = JmsMessageAdaptor.commandToMessage(_session, command); + _clientQueueProducer.send(message); + ((AMQSession)_session).sync(); + } + + private void sendCommandAndValidateResponse(final Command command, boolean shouldSucceed) throws Exception + { + sendCommandToClient(command); + Response response = _controllerQueue.getNext(); + validateResponse(command.getType(), response, shouldSucceed); + } + + private void sendCommandAndValidateResponse(final Command command) throws Exception + { + 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 Exception + { + 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 Exception + { + createTestProducer(sessionName, producerName, destinationName, true); + } + + private void createTestConsumer(String sessionName, String consumerName, String destinationName, boolean shouldSucceed) throws Exception + { + 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 Exception + { + createTestConsumer(sessionName, consumerName, destinationName, true); + } + + private void validateResponse(CommandType originatingCommandType, Response response, boolean shouldSucceed) throws JMSException + { + assertEquals("Response is a reply to the wrong command: " + response, + originatingCommandType, + response.getInReplyToCommandType()); + + boolean shouldHaveError = !shouldSucceed; + assertEquals("Response message " + response + " should have indicated hasError=" + shouldHaveError, + shouldHaveError, + response.hasError()); + } + + private void createClientQueueProducer(final RegisterClientCommand registration) throws JMSException + { + final Destination clientCommandQueue = createDestinationFromRegistration(registration); + _clientQueueProducer = _session.createProducer(clientCommandQueue); + } + + private Queue createDestinationFromRegistration(final RegisterClientCommand registrationCommand) throws JMSException + { + String clientQueueName = registrationCommand.getClientQueueName(); + assertNotNull("Null client queue in register message", clientQueueName); + return _session.createQueue(clientQueueName); + } + + private static void assertState(Client client, ClientState expectedState) + { + ClientState clientState = client.getState(); + assertEquals("Client should be in state: " + expectedState + " but is in state " + clientState, expectedState, clientState); + } +} diff --git a/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/MessageProviderTest.java b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/MessageProviderTest.java new file mode 100644 index 0000000000..dcbff6518b --- /dev/null +++ b/qpid/java/qpid-perftests-systests/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 messageProperties = new HashMap(); + messageProperties.put("test", new SimplePropertyValue("testValue")); + messageProperties.put("priority", new SimplePropertyValue(new Integer(9))); + messageProviderCommand.setMessageProperties(messageProperties); + _delegate.createMessageProvider(messageProviderCommand); + + final CreateProducerCommand producerCommand = new CreateProducerCommand(); + producerCommand.setNumberOfMessages(1); + producerCommand.setDeliveryMode(DeliveryMode.PERSISTENT); + producerCommand.setPriority(6); + producerCommand.setParticipantName("test"); + producerCommand.setMessageSize(10); + producerCommand.setSessionName("testSession"); + producerCommand.setDestinationName(getTestQueueName()); + producerCommand.setMessageProviderName(messageProviderCommand.getProviderName()); + + Session session = _connection.createSession(true, Session.SESSION_TRANSACTED); + _delegate.addConnection("name-does-not-matter", _connection); + _delegate.addSession(producerCommand.getSessionName(), session); + _delegate.createProducer(producerCommand); + + Message message = _delegate.sendNextMessage(producerCommand); + session.commit(); + assertMessage(message); + + _connection.start(); + Message receivedMessage = _consumer.receive(1000l); + assertMessage(receivedMessage); + } + + protected void assertMessage(Message message) throws JMSException + { + assertNotNull("Message should not be null", message); + assertEquals("Unexpected test property", "testValue", message.getStringProperty("test")); + assertEquals("Unexpected priority property", 9, message.getJMSPriority()); + assertTrue("Unexpected message type", message instanceof TextMessage); + String text = ((TextMessage)message).getText(); + assertNotNull("Message text should not be null", text); + assertNotNull("Unexpected message size ", text.length()); + } +} diff --git a/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ProducerParticipantTest.java b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ProducerParticipantTest.java new file mode 100644 index 0000000000..54bb9efa98 --- /dev/null +++ b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/clientonly/ProducerParticipantTest.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.systest.disttest.clientonly; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.naming.Context; + +import org.apache.qpid.disttest.client.Client; +import org.apache.qpid.disttest.client.ParticipantExecutor; +import org.apache.qpid.disttest.client.ProducerParticipant; +import org.apache.qpid.disttest.jms.ClientJmsDelegate; +import org.apache.qpid.disttest.message.CreateProducerCommand; +import org.apache.qpid.disttest.message.ParticipantResult; +import org.apache.qpid.systest.disttest.DistributedTestSystemTestBase; + +public class ProducerParticipantTest extends DistributedTestSystemTestBase +{ + private MessageConsumer _consumer; + private TestClientJmsDelegate _delegate; + private Client _client; + private ControllerQueue _controllerQueue; + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + _controllerQueue = new ControllerQueue(_connection, _context); + Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _consumer = session.createConsumer(getTestQueue()); + + _delegate = new TestClientJmsDelegate(getContext()); + _client = new Client(_delegate); + } + + + + @Override + protected void tearDown() throws Exception + { + _controllerQueue.close(); + super.tearDown(); + } + + + + public void testProduceNumberOfMessages() throws Exception + { + runTest(Session.AUTO_ACKNOWLEDGE, 100, 10, 0, 0); + } + + protected void runTest(int acknowledgeMode, int messageSize, int numberOfMessages, int batchSize, long publishInterval) throws Exception + { + final CreateProducerCommand command = new CreateProducerCommand(); + command.setNumberOfMessages(numberOfMessages); + command.setDeliveryMode(DeliveryMode.PERSISTENT); + command.setParticipantName("test"); + command.setMessageSize(messageSize); + command.setBatchSize(batchSize); + command.setInterval(publishInterval); + command.setSessionName("testSession"); + command.setDestinationName(getTestQueueName()); + + Session session = _connection.createSession(Session.SESSION_TRANSACTED == acknowledgeMode, acknowledgeMode); + + _delegate.addConnection("name-does-not-matter", _connection); + _delegate.addSession(command.getSessionName(), session); + _delegate.createProducer(command); + + final ProducerParticipant producer = new ProducerParticipant(_delegate, command); + + new ParticipantExecutor(producer).start(_client); + + _connection.start(); + for (int i = 0; i < numberOfMessages; i++) + { + final Message m = _consumer.receive(1000l); + assertNotNull("Expected message [" + i + "] is not received", m); + assertTrue("Unexpected message", m instanceof TextMessage); + } + Message m = _consumer.receive(500l); + assertNull("Unexpected message", m); + + ParticipantResult results = _controllerQueue.getNext(); + + assertNotNull("no results", results); + assertFalse(results.getStartInMillis() == 0); + assertFalse(results.getEndInMillis() == 0); + } + + static class TestClientJmsDelegate extends ClientJmsDelegate + { + + public TestClientJmsDelegate(Context context) + { + super(context); + } + + @Override + public void addSession(final String sessionName, final Session newSession) + { + super.addSession(sessionName, newSession); + } + + @Override + public void addConnection(final String connectionName, final Connection newConnection) + { + super.addConnection(connectionName, newConnection); + } + } +} diff --git a/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/ControllerAndClientTest.java b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/ControllerAndClientTest.java new file mode 100644 index 0000000000..75d0941c57 --- /dev/null +++ b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/controllerandclient/ControllerAndClientTest.java @@ -0,0 +1,263 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.Collection; +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.systest.disttest.ConfigFileTestHelper; +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 resultList = runTestsForTwoClients("producerAndConsumerInSeparateClients.json", 1); + + TestResult testResult1 = resultList.get(0); + assertEquals("Unexpected test name", "Test 1", testResult1.getName()); + List test1ParticipantResults = testResult1.getParticipantResults(); + assertEquals("Unexpected number of participant results for test 1", 2, test1ParticipantResults.size()); + assertParticipantNames(test1ParticipantResults, "participantConsumer1", "participantProducer1"); + ConsumerParticipantResult result = null; + for (ParticipantResult participantResult : test1ParticipantResults) + { + if (participantResult instanceof ConsumerParticipantResult) + { + result = (ConsumerParticipantResult)participantResult; + break; + } + } + assertNotNull("Consumer results not recived", result); + Collection latencies = result.getMessageLatencies(); + assertNotNull("Latency results are not collected", latencies); + assertEquals("Unexpected latency results", 1, latencies.size()); + } + + 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 = ConfigFileTestHelper.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 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 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 resultList = runTestsForTwoClients("producerAndThreeConsumersInSeparateClients.json", 1); + + TestResult testResult1 = resultList.get(0); + List 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 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 test1ParticipantResults = testResult.getParticipantResults(); + assertEquals("Unexpected number of participant results for test", 2, test1ParticipantResults.size()); + + ParticipantResult producer1 = test1ParticipantResults.get(1); + + assertEquals(expectedMessageSize, producer1.getPayloadSize()); + assertEquals(iterationNumber, producer1.getIterationNumber()); + } + + public void testTwoTests() throws Exception + { + List resultList = runTestsForTwoClients("testWithTwoTests.json", 2); + + assertEquals("Test 1", resultList.get(0).getName()); + assertEquals("Test 2", resultList.get(1).getName()); + } + + private List runTestsForTwoClients(String jsonConfigFile, int expectedNumberOfTests) throws NamingException, InterruptedException + { + final Config config = ConfigFileTestHelper.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 allTestResults = (List)results.getTestResults(); + assertEquals("Unexpected number of test results", expectedNumberOfTests, allTestResults.size()); + + return allTestResults; + } + + + private void assertParticipantNames(List 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/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/controlleronly/DistributedControllerTest.java b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/controlleronly/DistributedControllerTest.java new file mode 100644 index 0000000000..349ddb276e --- /dev/null +++ b/qpid/java/qpid-perftests-systests/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.systest.disttest.ConfigFileTestHelper; +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 = ConfigFileTestHelper.getConfigFromResource(getClass(), "distributedControllerTest.json"); + _controller.setConfig(config); + + sendRegistration(CLIENT1); + _controller.awaitClientRegistrations(); + + final ArrayBlockingQueue commandList = new ArrayBlockingQueue(4); + final MessageConsumer clientConsumer = _session.createConsumer(_clientQueue); + final AtomicReference listenerException = new AtomicReference(); + 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 commandList) throws InterruptedException + { + Command command = commandList.poll(1l, TimeUnit.SECONDS); + assertNotNull("Command of type " + expectedType + " is not received", command); + assertEquals("Unexpected command type", expectedType, command.getType()); + } + + private void sendRegistration(final String clientId) throws JMSException + { + final MessageProducer registrationProducer = _session.createProducer(_controllerQueue); + + final Command command = new RegisterClientCommand(clientId, _clientQueue.getQueueName()); + final Message registrationMessage = JmsMessageAdaptor.commandToMessage(_session, command); + registrationProducer.send(registrationMessage); + LOGGER.debug("sent registrationMessage: " + registrationMessage); + } + +} diff --git a/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/endtoend/EndToEndTest.java b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/endtoend/EndToEndTest.java new file mode 100644 index 0000000000..215536126e --- /dev/null +++ b/qpid/java/qpid-perftests-systests/src/test/java/org/apache/qpid/systest/disttest/endtoend/EndToEndTest.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.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.RUN_ID; +import static org.apache.qpid.disttest.ControllerRunner.TEST_CONFIG_PROP; +import static org.apache.qpid.disttest.ControllerRunner.WRITE_TO_DB; + +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 = "qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/endtoend/endtoend.json"; + private static final String JNDI_CONFIG_FILE = "qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/perftests.systests.properties"; + private static final String RUN1 = "run1"; + + 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, + WRITE_TO_DB + "=true", + RUN_ID + "=" + RUN1, + 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[3], 1); + + assertDataRowsHaveCorrectTestAndClientName("End To End 1", "", TestResultAggregator.ALL_PARTICIPANTS_NAME, csvLines[4], 1); + assertDataRowsHaveCorrectTestAndClientName("End To End 1", "", TestResultAggregator.ALL_CONSUMER_PARTICIPANTS_NAME, csvLines[2], 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[ParticipantAttribute.TEST_NAME.ordinal()]); + assertEquals("Unexpected client name in CSV line " + csvLine, clientName, cells[ParticipantAttribute.CONFIGURED_CLIENT_NAME.ordinal()]); + assertEquals("Unexpected participant name in CSV line " + csvLine, participantName, cells[ParticipantAttribute.PARTICIPANT_NAME.ordinal()]); + assertEquals("Unexpected number of messages processed in CSV line " + csvLine, String.valueOf(expectedNumberOfMessagesProcessed), cells[ParticipantAttribute.NUMBER_OF_MESSAGES_PROCESSED.ordinal()]); + + } + + 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/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/iteratingFeature.json b/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/iteratingFeature.json new file mode 100644 index 0000000000..89123302b7 --- /dev/null +++ b/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/iteratingFeature.json @@ -0,0 +1,63 @@ +{ + "_tests":[ + { + "_name": "Test iteration feature", + "_iterations":[ + { + "_messageSize": 100, + "_numberOfMessages": 10 + }, + { + "_messageSize": 200, + "_numberOfMessages": 5 + } + ], + "_queues":[ + { + "_name": "direct://amq.direct//testQueue" + } + ], + "_clients":[ + { + "_name": "producingClient", + "_connections":[ + { + "_name": "connection1", + "_factory": "connectionfactory", + "_sessions": [ + { + "_sessionName": "session1", + "_producers": [ + { + "_name": "participantProducer1", + "_destinationName": "direct://amq.direct//testQueue" + } + ] + } + ] + } + ] + }, + { + "_name": "consumingClient", + "_connections":[ + { + "_name": "connection1", + "_factory": "connectionfactory", + "_sessions": [ + { + "_sessionName": "session1", + "_consumers": [ + { + "_name": "participantConsumer1", + "_destinationName": "direct://amq.direct//testQueue" + } + ] + } + ] + } + ] + } + ] + }] +} \ No newline at end of file diff --git a/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/produceClient.json b/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/produceClient.json new file mode 100644 index 0000000000..605e5cb585 --- /dev/null +++ b/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/produceClient.json @@ -0,0 +1,41 @@ +{ + "_tests":[ + { + "_name": "Test 1"; + "_clients":[ + { + "_name": "producingClient", + "_connections":[ + { + "_name": "connection1", + "_factory": "connectionfactory", + "_sessions": [ + { + "_sessionName": "session1", + "_producers": [ + { + "_name": "participantProducer1", + "_destinationName": "direct://amq.direct//producerClient", + "_numberOfMessages": 10; + "_messageProviderName": "testProvider1" + } + ] + } + ] + } + ]; + "_messageProviders":[ + { + "_name": "testProvider1"; + "_messageProperties": { + "priority": {"@def": "list"; "_items": [0,1,2,3,4,5,6,7,8,9]}; + "id": {"@def": "range"; "_upper": 10; "_type": "int"}; + "test": "test-value" + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/producerAndConsumerInSeparateClients.json b/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/producerAndConsumerInSeparateClients.json new file mode 100644 index 0000000000..a008dc40d8 --- /dev/null +++ b/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/producerAndConsumerInSeparateClients.json @@ -0,0 +1,56 @@ +{ + "_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, + "_evaluateLatency": true + } + ] + } + ] + } + ] + } + ] + }] +} \ No newline at end of file diff --git a/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/producerAndThreeConsumersInSeparateClients.json b/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/producerAndThreeConsumersInSeparateClients.json new file mode 100644 index 0000000000..f94c4f0ae0 --- /dev/null +++ b/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/producerAndThreeConsumersInSeparateClients.json @@ -0,0 +1,77 @@ +{ + "_tests":[ + { + "_name": "ProducerAndThreeConsumersInSeparateClients"; + "_queues":[ + { + "_name": "direct://amq.direct//testQueue" + } + ]; + "_clients":[ + { + "_name": "producingClient", + "_connections":[ + { + "_name": "connection1", + "_factory": "connectionfactory", + "_sessions": [ + { + "_sessionName": "session1", + "_producers": [ + { + "_name": "participantProducer1", + "_destinationName": "direct://amq.direct//testQueue", + "_numberOfMessages": 9, + "_batchSize": 2, + "_interval": 50 + } + ] + } + ] + } + ] + }, + { + "_name": "consumingClient", + "_connections":[ + { + "_name": "connection1", + "_factory": "connectionfactory", + "_sessions": [ + { + "_sessionName": "session1", + "_consumers": [ + { + "_name": "participantConsumer1", + "_destinationName": "direct://amq.direct//testQueue", + "_numberOfMessages": 3 + } + ] + }, + { + "_sessionName": "session2", + "_consumers": [ + { + "_name": "participantConsumer2", + "_destinationName": "direct://amq.direct//testQueue", + "_numberOfMessages": 3 + } + ] + }, + { + "_sessionName": "session3", + "_consumers": [ + { + "_name": "participantConsumer3", + "_destinationName": "direct://amq.direct//testQueue", + "_numberOfMessages": 3 + } + ] + } + ] + } + ] + } + ] + }] +} \ No newline at end of file diff --git a/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/testWithTwoTests.json b/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/testWithTwoTests.json new file mode 100644 index 0000000000..4abd7f4feb --- /dev/null +++ b/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controllerandclient/testWithTwoTests.json @@ -0,0 +1,107 @@ +{ + "_tests":[ + { + "_name": "Test 1"; + "_queues":[ + { + "_name": "direct://amq.direct//testQueue" + } + ]; + "_clients":[ + { + "_name": "producingClient", + "_connections":[ + { + "_name": "connection1", + "_factory": "connectionfactory", + "_sessions": [ + { + "_sessionName": "session1", + "_producers": [ + { + "_name": "participantProducer1", + "_destinationName": "direct://amq.direct//testQueue", + "_numberOfMessages": 1 + } + ] + } + ] + } + ] + }, + { + "_name": "consumingClient", + "_connections":[ + { + "_name": "connection1", + "_factory": "connectionfactory", + "_sessions": [ + { + "_sessionName": "session1", + "_consumers": [ + { + "_name": "participantconsumer1", + "_destinationName": "direct://amq.direct//testQueue", + "_numberOfMessages": 1 + } + ] + } + ] + } + ] + } + ] + }, + { + "_name": "Test 2"; + "_queues":[ + { + "_name": "direct://amq.direct//testQueue2" + } + ]; + "_clients":[ + { + "_name": "producingClient", + "_connections":[ + { + "_name": "connection1", + "_factory": "connectionfactory", + "_sessions": [ + { + "_sessionName": "session1", + "_producers": [ + { + "_name": "participantProducer2", + "_destinationName": "direct://amq.direct//testQueue2", + "_numberOfMessages": 1 + } + ] + } + ] + } + ] + }, + { + "_name": "consumingClient", + "_connections":[ + { + "_name": "connection1", + "_factory": "connectionfactory", + "_sessions": [ + { + "_sessionName": "session1", + "_consumers": [ + { + "_name": "participantConsumer2", + "_destinationName": "direct://amq.direct//testQueue2", + "_numberOfMessages": 1 + } + ] + } + ] + } + ] + } + ] + }] +} \ No newline at end of file diff --git a/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controlleronly/distributedControllerTest.json b/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controlleronly/distributedControllerTest.json new file mode 100644 index 0000000000..b49603ef23 --- /dev/null +++ b/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/controlleronly/distributedControllerTest.json @@ -0,0 +1,17 @@ +{ + "_tests":[ + { + "_name": "Test 1"; + "_clients":[ + { + "_name": "client1", + "_connections":[ + { + "_name": "connection1", + "_factory": "connectionfactory" + } + ] + } + ] + }] +} \ No newline at end of file diff --git a/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/endtoend/endtoend.json b/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/endtoend/endtoend.json new file mode 100644 index 0000000000..1b7cc51265 --- /dev/null +++ b/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/endtoend/endtoend.json @@ -0,0 +1,65 @@ +{ + "_tests":[ + { + "_name": "End To End 1"; + "_queues":[ + { + "_name": "direct://amq.direct//testQueue" + } + ]; + "_clients":[ + { + "_name": "producingClient", + "_connections":[ + { + "_name": "connection1", + "_factory": "connectionfactory", + "_sessions": [ + { + "_sessionName": "session1", + "_producers": [ + { + "_name": "participantProducer1", + "_destinationName": "direct://amq.direct//testQueue", + "_numberOfMessages": 1 + } + ] + } + ]; + "_messageProviders":[ + { + "_name": "testProvider1"; + "_messageProperties": { + "priority": {"@def": "list"; "_items": [1,2,3,4,4]}; + "id": {"@def": "random"; "_upper": 10}; + "test": "test-value" + } + } + ] + } + ] + }, + { + "_name": "consumingClient", + "_connections":[ + { + "_name": "connection1", + "_factory": "connectionfactory", + "_sessions": [ + { + "_sessionName": "session1", + "_consumers": [ + { + "_name": "participantConsumer1", + "_destinationName": "direct://amq.direct//testQueue", + "_numberOfMessages": 1 + } + ] + } + ] + } + ] + } + ] + }] +} \ No newline at end of file diff --git a/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/perftests.systests.properties b/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/perftests.systests.properties new file mode 100644 index 0000000000..149e632048 --- /dev/null +++ b/qpid/java/qpid-perftests-systests/src/test/resources/org/apache/qpid/systest/disttest/perftests.systests.properties @@ -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. + +# 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 + +jdbcDriverClass=org.apache.derby.jdbc.EmbeddedDriver +jdbcUrl=jdbc:derby:/tmp/tempDbDirectory/perftestResultsDb;create=true diff --git a/qpid/java/qpid-systests-parent/pom.xml b/qpid/java/qpid-systests-parent/pom.xml index d59e373ed4..1225653650 100644 --- a/qpid/java/qpid-systests-parent/pom.xml +++ b/qpid/java/qpid-systests-parent/pom.xml @@ -74,20 +74,6 @@ - src/main/java - - - - src/main/resources - - - src/main/java - - **/*.java/ - - - - org.apache.maven.plugins diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.java deleted file mode 100644 index 3025414e4a..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.java +++ /dev/null @@ -1,145 +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; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.TextMessage; - -public class AMQQueueDeferredOrderingTest extends QpidBrokerTestCase -{ - private Connection con; - private Session session; - private AMQQueue queue; - private MessageConsumer consumer; - private int numMessages; - - private static final Logger _logger = LoggerFactory.getLogger(AMQQueueDeferredOrderingTest.class); - - private ASyncProducer producerThread; - - private class ASyncProducer extends Thread - { - - private MessageProducer producer; - private final Logger _logger = LoggerFactory.getLogger(ASyncProducer.class); - private Session session; - private int start; - private int end; - - public ASyncProducer(AMQQueue q, int start, int end) throws Exception - { - this.session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - this._logger.info("Create Consumer of Q1"); - this.producer = this.session.createProducer(q); - this.start = start; - this.end = end; - } - - public void run() - { - try - { - this._logger.info("Starting to send messages"); - for (int i = start; i < end && !interrupted(); i++) - { - producer.send(session.createTextMessage(Integer.toString(i))); - ((AMQSession)session).sync(); - } - this._logger.info("Sent " + (end - start) + " messages"); - } - catch (Exception e) - { - throw new RuntimeException(e); - } - } - } - - protected void setUp() throws Exception - { - super.setUp(); - - numMessages = isBrokerStorePersistent() ? 300 : 1000; - - _logger.info("Create Connection"); - con = getConnection(); - _logger.info("Create Session"); - session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - _logger.info("Create Q"); - queue = new AMQQueue(new AMQShortString("amq.direct"), new AMQShortString("Q"), new AMQShortString("Q"), - false, true); - _logger.info("Create Consumer of Q"); - consumer = session.createConsumer(queue); - _logger.info("Start Connection"); - con.start(); - } - - public void testMessagesSentByTwoThreadsAreDeliveredInOrder() throws Exception - { - - // Setup initial messages - _logger.info("Creating first producer thread"); - producerThread = new ASyncProducer(queue, 0, numMessages / 2); - producerThread.start(); - // Wait for them to be done - producerThread.join(); - - // Setup second set of messages to produce while we consume - _logger.info("Creating second producer thread"); - producerThread = new ASyncProducer(queue, numMessages / 2, numMessages); - producerThread.start(); - - // Start consuming and checking they're in order - _logger.info("Consuming messages"); - for (int i = 0; i < numMessages; i++) - { - Message msg = consumer.receive(3000); - assertNotNull("Message " + i + " should not be null", msg); - assertTrue("Message " + i + " should be a text message", msg instanceof TextMessage); - assertEquals("Message content " + i + "does not match expected", Integer.toString(i), ((TextMessage) msg).getText()); - } - } - - protected void tearDown() throws Exception - { - _logger.info("Interuptting producer thread"); - producerThread.interrupt(); - _logger.info("Closing connection"); - con.close(); - - super.tearDown(); - } - - public static junit.framework.Test suite() - { - return new junit.framework.TestSuite(AMQQueueDeferredOrderingTest.class); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/AMQTestConnection_0_10.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/AMQTestConnection_0_10.java deleted file mode 100644 index c5dd523214..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/client/AMQTestConnection_0_10.java +++ /dev/null @@ -1,34 +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; - -import org.apache.qpid.transport.Connection; - -public class AMQTestConnection_0_10 extends AMQConnection -{ - public AMQTestConnection_0_10(String url) throws Exception - { - super(url); - } - - public Connection getConnection() - { - return((AMQConnectionDelegate_0_10)getDelegate()).getQpidConnection(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/AsynchMessageListenerTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/AsynchMessageListenerTest.java deleted file mode 100644 index a13bf71d5e..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/client/AsynchMessageListenerTest.java +++ /dev/null @@ -1,362 +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; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.jms.Connection; -import javax.jms.ExceptionListener; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageListener; -import javax.jms.Queue; -import javax.jms.Session; - -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.util.LogMonitor; - -/** - * Tests the behaviour of JMS asynchronous message listeners as provided by - * {@link MessageListener#onMessage(Message)}. - * - */ -public class AsynchMessageListenerTest extends QpidBrokerTestCase -{ - private static final int MSG_COUNT = 10; - private static final long AWAIT_MESSAGE_TIMEOUT = 2000; - private static final long AWAIT_MESSAGE_TIMEOUT_NEGATIVE = 250; - private String _testQueueName; - private Connection _consumerConnection; - private Session _consumerSession; - private MessageConsumer _consumer; - private Queue _queue; - - protected void setUp() throws Exception - { - super.setUp(); - _testQueueName = getTestQueueName(); - _consumerConnection = getConnection(); - _consumerConnection.start(); - _consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - _queue = _consumerSession.createQueue(_testQueueName); - _consumer = _consumerSession.createConsumer(_queue); - - // Populate queue - Connection producerConnection = getConnection(); - Session producerSession = producerConnection.createSession(true, Session.SESSION_TRANSACTED); - sendMessage(producerSession, _queue, MSG_COUNT); - producerConnection.close(); - - } - - public void testMessageListener() throws Exception - { - CountingMessageListener countingMessageListener = new CountingMessageListener(MSG_COUNT); - _consumer.setMessageListener(countingMessageListener); - countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT); - - assertEquals("Unexpected number of outstanding messages", 0, countingMessageListener.getOutstandingCount()); - } - - public void testSynchronousReceiveFollowedByMessageListener() throws Exception - { - // Receive initial message synchronously - assertNotNull("Could not receive first message synchronously", _consumer.receive(AWAIT_MESSAGE_TIMEOUT) != null); - final int numberOfMessagesToReceiveByMessageListener = MSG_COUNT - 1; - - // Consume remainder asynchronously - CountingMessageListener countingMessageListener = new CountingMessageListener(numberOfMessagesToReceiveByMessageListener); - _consumer.setMessageListener(countingMessageListener); - countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT); - - assertEquals("Unexpected number of outstanding messages", 0, countingMessageListener.getOutstandingCount()); - } - - public void testMessageListenerSetDisallowsSynchronousReceive() throws Exception - { - CountingMessageListener countingMessageListener = new CountingMessageListener(MSG_COUNT); - _consumer.setMessageListener(countingMessageListener); - - try - { - _consumer.receive(); - fail("Exception not thrown"); - } - catch (JMSException e) - { - // PASS - assertEquals("A listener has already been set.", e.getMessage()); - } - } - - - public void testConnectionStopThenStart() throws Exception - { - int messageToReceivedBeforeConnectionStop = 2; - CountingMessageListener countingMessageListener = new CountingMessageListener(MSG_COUNT, messageToReceivedBeforeConnectionStop); - - // Consume at least two messages - _consumer.setMessageListener(countingMessageListener); - countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT); - - _consumerConnection.stop(); - - assertTrue("Too few messages received afer Connection#stop()", countingMessageListener.getReceivedCount() >= messageToReceivedBeforeConnectionStop); - countingMessageListener.resetLatch(); - - // Restart connection - _consumerConnection.start(); - - // Consume the remainder - countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT); - - assertEquals("Unexpected number of outstanding messages", 0, countingMessageListener.getOutstandingCount()); - } - - public void testConnectionStopAndMessageListenerChange() throws Exception - { - int messageToReceivedBeforeConnectionStop = 2; - CountingMessageListener countingMessageListener1 = new CountingMessageListener(MSG_COUNT, messageToReceivedBeforeConnectionStop); - - // Consume remainder asynchronously - _consumer.setMessageListener(countingMessageListener1); - countingMessageListener1.awaitMessages(AWAIT_MESSAGE_TIMEOUT); - - _consumerConnection.stop(); - assertTrue("Too few messages received afer Connection#stop()", countingMessageListener1.getReceivedCount() >= messageToReceivedBeforeConnectionStop); - - CountingMessageListener countingMessageListener2 = new CountingMessageListener(countingMessageListener1.getOutstandingCount()); - - // Reset Message Listener - _consumer.setMessageListener(countingMessageListener2); - - _consumerConnection.start(); - - // Consume the remainder - countingMessageListener2.awaitMessages(AWAIT_MESSAGE_TIMEOUT); - - assertEquals("Unexpected number of outstanding messages", 0, countingMessageListener2.getOutstandingCount()); - - } - - public void testConnectionStopHaltsDeliveryToListener() throws Exception - { - int messageToReceivedBeforeConnectionStop = 2; - CountingMessageListener countingMessageListener = new CountingMessageListener(MSG_COUNT, messageToReceivedBeforeConnectionStop); - - // Consume at least two messages - _consumer.setMessageListener(countingMessageListener); - countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT); - - _consumerConnection.stop(); - - // Connection should now be stopped and listener should receive no more - final int outstandingCountAtStop = countingMessageListener.getOutstandingCount(); - countingMessageListener.resetLatch(); - countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT_NEGATIVE); - - assertEquals("Unexpected number of outstanding messages", outstandingCountAtStop, countingMessageListener.getOutstandingCount()); - } - - public void testSessionCloseHaltsDelivery() throws Exception - { - int messageToReceivedBeforeConnectionStop = 2; - CountingMessageListener countingMessageListener = new CountingMessageListener(MSG_COUNT, messageToReceivedBeforeConnectionStop); - - // Consume at least two messages - _consumer.setMessageListener(countingMessageListener); - countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT); - - _consumerSession.close(); - - // Once a session is closed, the listener should receive no more - final int outstandingCountAtClose = countingMessageListener.getOutstandingCount(); - countingMessageListener.resetLatch(); - countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT_NEGATIVE); - - assertEquals("Unexpected number of outstanding messages", outstandingCountAtClose, countingMessageListener.getOutstandingCount()); - } - - public void testImmediatePrefetchWithMessageListener() throws Exception - { - // Close connection provided by setup so we can set IMMEDIATE_PREFETCH - _consumerConnection.close(); - setTestClientSystemProperty(AMQSession.IMMEDIATE_PREFETCH, "true"); - - _consumerConnection = getConnection(); - _consumerConnection.start(); - _consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - _consumer = _consumerSession.createConsumer(_queue); - CountingMessageListener countingMessageListener = new CountingMessageListener(MSG_COUNT); - _consumer.setMessageListener(countingMessageListener); - - countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT); - - assertEquals("Unexpected number of messages received", MSG_COUNT, countingMessageListener.getReceivedCount()); - } - - public void testReceiveTwoConsumers() throws Exception - { - Session consumerSession2 = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer _consumer2 = consumerSession2.createConsumer(_queue); - - CountingMessageListener countingMessageListener = new CountingMessageListener(MSG_COUNT); - _consumer.setMessageListener(countingMessageListener); - _consumer2.setMessageListener(countingMessageListener); - - countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT); - assertEquals("Unexpected number of messages received", MSG_COUNT, countingMessageListener.getReceivedCount()); - } - - /** - * Tests the case where the message listener throws an java.lang.Error. - * TODO - a useful test?. - */ - public void testMessageListenerThrowsError() throws Exception - { - int expectedMessages = 1; // The error will kill the dispatcher so only one message will be delivered. - final CountDownLatch awaitMessages = new CountDownLatch(expectedMessages); - final AtomicInteger receivedCount = new AtomicInteger(0); - final String javaLangErrorMessageText = "MessageListener failed with java.lang.Error"; - CountingExceptionListener countingExceptionListener = new CountingExceptionListener(); - _consumerConnection.setExceptionListener(countingExceptionListener); - - _consumer.setMessageListener(new MessageListener() - { - @Override - public void onMessage(Message message) - { - try - { - throw new Error(javaLangErrorMessageText); - } - finally - { - receivedCount.incrementAndGet(); - awaitMessages.countDown(); - } - } - }); - - awaitMessages.await(AWAIT_MESSAGE_TIMEOUT, TimeUnit.MILLISECONDS); - - assertEquals("Unexpected number of messages received", expectedMessages, receivedCount.get()); - assertEquals("onException should NOT have been called", 0, countingExceptionListener.getErrorCount()); - - // Check that Error has been written to the application log. - - LogMonitor _monitor = new LogMonitor(_outputFile); - assertTrue("The expected message not written to log file.", - _monitor.waitForMessage(javaLangErrorMessageText, LOGMONITOR_TIMEOUT)); - - if (_consumerConnection != null) - { - try - { - _consumerConnection.close(); - } - catch (JMSException e) - { - // Ignore connection close errors for this test. - } - finally - { - _consumerConnection = null; - } - } - } - - private final class CountingExceptionListener implements ExceptionListener - { - private final AtomicInteger _errorCount = new AtomicInteger(); - - @Override - public void onException(JMSException arg0) - { - _errorCount.incrementAndGet(); - } - - public int getErrorCount() - { - return _errorCount.intValue(); - } - } - - private final class CountingMessageListener implements MessageListener - { - private volatile CountDownLatch _awaitMessages; - private final AtomicInteger _receivedCount; - private final AtomicInteger _outstandingMessageCount; - - public CountingMessageListener(final int totalExpectedMessageCount) - { - this(totalExpectedMessageCount, totalExpectedMessageCount); - } - - - public CountingMessageListener(int totalExpectedMessageCount, int numberOfMessagesToAwait) - { - _receivedCount = new AtomicInteger(0); - _outstandingMessageCount = new AtomicInteger(totalExpectedMessageCount); - _awaitMessages = new CountDownLatch(numberOfMessagesToAwait); - } - - public int getOutstandingCount() - { - return _outstandingMessageCount.get(); - } - - public int getReceivedCount() - { - return _receivedCount.get(); - } - - public void resetLatch() - { - _awaitMessages = new CountDownLatch(_outstandingMessageCount.get()); - } - - @Override - public void onMessage(Message message) - { - _receivedCount.incrementAndGet(); - _outstandingMessageCount.decrementAndGet(); - _awaitMessages.countDown(); - } - - public boolean awaitMessages(long timeout) - { - try - { - return _awaitMessages.await(timeout, TimeUnit.MILLISECONDS); - } - catch (InterruptedException e) - { - Thread.currentThread().interrupt(); - return false; - } - } - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/HeartbeatTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/HeartbeatTest.java deleted file mode 100644 index 881a37a970..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/client/HeartbeatTest.java +++ /dev/null @@ -1,224 +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; - -import static org.apache.qpid.configuration.ClientProperties.AMQJ_HEARTBEAT_DELAY; -import static org.apache.qpid.configuration.ClientProperties.IDLE_TIMEOUT_PROP_NAME; -import static org.apache.qpid.configuration.ClientProperties.QPID_HEARTBEAT_INTERVAL; - -import java.util.concurrent.atomic.AtomicInteger; - -import javax.jms.Destination; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; - -import org.apache.log4j.Logger; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class HeartbeatTest extends QpidBrokerTestCase -{ - private static final Logger LOGGER = Logger.getLogger(HeartbeatTest.class); - - private static final String CONNECTION_URL_WITH_HEARTBEAT = "amqp://guest:guest@clientid/?brokerlist='localhost:%d?heartbeat='%d''"; - private TestListener _listener = new TestListener("listener"); - - @Override - public void setUp() throws Exception - { - if (getName().equals("testHeartbeatsEnabledBrokerSide")) - { - getBrokerConfiguration().setBrokerAttribute(Broker.CONNECTION_HEART_BEAT_DELAY, "1"); - } - super.setUp(); - } - - public void testHeartbeatsEnabledUsingUrl() throws Exception - { - final String url = String.format(CONNECTION_URL_WITH_HEARTBEAT, DEFAULT_PORT, 1); - AMQConnection conn = (AMQConnection) getConnection(new AMQConnectionURL(url)); - conn.setHeartbeatListener(_listener); - conn.start(); - - Thread.sleep(2500); - - assertTrue("Too few heartbeats received: "+_listener.getHeartbeatsReceived() +" (expected at least 2)", _listener.getHeartbeatsReceived() >=2); - assertTrue("Too few heartbeats sent "+_listener.getHeartbeatsSent() +" (expected at least 2)", _listener.getHeartbeatsSent() >=2); - - conn.close(); - } - - public void testHeartbeatsEnabledUsingSystemProperty() throws Exception - { - setTestSystemProperty(QPID_HEARTBEAT_INTERVAL, "1"); - AMQConnection conn = (AMQConnection) getConnection(); - conn.setHeartbeatListener(_listener); - conn.start(); - - Thread.sleep(2500); - - assertTrue("Too few heartbeats received: "+_listener.getHeartbeatsReceived() +" (expected at least 2)", _listener.getHeartbeatsReceived() >=2); - assertTrue("Too few heartbeats sent "+_listener.getHeartbeatsSent() +" (expected at least 2)", _listener.getHeartbeatsSent() >=2); - - conn.close(); - } - - public void testHeartbeatsDisabledUsingSystemProperty() throws Exception - { - setTestSystemProperty(QPID_HEARTBEAT_INTERVAL, "0"); - AMQConnection conn = (AMQConnection) getConnection(); - conn.setHeartbeatListener(_listener); - conn.start(); - - Thread.sleep(2500); - - assertEquals("Heartbeats unexpectedly received", 0, _listener.getHeartbeatsReceived()); - assertEquals("Heartbeats unexpectedly sent ", 0, _listener.getHeartbeatsSent()); - - conn.close(); - } - - /** - * This test carefully arranges message flow so that bytes flow only from producer to broker - * on the producer side and broker to consumer on the consumer side, deliberately leaving the - * reverse path quiet so heartbeats will flow. - */ - public void testUnidirectionalHeartbeating() throws Exception - { - setTestSystemProperty(QPID_HEARTBEAT_INTERVAL,"1"); - AMQConnection receiveConn = (AMQConnection) getConnection(); - AMQConnection sendConn = (AMQConnection) getConnection(); - Destination destination = getTestQueue(); - TestListener receiveListener = new TestListener("receiverListener"); - TestListener sendListener = new TestListener("senderListener"); - - - Session receiveSession = receiveConn.createSession(false, Session.CLIENT_ACKNOWLEDGE); - Session senderSession = sendConn.createSession(false, Session.CLIENT_ACKNOWLEDGE); - - MessageConsumer consumer = receiveSession.createConsumer(destination); - MessageProducer producer = senderSession.createProducer(destination); - - receiveConn.setHeartbeatListener(receiveListener); - sendConn.setHeartbeatListener(sendListener); - receiveConn.start(); - - for(int i = 0; i < 5; i++) - { - producer.send(senderSession.createTextMessage("Msg " + i)); - Thread.sleep(500); - assertNotNull("Expected to received message", consumer.receive(500)); - // Consumer does not ack the message in order to generate no bytes from consumer back to Broker - } - - assertTrue("Too few heartbeats sent "+ receiveListener.getHeartbeatsSent() +" (expected at least 2)", receiveListener.getHeartbeatsSent()>=2); - assertEquals("Unexpected number of heartbeats sent by the sender: ",0,sendListener.getHeartbeatsSent()); - - assertTrue("Too few heartbeats received at the sender "+ sendListener.getHeartbeatsReceived() +" (expected at least 2)", sendListener.getHeartbeatsReceived()>=2); - assertEquals("Unexpected number of heartbeats received by the receiver: ",0,receiveListener.getHeartbeatsReceived()); - - receiveConn.close(); - sendConn.close(); - } - - public void testHeartbeatsEnabledBrokerSide() throws Exception - { - - AMQConnection conn = (AMQConnection) getConnection(); - conn.setHeartbeatListener(_listener); - conn.start(); - - Thread.sleep(2500); - - assertTrue("Too few heartbeats received: "+_listener.getHeartbeatsReceived() +" (expected at least 2)", _listener.getHeartbeatsReceived()>=2); - assertTrue("Too few heartbeats sent "+ _listener.getHeartbeatsSent() +" (expected at least 2)", _listener.getHeartbeatsSent() >=2); - - conn.close(); - } - - - @SuppressWarnings("deprecation") - public void testHeartbeatsEnabledUsingAmqjLegacySystemProperty() throws Exception - { - setTestSystemProperty(AMQJ_HEARTBEAT_DELAY, "1"); - AMQConnection conn = (AMQConnection) getConnection(); - conn.setHeartbeatListener(_listener); - conn.start(); - - Thread.sleep(2500); - - assertTrue("Too few heartbeats received: "+_listener.getHeartbeatsReceived()+" (expected at least 2)", _listener.getHeartbeatsReceived()>=2); - assertTrue("Too few heartbeats sent "+_listener.getHeartbeatsSent() +" (expected at least 2)", _listener.getHeartbeatsSent()>=2); - - conn.close(); - } - - @SuppressWarnings("deprecation") - public void testHeartbeatsEnabledUsingOlderLegacySystemProperty() throws Exception - { - setTestSystemProperty(IDLE_TIMEOUT_PROP_NAME, "1000"); - AMQConnection conn = (AMQConnection) getConnection(); - conn.setHeartbeatListener(_listener); - conn.start(); - - Thread.sleep(2500); - - assertTrue("Too few heartbeats received: "+_listener.getHeartbeatsReceived() +" (expected at least 2)", _listener.getHeartbeatsReceived()>=2); - assertTrue("Too few heartbeats sent "+_listener.getHeartbeatsSent() +" (expected at least 2)", _listener.getHeartbeatsSent()>=2); - - conn.close(); - } - - private class TestListener implements HeartbeatListener - { - private final String _name; - private final AtomicInteger _heartbeatsReceived = new AtomicInteger(0); - private final AtomicInteger _heartbeatsSent = new AtomicInteger(0); - - public TestListener(String name) - { - _name = name; - } - - @Override - public void heartbeatReceived() - { - LOGGER.debug(_name + " heartbeat received"); - _heartbeatsReceived.incrementAndGet(); - } - - public int getHeartbeatsReceived() - { - return _heartbeatsReceived.get(); - } - - @Override - public void heartbeatSent() - { - LOGGER.debug(_name + " heartbeat sent"); - _heartbeatsSent.incrementAndGet(); - } - - public int getHeartbeatsSent() - { - return _heartbeatsSent.get(); - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/SessionCreateTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/SessionCreateTest.java deleted file mode 100644 index 08ed2258b2..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/client/SessionCreateTest.java +++ /dev/null @@ -1,61 +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; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.Session; - - -/** - * Class to check that session creation on a connection has no accidental limit - */ -public class SessionCreateTest extends QpidBrokerTestCase -{ - private static final Logger LOGGER = LoggerFactory.getLogger(SessionCreateTest.class); - - private Connection _clientConnection; - protected int maxSessions = 65555; - - public void testSessionCreationLimit() throws Exception - { - // Create Client - _clientConnection = getConnection("guest", "guest"); - - _clientConnection.start(); - - for (int i=0; i < maxSessions; i++) - { - Session sess = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - assertNotNull(sess); - sess.close(); - LOGGER.debug("created session: " + i); - } - - _clientConnection.close(); - - } - -} \ No newline at end of file diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/SynchReceiveTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/SynchReceiveTest.java deleted file mode 100644 index bf147197e4..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/client/SynchReceiveTest.java +++ /dev/null @@ -1,133 +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; - -import javax.jms.Connection; -import javax.jms.MessageConsumer; -import javax.jms.Queue; -import javax.jms.Session; - -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class SynchReceiveTest extends QpidBrokerTestCase -{ - private static final long AWAIT_MESSAGE_TIMEOUT = 2000; - private static final long AWAIT_MESSAGE_TIMEOUT_NEGATIVE = 250; - private static final int MSG_COUNT = 10; - private final String _testQueueName = getTestQueueName(); - private Connection _consumerConnection; - private Session _consumerSession; - private MessageConsumer _consumer; - private Queue _queue; - - protected void setUp() throws Exception - { - super.setUp(); - - _consumerConnection = getConnection(); - _consumerConnection.start(); - _consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - _queue = _consumerSession.createQueue(_testQueueName); - _consumer = _consumerSession.createConsumer(_queue); - - // Populate queue - Connection producerConnection = getConnection(); - Session producerSession = producerConnection.createSession(true, Session.SESSION_TRANSACTED); - sendMessage(producerSession, _queue, MSG_COUNT); - producerConnection.close(); - } - - public void testReceiveWithTimeout() throws Exception - { - for (int msg = 0; msg < MSG_COUNT; msg++) - { - assertNotNull("Expected message number " + msg, _consumer.receive(AWAIT_MESSAGE_TIMEOUT)); - } - - assertNull("Received too many messages", _consumer.receive(500)); - } - - public void testReceiveNoWait() throws Exception - { - for (int msg = 0; msg < MSG_COUNT; msg++) - { - assertNotNull("Expected message number " + msg, _consumer.receiveNoWait()); - } - - assertNull("Received too many messages", _consumer.receive(500)); - } - - public void testTwoConsumersInterleaved() throws Exception - { - //create a new connection with prefetch set to 1 - _consumerConnection.close(); - setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, new Integer(1).toString()); - - _consumerConnection = getConnection(); - _consumerConnection.start(); - Session consumerSession1 = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer consumer1 = consumerSession1.createConsumer(_queue); - - Session consumerSession2 = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer consumer2 = consumerSession2.createConsumer(_queue); - - final int maxLoops = MSG_COUNT * 2; - int msg = 0; - int loops = 0; - while(msg < MSG_COUNT && loops < maxLoops) - { - if (consumer1.receive(AWAIT_MESSAGE_TIMEOUT) != null) - { - msg++; - } - - if (consumer2.receive(AWAIT_MESSAGE_TIMEOUT) != null) - { - msg++; - } - - loops++; - } - - assertEquals("Not all messages received.", MSG_COUNT, msg); - assertNull("Received too many messages", consumer1.receive(AWAIT_MESSAGE_TIMEOUT_NEGATIVE)); - assertNull("Received too many messages", consumer2.receive(AWAIT_MESSAGE_TIMEOUT_NEGATIVE)); - } - - public void testIdleSecondConsumer() throws Exception - { - Session idleSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - @SuppressWarnings("unused") - MessageConsumer idleConsumerOnSameQueue = idleSession.createConsumer(_queue); - - // Since we don't call receive on the idle consumer, all messages will flow to other - - for (int msg = 0; msg < MSG_COUNT; msg++) - { - assertNotNull("Expected message number " + msg, _consumer.receive(AWAIT_MESSAGE_TIMEOUT)); - } - - assertNull("Received too many messages", _consumer.receive(AWAIT_MESSAGE_TIMEOUT_NEGATIVE)); - } - - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/failover/AddressBasedFailoverBehaviourTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/failover/AddressBasedFailoverBehaviourTest.java deleted file mode 100644 index 99fcbc5dc0..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/client/failover/AddressBasedFailoverBehaviourTest.java +++ /dev/null @@ -1,34 +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.failover; - -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Session; - -public class AddressBasedFailoverBehaviourTest extends FailoverBehaviourTest -{ - @Override - protected Destination createDestination(Session session) throws JMSException - { - return session.createQueue("ADDR:" +getTestQueueName() + "_" + System.currentTimeMillis() + "; {create: always}"); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/failover/FailoverBehaviourTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/failover/FailoverBehaviourTest.java deleted file mode 100644 index 3331a8a665..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/client/failover/FailoverBehaviourTest.java +++ /dev/null @@ -1,1436 +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.failover; - -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQConnectionFactory; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.jms.BrokerDetails; -import org.apache.qpid.jms.ConnectionListener; -import org.apache.qpid.jms.FailoverPolicy; -import org.apache.qpid.test.utils.FailoverBaseCase; -import org.apache.qpid.url.URLSyntaxException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.jms.Connection; -import javax.jms.ConnectionFactory; -import javax.jms.Destination; -import javax.jms.ExceptionListener; -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.QueueBrowser; -import javax.jms.Session; -import javax.jms.TextMessage; -import javax.jms.TransactionRolledBackException; -import javax.naming.NamingException; - -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Test suite to test all possible failover corner cases - */ -public class FailoverBehaviourTest extends FailoverBaseCase implements ConnectionListener, ExceptionListener -{ - protected static final Logger _LOGGER = LoggerFactory.getLogger(FailoverBehaviourTest.class); - - private static final String TEST_MESSAGE_FORMAT = "test message {0}"; - - /** Indicates whether tests are run against clustered broker */ - private static boolean CLUSTERED = Boolean.getBoolean("profile.clustered"); - - /** Default number of messages to send before failover */ - private static final int DEFAULT_NUMBER_OF_MESSAGES = 40; - - /** Actual number of messages to send before failover */ - protected int _messageNumber = Integer.getInteger("profile.failoverMsgCount", DEFAULT_NUMBER_OF_MESSAGES); - - /** Test connection */ - protected Connection _connection; - - /** - * Failover completion latch is used to wait till connectivity to broker is - * restored - */ - private CountDownLatch _failoverComplete; - - /** - * Consumer session - */ - private Session _consumerSession; - - /** - * Test destination - */ - private Destination _destination; - - /** - * Consumer - */ - private MessageConsumer _consumer; - - /** - * Producer session - */ - private Session _producerSession; - - /** - * Producer - */ - private MessageProducer _producer; - - /** - * Holds exception sent into {@link ExceptionListener} on failover - */ - private JMSException _exceptionListenerException; - - /** - * Latch to check that failover mutex is hold by a failover thread - */ - private CountDownLatch _failoverStarted; - - @Override - protected void setUp() throws Exception - { - super.setUp(); - - _connection = getConnection(); - _connection.setExceptionListener(this); - ((AMQConnection) _connection).setConnectionListener(this); - _failoverComplete = new CountDownLatch(1); - _failoverStarted = new CountDownLatch(1); - } - - /** - * Test whether MessageProducer can successfully publish messages after - * failover and rollback transaction - */ - public void testMessageProducingAndRollbackAfterFailover() throws Exception - { - init(Session.SESSION_TRANSACTED, true); - produceMessages(); - causeFailure(); - - assertFailoverException(); - // producer should be able to send messages after failover - _producer.send(_producerSession.createTextMessage("test message " + _messageNumber)); - - // rollback after failover - _producerSession.rollback(); - - // tests whether sending and committing is working after failover - produceMessages(); - _producerSession.commit(); - - // tests whether receiving and committing is working after failover - consumeMessages(); - _consumerSession.commit(); - } - - /** - * Test whether {@link TransactionRolledBackException} is thrown on commit - * of dirty transacted session after failover. - *

- * Verifies whether second after failover commit is successful. - */ - public void testTransactionRolledBackExceptionThrownOnCommitAfterFailoverOnProducingMessages() throws Exception - { - init(Session.SESSION_TRANSACTED, true); - produceMessages(); - causeFailure(); - - assertFailoverException(); - - // producer should be able to send messages after failover - _producer.send(_producerSession.createTextMessage("test message " + _messageNumber)); - - try - { - _producerSession.commit(); - fail("TransactionRolledBackException is expected on commit after failover with dirty session!"); - } - catch (JMSException t) - { - assertTrue("Expected TransactionRolledBackException but thrown " + t, - t instanceof TransactionRolledBackException); - } - - // simulate process of user replaying the transaction - produceMessages("replayed test message {0}", _messageNumber, false); - - // no exception should be thrown - _producerSession.commit(); - - // only messages sent after rollback should be received - consumeMessages("replayed test message {0}", _messageNumber); - - // no exception should be thrown - _consumerSession.commit(); - } - - /** - * Tests JMSException is not thrown on commit with a clean session after - * failover - */ - public void testNoJMSExceptionThrownOnCommitAfterFailoverWithCleanProducerSession() throws Exception - { - init(Session.SESSION_TRANSACTED, true); - - causeFailure(); - - assertFailoverException(); - - // should not throw an exception for a clean session - _producerSession.commit(); - - // tests whether sending and committing is working after failover - produceMessages(); - _producerSession.commit(); - - // tests whether receiving and committing is working after failover - consumeMessages(); - _consumerSession.commit(); - } - - /** - * Tests {@link TransactionRolledBackException} is thrown on commit of dirty - * transacted session after failover. - *

- * Verifies whether second after failover commit is successful. - */ - public void testTransactionRolledBackExceptionThrownOnCommitAfterFailoverOnMessageReceiving() throws Exception - { - init(Session.SESSION_TRANSACTED, true); - produceMessages(); - _producerSession.commit(); - - // receive messages but do not commit - consumeMessages(); - - causeFailure(); - - assertFailoverException(); - - try - { - // should throw TransactionRolledBackException - _consumerSession.commit(); - fail("TransactionRolledBackException is expected on commit after failover"); - } - catch (Exception t) - { - assertTrue("Expected TransactionRolledBackException but thrown " + t, - t instanceof TransactionRolledBackException); - } - - resendMessagesIfNecessary(); - - // consume messages successfully - consumeMessages(); - _consumerSession.commit(); - } - - /** - * Tests JMSException is not thrown on commit with a clean session after failover - */ - public void testNoJMSExceptionThrownOnCommitAfterFailoverWithCleanConsumerSession() throws Exception - { - init(Session.SESSION_TRANSACTED, true); - produceMessages(); - _producerSession.commit(); - - consumeMessages(); - _consumerSession.commit(); - - causeFailure(); - - assertFailoverException(); - - // should not throw an exception with a clean consumer session - _consumerSession.commit(); - } - - /** - * Test that TransactionRolledBackException is thrown on commit of - * dirty session in asynchronous consumer after failover. - */ - public void testTransactionRolledBackExceptionThrownOnCommitAfterFailoverOnReceivingMessagesAsynchronously() - throws Exception - { - init(Session.SESSION_TRANSACTED, false); - FailoverTestMessageListener ml = new FailoverTestMessageListener(); - _consumer.setMessageListener(ml); - - _connection.start(); - - produceMessages(); - _producerSession.commit(); - - // wait for message receiving - ml.awaitForEnd(); - - assertEquals("Received unexpected number of messages!", _messageNumber, ml.getMessageCounter()); - - // assert messages - int counter = 0; - for (Message message : ml.getReceivedMessages()) - { - assertReceivedMessage(message, TEST_MESSAGE_FORMAT, counter++); - } - ml.reset(); - - causeFailure(); - assertFailoverException(); - - - try - { - _consumerSession.commit(); - fail("TransactionRolledBackException should be thrown!"); - } - catch (TransactionRolledBackException e) - { - // that is what is expected - } - - resendMessagesIfNecessary(); - - // wait for message receiving - ml.awaitForEnd(); - - assertEquals("Received unexpected number of messages!", _messageNumber, ml.getMessageCounter()); - - // assert messages - counter = 0; - for (Message message : ml.getReceivedMessages()) - { - assertReceivedMessage(message, TEST_MESSAGE_FORMAT, counter++); - } - - // commit again. It should be successful - _consumerSession.commit(); - } - - /** - * Test that {@link Session#rollback()} does not throw exception after failover - * and that we are able to consume messages. - */ - public void testRollbackAfterFailover() throws Exception - { - init(Session.SESSION_TRANSACTED, true); - - produceMessages(); - _producerSession.commit(); - - consumeMessages(); - - causeFailure(); - - assertFailoverException(); - - _consumerSession.rollback(); - - resendMessagesIfNecessary(); - - // tests whether receiving and committing is working after failover - consumeMessages(); - _consumerSession.commit(); - } - - /** - * Test that {@link Session#rollback()} does not throw exception after receiving further messages - * after failover, and we can receive published messages after rollback. - */ - public void testRollbackAfterReceivingAfterFailover() throws Exception - { - init(Session.SESSION_TRANSACTED, true); - - produceMessages(); - _producerSession.commit(); - - consumeMessages(); - causeFailure(); - - assertFailoverException(); - - resendMessagesIfNecessary(); - - consumeMessages(); - - _consumerSession.rollback(); - - // tests whether receiving and committing is working after failover - consumeMessages(); - _consumerSession.commit(); - } - - /** - * Test that {@link Session#recover()} does not throw an exception after failover - * and that we can consume messages after recover. - */ - public void testRecoverAfterFailover() throws Exception - { - init(Session.CLIENT_ACKNOWLEDGE, true); - - produceMessages(); - - // consume messages but do not acknowledge them - consumeMessages(); - - causeFailure(); - - assertFailoverException(); - - _consumerSession.recover(); - - resendMessagesIfNecessary(); - - // tests whether receiving and acknowledgment is working after recover - Message lastMessage = consumeMessages(); - lastMessage.acknowledge(); - } - - /** - * Test that receiving more messages after failover and then calling - * {@link Session#recover()} does not throw an exception - * and that we can consume messages after recover. - */ - public void testRecoverWithConsumedMessagesAfterFailover() throws Exception - { - init(Session.CLIENT_ACKNOWLEDGE, true); - - produceMessages(); - - // consume messages but do not acknowledge them - consumeMessages(); - - causeFailure(); - - assertFailoverException(); - - // publishing should work after failover - resendMessagesIfNecessary(); - - // consume messages again on a dirty session - consumeMessages(); - - // recover should successfully restore session - _consumerSession.recover(); - - // tests whether receiving and acknowledgment is working after recover - Message lastMessage = consumeMessages(); - lastMessage.acknowledge(); - } - - /** - * Test that first call to {@link Message#acknowledge()} after failover - * throws a JMSEXception if session is dirty. - */ - public void testAcknowledgeAfterFailover() throws Exception - { - init(Session.CLIENT_ACKNOWLEDGE, true); - - produceMessages(); - - // consume messages but do not acknowledge them - Message lastMessage = consumeMessages(); - causeFailure(); - - assertFailoverException(); - - try - { - // an implicit recover performed when acknowledge throws an exception due to failover - lastMessage.acknowledge(); - fail("JMSException should be thrown"); - } - catch (JMSException t) - { - // TODO: assert error code and/or expected exception type - } - - resendMessagesIfNecessary(); - - // tests whether receiving and acknowledgment is working after recover - lastMessage = consumeMessages(); - lastMessage.acknowledge(); - } - - /** - * Test that calling acknowledge before failover leaves the session - * clean for use after failover. - */ - public void testAcknowledgeBeforeFailover() throws Exception - { - init(Session.CLIENT_ACKNOWLEDGE, true); - - produceMessages(); - - // consume messages and acknowledge them - Message lastMessage = consumeMessages(); - lastMessage.acknowledge(); - - causeFailure(); - - assertFailoverException(); - - produceMessages(); - - // tests whether receiving and acknowledgment is working after recover - lastMessage = consumeMessages(); - lastMessage.acknowledge(); - } - - /** - * Test that receiving of messages after failover prior to calling - * {@link Message#acknowledge()} still results in acknowledge throwing an exception. - */ - public void testAcknowledgeAfterMessageReceivingAfterFailover() throws Exception - { - init(Session.CLIENT_ACKNOWLEDGE, true); - - produceMessages(); - - // consume messages but do not acknowledge them - consumeMessages(); - causeFailure(); - - assertFailoverException(); - - resendMessagesIfNecessary(); - - // consume again on dirty session - Message lastMessage = consumeMessages(); - try - { - // an implicit recover performed when acknowledge throws an exception due to failover - lastMessage.acknowledge(); - fail("JMSException should be thrown"); - } - catch (JMSException t) - { - // TODO: assert error code and/or expected exception type - } - - // tests whether receiving and acknowledgment is working on a clean session - lastMessage = consumeMessages(); - lastMessage.acknowledge(); - } - - /** - * Tests that call to {@link Message#acknowledge()} after failover throws an exception in asynchronous consumer - * and we can consume messages after acknowledge. - */ - public void testAcknowledgeAfterFailoverForAsynchronousConsumer() throws Exception - { - init(Session.CLIENT_ACKNOWLEDGE, false); - FailoverTestMessageListener ml = new FailoverTestMessageListener(); - _consumer.setMessageListener(ml); - _connection.start(); - - produceMessages(); - - // wait for message receiving - ml.awaitForEnd(); - - assertEquals("Received unexpected number of messages!", _messageNumber, ml.getMessageCounter()); - - // assert messages - int counter = 0; - Message currentMessage = null; - for (Message message : ml.getReceivedMessages()) - { - assertReceivedMessage(message, TEST_MESSAGE_FORMAT, counter++); - currentMessage = message; - } - ml.reset(); - - causeFailure(); - assertFailoverException(); - - - try - { - currentMessage.acknowledge(); - fail("JMSException should be thrown!"); - } - catch (JMSException e) - { - // TODO: assert error code and/or expected exception type - } - - resendMessagesIfNecessary(); - - // wait for message receiving - ml.awaitForEnd(); - - assertEquals("Received unexpected number of messages!", _messageNumber, ml.getMessageCounter()); - - // assert messages - counter = 0; - for (Message message : ml.getReceivedMessages()) - { - assertReceivedMessage(message, TEST_MESSAGE_FORMAT, counter++); - currentMessage = message; - } - - // acknowledge again. It should be successful - currentMessage.acknowledge(); - } - - /** - * Test whether {@link Session#recover()} works as expected after failover - * in AA mode. - */ - public void testRecoverAfterFailoverInAutoAcknowledgeMode() throws Exception - { - init(Session.AUTO_ACKNOWLEDGE, true); - - produceMessages(); - - // receive first message in order to start a dispatcher thread - Message receivedMessage = _consumer.receive(1000l); - assertReceivedMessage(receivedMessage, TEST_MESSAGE_FORMAT, 0); - - causeFailure(); - - assertFailoverException(); - - _consumerSession.recover(); - - resendMessagesIfNecessary(); - - // tests whether receiving is working after recover - consumeMessages(); - } - - public void testClientAcknowledgedSessionCloseAfterFailover() throws Exception - { - sessionCloseAfterFailoverImpl(Session.CLIENT_ACKNOWLEDGE); - } - - public void testTransactedSessionCloseAfterFailover() throws Exception - { - sessionCloseAfterFailoverImpl(Session.SESSION_TRANSACTED); - } - - public void testAutoAcknowledgedSessionCloseAfterFailover() throws Exception - { - sessionCloseAfterFailoverImpl(Session.AUTO_ACKNOWLEDGE); - } - - public void testPublishAutoAcknowledgedWhileFailover() throws Exception - { - publishWhileFailingOver(Session.AUTO_ACKNOWLEDGE); - } - - public void testPublishClientAcknowledgedWhileFailover() throws Exception - { - Message receivedMessage = publishWhileFailingOver(Session.CLIENT_ACKNOWLEDGE); - receivedMessage.acknowledge(); - } - - public void testPublishTransactedAcknowledgedWhileFailover() throws Exception - { - publishWhileFailingOver(Session.SESSION_TRANSACTED); - _consumerSession.commit(); - } - - public void testPublishAutoAcknowledgedWithFailoverMutex() throws Exception - { - publishWithFailoverMutex(Session.AUTO_ACKNOWLEDGE); - } - - public void testPublishClientAcknowledgedWithFailoverMutex() throws Exception - { - publishWithFailoverMutex(Session.CLIENT_ACKNOWLEDGE); - - } - - public void testPublishTransactedAcknowledgedWithFailoverMutex() throws Exception - { - publishWithFailoverMutex(Session.SESSION_TRANSACTED); - } - - public void testClientAcknowledgedSessionCloseWhileFailover() throws Exception - { - sessionCloseWhileFailoverImpl(Session.CLIENT_ACKNOWLEDGE); - } - - public void testTransactedSessionCloseWhileFailover() throws Exception - { - sessionCloseWhileFailoverImpl(Session.SESSION_TRANSACTED); - } - - public void testAutoAcknowledgedSessionCloseWhileFailover() throws Exception - { - sessionCloseWhileFailoverImpl(Session.AUTO_ACKNOWLEDGE); - } - - public void testClientAcknowledgedQueueBrowserCloseWhileFailover() throws Exception - { - browserCloseWhileFailoverImpl(Session.CLIENT_ACKNOWLEDGE); - } - - public void testTransactedQueueBrowserCloseWhileFailover() throws Exception - { - browserCloseWhileFailoverImpl(Session.SESSION_TRANSACTED); - } - - public void testAutoAcknowledgedQueueBrowserCloseWhileFailover() throws Exception - { - browserCloseWhileFailoverImpl(Session.AUTO_ACKNOWLEDGE); - } - - private Message publishWhileFailingOver(int autoAcknowledge) throws JMSException, InterruptedException - { - setDelayedFailoverPolicy(5); - init(autoAcknowledge, true); - - String text = MessageFormat.format(TEST_MESSAGE_FORMAT, 0); - Message message = _producerSession.createTextMessage(text); - - failBroker(getFailingPort()); - - if(!_failoverStarted.await(5, TimeUnit.SECONDS)) - { - fail("Did not receieve notification failover had started"); - } - - _producer.send(message); - - if (_producerSession.getTransacted()) - { - _producerSession.commit(); - } - - Message receivedMessage = _consumer.receive(1000l); - assertReceivedMessage(receivedMessage, TEST_MESSAGE_FORMAT, 0); - return receivedMessage; - } - - private void publishWithFailoverMutex(int autoAcknowledge) throws JMSException, InterruptedException - { - setDelayedFailoverPolicy(5); - init(autoAcknowledge, true); - - String text = MessageFormat.format(TEST_MESSAGE_FORMAT, 0); - Message message = _producerSession.createTextMessage(text); - - AMQConnection connection = (AMQConnection)_connection; - - // holding failover mutex should prevent the failover from - // proceeding before we try to send the message - synchronized(connection.getFailoverMutex()) - { - failBroker(getFailingPort()); - - // wait to make sure that connection is lost - while(!connection.isFailingOver()) - { - Thread.sleep(25l); - } - - try - { - _producer.send(message); - fail("Sending should fail because connection was lost and failover has not yet completed"); - } - catch(JMSException e) - { - // JMSException is expected - } - } - // wait for failover completion, thus ensuring it actually - //got started, before allowing the test to tear down - awaitForFailoverCompletion(DEFAULT_FAILOVER_TIME); - } - - /** - * This test only tests 0-8/0-9/0-9-1 failover timeout - */ - public void testFailoverHandlerTimeoutExpires() throws Exception - { - _connection.close(); - setTestSystemProperty("qpid.failover_method_timeout", "10000"); - AMQConnection connection = null; - try - { - connection = createConnectionWithFailover(); - - // holding failover mutex should prevent the failover from proceeding - synchronized(connection.getFailoverMutex()) - { - killBroker(); - startBroker(); - - // sleep interval exceeds failover timeout interval - Thread.sleep(11000l); - } - - // allows the failover thread to proceed - Thread.yield(); - assertFalse("Unexpected failover", _failoverComplete.await(2000l, TimeUnit.MILLISECONDS)); - assertTrue("Failover should not succeed due to timeout", connection.isClosed()); - } - finally - { - if (connection != null) - { - connection.close(); - } - } - } - - public void testFailoverHandlerTimeoutReconnected() throws Exception - { - _connection.close(); - setTestSystemProperty("qpid.failover_method_timeout", "10000"); - AMQConnection connection = null; - try - { - connection = createConnectionWithFailover(); - - // holding failover mutex should prevent the failover from proceeding - synchronized(connection.getFailoverMutex()) - { - killBroker(); - startBroker(); - } - - // allows the failover thread to proceed - Thread.yield(); - awaitForFailoverCompletion(DEFAULT_FAILOVER_TIME); - assertFalse("Failover should restore connectivity", connection.isClosed()); - } - finally - { - if (connection != null) - { - connection.close(); - } - } - } - - /** - * Tests that the producer flow control flag is reset when failover occurs while - * the producers are being blocked by the broker. - * - * Uses Java broker specific queue configuration to enabled PSFC. - */ - public void testFlowControlFlagResetOnFailover() throws Exception - { - // we do not need the connection failing to second broker - _connection.close(); - - // make sure that failover timeout is bigger than flow control timeout - setTestSystemProperty("qpid.failover_method_timeout", "60000"); - setTestSystemProperty("qpid.flow_control_wait_failure", "10000"); - - AMQConnection connection = null; - try - { - connection = createConnectionWithFailover(); - - final Session producerSession = connection.createSession(true, Session.SESSION_TRANSACTED); - final Queue queue = createAndBindQueueWithFlowControlEnabled(producerSession, getTestQueueName(), DEFAULT_MESSAGE_SIZE * 3, DEFAULT_MESSAGE_SIZE * 2); - final AtomicInteger counter = new AtomicInteger(); - // try to send 5 messages (should block after 4) - new Thread(new Runnable() - { - @Override - public void run() - { - try - { - MessageProducer producer = producerSession.createProducer(queue); - for (int i=0; i < 5; i++) - { - Message next = createNextMessage(producerSession, i); - producer.send(next); - producerSession.commit(); - counter.incrementAndGet(); - } - } - catch(Exception e) - { - // ignore - } - } - }).start(); - - long limit= 30000l; - long start = System.currentTimeMillis(); - - // wait until session is blocked - while(!((AMQSession)producerSession).isFlowBlocked() && System.currentTimeMillis() - start < limit) - { - Thread.sleep(100l); - } - - assertTrue("Flow is not blocked", ((AMQSession) producerSession).isFlowBlocked()); - // Message counter could be 3 or 4 depending on the progression of producing thread relative - // to the receipt of the ChannelFlow. - final int currentCounter = counter.get(); - assertTrue("Unexpected number of sent messages", currentCounter == 3 || currentCounter == 4); - - killBroker(); - startBroker(); - - // allows the failover thread to proceed - Thread.yield(); - awaitForFailoverCompletion(60000l); - - assertFalse("Flow is blocked", ((AMQSession) producerSession).isFlowBlocked()); - } - finally - { - if (connection != null) - { - connection.close(); - } - } - } - - private Queue createAndBindQueueWithFlowControlEnabled(Session session, String queueName, int capacity, int resumeCapacity) throws Exception - { - final Map arguments = new HashMap(); - arguments.put("x-qpid-capacity", capacity); - arguments.put("x-qpid-flow-resume-capacity", resumeCapacity); - ((AMQSession) session).createQueue(new AMQShortString(queueName), false, true, false, arguments); - Queue queue = session.createQueue("direct://amq.direct/" + queueName + "/" + queueName + "?durable='" + true - + "'&autodelete='" + false + "'"); - ((AMQSession) session).declareAndBind((AMQDestination) queue); - return queue; - } - - private AMQConnection createConnectionWithFailover() throws NamingException, JMSException, URLSyntaxException - { - BrokerDetails origBrokerDetails = ((AMQConnectionFactory) getConnectionFactory("default")).getConnectionURL().getBrokerDetails(0); - - String retries = "200"; - String connectdelay = "1000"; - String cycleCount = "2"; - - String newUrlFormat="amqp://username:password@clientid/test?brokerlist=" + - "'tcp://%s:%s?retries='%s'&connectdelay='%s''&failover='singlebroker?cyclecount='%s''"; - - String newUrl = String.format(newUrlFormat, origBrokerDetails.getHost(), origBrokerDetails.getPort(), - retries, connectdelay, cycleCount); - - ConnectionFactory connectionFactory = new AMQConnectionFactory(newUrl); - AMQConnection connection = (AMQConnection) connectionFactory.createConnection("admin", "admin"); - connection.setConnectionListener(this); - return connection; - } - - /** - * Tests {@link Session#close()} for session with given acknowledge mode - * to ensure that close works after failover. - * - * @param acknowledgeMode session acknowledge mode - * @throws JMSException - */ - private void sessionCloseAfterFailoverImpl(int acknowledgeMode) throws JMSException - { - init(acknowledgeMode, true); - produceMessages(TEST_MESSAGE_FORMAT, _messageNumber, false); - if (acknowledgeMode == Session.SESSION_TRANSACTED) - { - _producerSession.commit(); - } - - // intentionally receive message but do not commit or acknowledge it in - // case of transacted or CLIENT_ACK session - Message receivedMessage = _consumer.receive(1000l); - assertReceivedMessage(receivedMessage, TEST_MESSAGE_FORMAT, 0); - - causeFailure(); - - assertFailoverException(); - - // for transacted/client_ack session - // no exception should be thrown but transaction should be automatically - // rolled back - _consumerSession.close(); - } - - /** - * A helper method to instantiate produce and consumer sessions, producer - * and consumer. - * - * @param acknowledgeMode - * acknowledge mode - * @param startConnection - * indicates whether connection should be started - * @throws JMSException - */ - private void init(int acknowledgeMode, boolean startConnection) throws JMSException - { - boolean isTransacted = acknowledgeMode == Session.SESSION_TRANSACTED ? true : false; - - _consumerSession = _connection.createSession(isTransacted, acknowledgeMode); - _destination = createDestination(_consumerSession); - _consumer = _consumerSession.createConsumer(_destination); - - if (startConnection) - { - _connection.start(); - } - - _producerSession = _connection.createSession(isTransacted, acknowledgeMode); - _producer = _producerSession.createProducer(_destination); - - } - - protected Destination createDestination(Session session) throws JMSException - { - return session.createQueue(getTestQueueName() + "_" + System.currentTimeMillis()); - } - - /** - * Resends messages if reconnected to a non-clustered broker - * - * @throws JMSException - */ - private void resendMessagesIfNecessary() throws JMSException - { - if (!CLUSTERED) - { - // assert that a new broker does not have messages on a queue - if (_consumer.getMessageListener() == null) - { - Message message = _consumer.receive(100l); - assertNull("Received a message after failover with non-clustered broker!", message); - } - // re-sending messages if reconnected to a non-clustered broker - produceMessages(true); - } - } - - /** - * Produces a default number of messages with default text content into test - * queue - * - * @throws JMSException - */ - private void produceMessages() throws JMSException - { - produceMessages(false); - } - - private void produceMessages(boolean seperateProducer) throws JMSException - { - produceMessages(TEST_MESSAGE_FORMAT, _messageNumber, seperateProducer); - } - - /** - * Consumes a default number of messages and asserts their content. - * - * @return last consumed message - * @throws JMSException - */ - private Message consumeMessages() throws JMSException - { - return consumeMessages(TEST_MESSAGE_FORMAT, _messageNumber); - } - - /** - * Produces given number of text messages with content matching given - * content pattern - * - * @param messagePattern message content pattern - * @param messageNumber number of messages to send - * @param standaloneProducer whether to use the existing producer or a new one. - * @throws JMSException - */ - private void produceMessages(String messagePattern, int messageNumber, boolean standaloneProducer) throws JMSException - { - Session producerSession; - MessageProducer producer; - - if(standaloneProducer) - { - producerSession = _connection.createSession(true, Session.SESSION_TRANSACTED); - producer = producerSession.createProducer(_destination); - } - else - { - producerSession = _producerSession; - producer = _producer; - } - - for (int i = 0; i < messageNumber; i++) - { - String text = MessageFormat.format(messagePattern, i); - Message message = producerSession.createTextMessage(text); - producer.send(message); - _LOGGER.debug("Test message number " + i + " produced with text = " + text + ", and JMSMessageID = " + message.getJMSMessageID()); - } - - if(standaloneProducer) - { - producerSession.commit(); - } - } - - /** - * Consumes given number of text messages and asserts that their content - * matches given pattern - * - * @param messagePattern - * messages content pattern - * @param messageNumber - * message number to received - * @return last consumed message - * @throws JMSException - */ - private Message consumeMessages(String messagePattern, int messageNumber) throws JMSException - { - Message receivedMesssage = null; - for (int i = 0; i < messageNumber; i++) - { - receivedMesssage = _consumer.receive(1000l); - assertReceivedMessage(receivedMesssage, messagePattern, i); - } - return receivedMesssage; - } - - /** - * Asserts received message - * - * @param receivedMessage - * received message - * @param messagePattern - * messages content pattern - * @param messageIndex - * message index - */ - private void assertReceivedMessage(Message receivedMessage, String messagePattern, int messageIndex) throws JMSException - { - assertNotNull("Expected message [" + messageIndex + "] is not received!", receivedMessage); - assertTrue("Failure to receive message [" + messageIndex + "], expected TextMessage but received " - + receivedMessage, receivedMessage instanceof TextMessage); - String expectedText = MessageFormat.format(messagePattern, messageIndex); - String receivedText = null; - try - { - receivedText = ((TextMessage) receivedMessage).getText(); - } - catch (JMSException e) - { - fail("JMSException occured while getting message text:" + e.getMessage()); - } - _LOGGER.debug("Test message number " + messageIndex + " consumed with text = " + receivedText + ", and JMSMessageID = " + receivedMessage.getJMSMessageID()); - assertEquals("Failover is broken! Expected [" + expectedText + "] but got [" + receivedText + "]", - expectedText, receivedText); - } - - /** - * Causes failover and waits till connection is re-established. - */ - private void causeFailure() - { - causeFailure(getFailingPort(), DEFAULT_FAILOVER_TIME * 2); - } - - /** - * Causes failover by stopping broker on given port and waits till - * connection is re-established during given time interval. - * - * @param port - * broker port - * @param delay - * time interval to wait for connection re-establishement - */ - private void causeFailure(int port, long delay) - { - failBroker(port); - - awaitForFailoverCompletion(delay); - } - - private void awaitForFailoverCompletion(long delay) - { - _logger.info("Awaiting Failover completion.."); - try - { - if (!_failoverComplete.await(delay, TimeUnit.MILLISECONDS)) - { - fail("Failover did not complete"); - } - } - catch (InterruptedException e) - { - fail("Test was interrupted:" + e.getMessage()); - } - } - - private void assertFailoverException() - { - // TODO: assert exception is received (once implemented) - // along with error code and/or expected exception type - } - - @Override - public void bytesSent(long count) - { - } - - @Override - public void bytesReceived(long count) - { - } - - @Override - public boolean preFailover(boolean redirect) - { - _failoverStarted.countDown(); - return true; - } - - @Override - public boolean preResubscribe() - { - return true; - } - - @Override - public void failoverComplete() - { - _failoverComplete.countDown(); - } - - @Override - public void onException(JMSException e) - { - _exceptionListenerException = e; - } - - /** - * Causes 1 second delay before reconnect in order to test whether JMS - * methods block while failover is in progress - */ - private static class DelayingFailoverPolicy extends FailoverPolicy - { - - private CountDownLatch _suspendLatch; - private long _delay; - - public DelayingFailoverPolicy(AMQConnection connection, long delay) - { - super(connection.getConnectionURL(), connection); - _suspendLatch = new CountDownLatch(1); - _delay = delay; - } - - public void attainedConnection() - { - try - { - _suspendLatch.await(_delay, TimeUnit.SECONDS); - } - catch (InterruptedException e) - { - // continue - } - super.attainedConnection(); - } - - } - - - private class FailoverTestMessageListener implements MessageListener - { - // message counter - private AtomicInteger _counter = new AtomicInteger(); - - private List _receivedMessage = new ArrayList(); - - private volatile CountDownLatch _endLatch; - - public FailoverTestMessageListener() throws JMSException - { - _endLatch = new CountDownLatch(1); - } - - @Override - public void onMessage(Message message) - { - _receivedMessage.add(message); - if (_counter.incrementAndGet() % _messageNumber == 0) - { - _endLatch.countDown(); - } - } - - public void reset() - { - _receivedMessage.clear(); - _endLatch = new CountDownLatch(1); - _counter.set(0); - } - - public List getReceivedMessages() - { - return _receivedMessage; - } - - public Object awaitForEnd() throws InterruptedException - { - return _endLatch.await((long) _messageNumber, TimeUnit.SECONDS); - } - - public int getMessageCounter() - { - return _counter.get(); - } - } - - /** - * Tests {@link Session#close()} for session with given acknowledge mode - * to ensure that it blocks until failover implementation restores connection. - * - * @param acknowledgeMode session acknowledge mode - * @throws JMSException - */ - private void sessionCloseWhileFailoverImpl(int acknowledgeMode) throws Exception - { - initDelayedFailover(acknowledgeMode); - - // intentionally receive message but not commit or acknowledge it in - // case of transacted or CLIENT_ACK session - Message receivedMessage = _consumer.receive(1000l); - assertReceivedMessage(receivedMessage, TEST_MESSAGE_FORMAT, 0); - - failBroker(getFailingPort()); - - // wait until failover is started - _failoverStarted.await(5, TimeUnit.SECONDS); - - // test whether session#close blocks while failover is in progress - _consumerSession.close(); - - assertTrue("Failover has not completed yet but session was closed", _failoverComplete.await(5, TimeUnit.SECONDS)); - - assertFailoverException(); - } - - /** - * A helper method to instantiate {@link QueueBrowser} and publish test messages on a test queue for further browsing. - * - * @param acknowledgeMode session acknowledge mode - * @return queue browser - * @throws JMSException - */ - private QueueBrowser prepareQueueBrowser(int acknowledgeMode) throws JMSException, AMQException - { - init(acknowledgeMode, false); - _consumer.close(); - _connection.start(); - - produceMessages(TEST_MESSAGE_FORMAT, _messageNumber, false); - if (acknowledgeMode == Session.SESSION_TRANSACTED) - { - _producerSession.commit(); - } - else - { - ((AMQSession)_producerSession).sync(); - } - - QueueBrowser browser = _consumerSession.createBrowser((Queue) _destination); - return browser; - } - - /** - * Tests {@link QueueBrowser#close()} for session with given acknowledge mode - * to ensure that it blocks until failover implementation restores connection. - * - * @param acknowledgeMode session acknowledge mode - * @throws JMSException - */ - private void browserCloseWhileFailoverImpl(int acknowledgeMode) throws Exception - { - QueueBrowser browser = prepareQueueBrowser(acknowledgeMode); - - @SuppressWarnings("unchecked") - Enumeration messages = browser.getEnumeration(); - Message receivedMessage = (Message) messages.nextElement(); - assertReceivedMessage(receivedMessage, TEST_MESSAGE_FORMAT, 0); - - failBroker(getFailingPort()); - - // wait until failover is started - _failoverStarted.await(5, TimeUnit.SECONDS); - - browser.close(); - - assertTrue("Failover has not completed yet but browser was closed", _failoverComplete.await(5, TimeUnit.SECONDS)); - - assertFailoverException(); - } - - private DelayingFailoverPolicy initDelayedFailover(int acknowledgeMode) throws JMSException - { - DelayingFailoverPolicy failoverPolicy = setDelayedFailoverPolicy(); - init(acknowledgeMode, true); - produceMessages(TEST_MESSAGE_FORMAT, _messageNumber, false); - if (acknowledgeMode == Session.SESSION_TRANSACTED) - { - _producerSession.commit(); - } - return failoverPolicy; - } - - private DelayingFailoverPolicy setDelayedFailoverPolicy() - { - return setDelayedFailoverPolicy(2); - } - - private DelayingFailoverPolicy setDelayedFailoverPolicy(long delay) - { - AMQConnection amqConnection = (AMQConnection) _connection; - DelayingFailoverPolicy failoverPolicy = new DelayingFailoverPolicy(amqConnection, delay); - ((AMQConnection) _connection).setFailoverPolicy(failoverPolicy); - return failoverPolicy; - } - - @Override - public void failBroker(int port) - { - killBroker(port); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/failover/MultipleBrokersFailoverTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/failover/MultipleBrokersFailoverTest.java deleted file mode 100644 index 15ec0f9a4d..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/client/failover/MultipleBrokersFailoverTest.java +++ /dev/null @@ -1,288 +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.failover; - -import java.io.File; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.TextMessage; - -import org.apache.log4j.Logger; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQConnectionURL; -import org.apache.qpid.jms.ConnectionListener; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.test.utils.TestUtils; -import org.apache.qpid.util.FileUtils; - -public class MultipleBrokersFailoverTest extends QpidBrokerTestCase implements ConnectionListener -{ - private static final Logger _logger = Logger.getLogger(MultipleBrokersFailoverTest.class); - - private static final String FAILOVER_VIRTUAL_HOST = "failover"; - private static final String NON_FAILOVER_VIRTUAL_HOST = "nonfailover"; - private static final String BROKER_PORTION_FORMAT = "tcp://localhost:%d?connectdelay='%d',retries='%d'"; - private static final int FAILOVER_RETRIES = 1; - private static final int FAILOVER_CONNECTDELAY = 1000; - private static final int FAILOVER_FACTOR = 4; - - private int[] _brokerPorts; - private AMQConnectionURL _connectionURL; - private Connection _connection; - private CountDownLatch _failoverComplete; - private CountDownLatch _failoverStarted; - private Session _consumerSession; - private Destination _destination; - private MessageConsumer _consumer; - private Session _producerSession; - private MessageProducer _producer; - - @Override - protected void setUp() throws Exception - { - super.setUp(); - - int numBrokers = 4; - int port = findFreePort(); - _brokerPorts = new int[numBrokers]; - - // we need to create 4 brokers: - // 1st broker will be running in test JVM and will not have failover host (only tcp connection will established, amqp connection will be closed) - // 2d broker will be spawn in separate JVM and should have a failover host (amqp connection should be established) - // 3d broker will be spawn in separate JVM and should not have a failover host (only tcp connection will established, amqp connection will be closed) - // 4d broker will be spawn in separate JVM and should have a failover host (amqp connection should be established) - - // the test should connect to the second broker first and fail over to the forth broker - // after unsuccessful try to establish the connection to the 3d broker - for (int i = 0; i < numBrokers; i++) - { - if (i > 0) - { - port = getNextAvailable(port + 1); - } - _brokerPorts[i] = port; - - createBrokerConfiguration(port); - String host = null; - if (i == 1 || i == _brokerPorts.length - 1) - { - host = FAILOVER_VIRTUAL_HOST; - } - else - { - host = NON_FAILOVER_VIRTUAL_HOST; - } - createTestVirtualHostNode(port, host); - - startBroker(port); - revertSystemProperties(); - } - - _connectionURL = new AMQConnectionURL(generateUrlString(numBrokers)); - - _connection = getConnection(_connectionURL); - ((AMQConnection) _connection).setConnectionListener(this); - _failoverComplete = new CountDownLatch(1); - _failoverStarted = new CountDownLatch(1); - } - - public void startBroker() throws Exception - { - // noop, prevent the broker startup in super.setUp() - } - - private String generateUrlString(int numBrokers) - { - String baseString = "amqp://guest:guest@test/" + FAILOVER_VIRTUAL_HOST - + "?&failover='roundrobin?cyclecount='1''&brokerlist='"; - StringBuffer buffer = new StringBuffer(baseString); - - for(int i = 0; i< numBrokers ; i++) - { - if(i != 0) - { - buffer.append(";"); - } - - String broker = String.format(BROKER_PORTION_FORMAT, _brokerPorts[i], - FAILOVER_CONNECTDELAY, FAILOVER_RETRIES); - buffer.append(broker); - } - buffer.append("'"); - - return buffer.toString(); - } - - public void tearDown() throws Exception - { - try - { - super.tearDown(); - } - finally - { - for (int i = 0; i < _brokerPorts.length; i++) - { - if (_brokerPorts[i] > 0) - { - stopBrokerSafely(_brokerPorts[i]); - FileUtils.deleteDirectory(System.getProperty("QPID_WORK") + File.separator + getFailingPort()); - } - } - - } - } - - - public void testFailoverOnBrokerKill() throws Exception - { - init(Session.SESSION_TRANSACTED, true); - assertConnectionPort(_brokerPorts[1]); - - assertSendReceive(0); - - killBroker(_brokerPorts[1]); - - awaitForFailoverCompletion(FAILOVER_CONNECTDELAY * _brokerPorts.length * FAILOVER_FACTOR); - assertEquals("Failover is not started as expected", 0, _failoverStarted.getCount()); - - assertSendReceive(2); - assertConnectionPort(_brokerPorts[_brokerPorts.length - 1]); - } - - public void testFailoverOnBrokerStop() throws Exception - { - init(Session.SESSION_TRANSACTED, true); - assertConnectionPort(_brokerPorts[1]); - - assertSendReceive(0); - - stopBroker(_brokerPorts[1]); - - awaitForFailoverCompletion(FAILOVER_CONNECTDELAY * _brokerPorts.length * FAILOVER_FACTOR); - assertEquals("Failover is not started as expected", 0, _failoverStarted.getCount()); - - assertSendReceive(1); - assertConnectionPort(_brokerPorts[_brokerPorts.length - 1]); - } - - private void assertConnectionPort(int brokerPort) - { - int connectionPort = ((AMQConnection)_connection).getActiveBrokerDetails().getPort(); - assertEquals("Unexpected broker port", brokerPort, connectionPort); - } - - private void assertSendReceive(int index) throws JMSException - { - Message message = createNextMessage(_producerSession, index); - _producer.send(message); - if (_producerSession.getTransacted()) - { - _producerSession.commit(); - } - Message receivedMessage = _consumer.receive(1000l); - assertReceivedMessage(receivedMessage, index); - if (_consumerSession.getTransacted()) - { - _consumerSession.commit(); - } - } - - private void awaitForFailoverCompletion(long delay) - { - _logger.info("Awaiting Failover completion.."); - try - { - if (!_failoverComplete.await(delay, TimeUnit.MILLISECONDS)) - { - _logger.warn("Test thread stack:\n\n" + TestUtils.dumpThreads()); - fail("Failover did not complete"); - } - } - catch (InterruptedException e) - { - fail("Test was interrupted:" + e.getMessage()); - } - } - - private void assertReceivedMessage(Message receivedMessage, int messageIndex) - { - assertNotNull("Expected message [" + messageIndex + "] is not received!", receivedMessage); - assertTrue( - "Failure to receive message [" + messageIndex + "], expected TextMessage but received " + receivedMessage, - receivedMessage instanceof TextMessage); - } - - private void init(int acknowledgeMode, boolean startConnection) throws JMSException - { - boolean isTransacted = acknowledgeMode == Session.SESSION_TRANSACTED ? true : false; - - _consumerSession = _connection.createSession(isTransacted, acknowledgeMode); - _destination = _consumerSession.createQueue(getTestQueueName()); - _consumer = _consumerSession.createConsumer(_destination); - - if (startConnection) - { - _connection.start(); - } - - _producerSession = _connection.createSession(isTransacted, acknowledgeMode); - _producer = _producerSession.createProducer(_destination); - - } - - @Override - public void bytesSent(long count) - { - } - - @Override - public void bytesReceived(long count) - { - } - - @Override - public boolean preFailover(boolean redirect) - { - _failoverStarted.countDown(); - return true; - } - - @Override - public boolean preResubscribe() - { - return true; - } - - @Override - public void failoverComplete() - { - _failoverComplete.countDown(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessageTest.java deleted file mode 100644 index 787e727e66..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/client/message/AMQPEncodedMapMessageTest.java +++ /dev/null @@ -1,275 +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 org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.MapMessage; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.Session; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - - -public class AMQPEncodedMapMessageTest extends QpidBrokerTestCase -{ - private Connection _connection; - private Session _session; - private MessageConsumer _consumer; - private MessageProducer _producer; - private UUID myUUID = UUID.randomUUID(); - - public void setUp() throws Exception - { - super.setUp(); - - //Create Connection - _connection = getConnection(); - - //Create Session - _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - //Create Queue - String queueName = getTestQueueName(); - Queue queue = _session.createQueue(queueName); - - //Create Consumer - _consumer = _session.createConsumer(queue); - - //Create Producer - _producer = _session.createProducer(queue); - - _connection.start(); - } - - public void testEmptyMessage() throws JMSException - { - MapMessage m = _session.createMapMessage(); - _producer.send(m); - AMQPEncodedMapMessage msg = (AMQPEncodedMapMessage)_consumer.receive(RECEIVE_TIMEOUT); - assertNotNull("Message was not received on time",msg); - assertEquals("Message content-type is incorrect", - AMQPEncodedMapMessage.MIME_TYPE, - ((AbstractJMSMessage)msg).getContentType()); - - assertEquals("Message content should be an empty map", - Collections.EMPTY_MAP, - ((AMQPEncodedMapMessage)msg).getMap()); - } - - public void testNullMessage() throws JMSException - { - MapMessage m = _session.createMapMessage(); - ((AMQPEncodedMapMessage)m).setMap(null); - _producer.send(m); - AMQPEncodedMapMessage msg = (AMQPEncodedMapMessage)_consumer.receive(RECEIVE_TIMEOUT); - assertNotNull("Message was not received on time",msg); - assertEquals("Message content-type is incorrect", - AMQPEncodedMapMessage.MIME_TYPE, - ((AbstractJMSMessage)msg).getContentType()); - - assertEquals("Message content should be null", - null, - ((AMQPEncodedMapMessage)msg).getMap()); - - } - - public void testMessageWithContent() throws JMSException - { - MapMessage m = _session.createMapMessage(); - m.setBoolean("Boolean", true); - m.setByte("Byte", (byte)5); - byte[] bytes = new byte[]{(byte)5,(byte)8}; - m.setBytes("Bytes", bytes); - m.setChar("Char", 'X'); - m.setDouble("Double", 56.84); - m.setFloat("Float", Integer.MAX_VALUE + 5000); - m.setInt("Int", Integer.MAX_VALUE - 5000); - m.setShort("Short", (short)58); - m.setString("String", "Hello"); - m.setObject("uuid", myUUID); - _producer.send(m); - - AMQPEncodedMapMessage msg = (AMQPEncodedMapMessage)_consumer.receive(RECEIVE_TIMEOUT); - assertNotNull("Message was not received on time",msg); - assertEquals("Message content-type is incorrect", - AMQPEncodedMapMessage.MIME_TYPE, - ((AbstractJMSMessage)msg).getContentType()); - - assertEquals(true,m.getBoolean("Boolean")); - assertEquals((byte)5,m.getByte("Byte")); - byte[] bytesRcv = m.getBytes("Bytes"); - assertNotNull("Byte array is null",bytesRcv); - assertEquals((byte)5,bytesRcv[0]); - assertEquals((byte)8,bytesRcv[1]); - assertEquals('X',m.getChar("Char")); - assertEquals(56.84,m.getDouble("Double")); - //assertEquals(Integer.MAX_VALUE + 5000,m.getFloat("Float")); - assertEquals(Integer.MAX_VALUE - 5000,m.getInt("Int")); - assertEquals((short)58,m.getShort("Short")); - assertEquals("Hello",m.getString("String")); - assertEquals(myUUID,(UUID)m.getObject("uuid")); - } - - - public void testMessageWithListEntries() throws JMSException - { - MapMessage m = _session.createMapMessage(); - - List myList = getList(); - - m.setObject("List", myList); - - List uuidList = new ArrayList(); - uuidList.add(myUUID); - m.setObject("uuid-list", uuidList); - _producer.send(m); - - AMQPEncodedMapMessage msg = (AMQPEncodedMapMessage)_consumer.receive(RECEIVE_TIMEOUT); - assertNotNull("Message was not received on time",msg); - assertEquals("Message content-type is incorrect", - AMQPEncodedMapMessage.MIME_TYPE, - ((AbstractJMSMessage)msg).getContentType()); - - List list = (List)msg.getObject("List"); - assertNotNull("List not received",list); - Collections.sort(list); - int i = 1; - for (Integer j: list) - { - assertEquals(i,j.intValue()); - i++; - } - - List list2 = (List)msg.getObject("uuid-list"); - assertNotNull("UUID List not received",list2); - assertEquals(myUUID,list2.get(0)); - } - - public void testMessageWithMapEntries() throws JMSException - { - MapMessage m = _session.createMapMessage(); - - Map myMap = getMap(); - m.setObject("Map", myMap); - - Map uuidMap = new HashMap(); - uuidMap.put("uuid", myUUID); - m.setObject("uuid-map", uuidMap); - - _producer.send(m); - - AMQPEncodedMapMessage msg = (AMQPEncodedMapMessage)_consumer.receive(RECEIVE_TIMEOUT); - assertNotNull("Message was not received on time",msg); - assertEquals("Message content-type is incorrect", - AMQPEncodedMapMessage.MIME_TYPE, - ((AbstractJMSMessage)msg).getContentType()); - - Map map = (Map)msg.getObject("Map"); - assertNotNull("Map not received",map); - for (int i=1; i <4; i++ ) - { - assertEquals("String" + i,map.get("Key" + i)); - i++; - } - - Map map2 = (Map)msg.getObject("uuid-map"); - assertNotNull("Map not received",map2); - assertEquals(myUUID,map2.get("uuid")); - } - - public void testMessageWithNestedListsAndMaps() throws JMSException - { - MapMessage m = _session.createMapMessage(); - - Map myMap = new HashMap(); - myMap.put("map", getMap()); - myMap.put("list", getList()); - - m.setObject("Map", myMap); - _producer.send(m); - - AMQPEncodedMapMessage msg = (AMQPEncodedMapMessage)_consumer.receive(RECEIVE_TIMEOUT); - assertNotNull("Message was not received on time",msg); - assertEquals("Message content-type is incorrect", - AMQPEncodedMapMessage.MIME_TYPE, - ((AbstractJMSMessage)msg).getContentType()); - - Map mainMap = (Map)msg.getObject("Map"); - assertNotNull("Main Map not received",mainMap); - - Map map = (Map)mainMap.get("map"); - assertNotNull("Nested Map not received",map); - for (int i=1; i <4; i++ ) - { - assertEquals("String" + i,map.get("Key" + i)); - i++; - } - - List list = (List)mainMap.get("list"); - assertNotNull("Nested List not received",list); - Collections.sort(list); - - int i = 1; - for (Integer j: list) - { - assertEquals(i,j.intValue()); - i++; - } - } - - private List getList() - { - List myList = new ArrayList(); - myList.add(1); - myList.add(2); - myList.add(3); - - return myList; - } - - private Map getMap() - { - Map myMap = new HashMap(); - myMap.put("Key1","String1"); - myMap.put("Key2","String2"); - myMap.put("Key3","String3"); - - return myMap; - } - - public void tearDown() throws Exception - { - //clean up - _connection.close(); - - super.tearDown(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/message/NonQpidObjectMessage.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/message/NonQpidObjectMessage.java deleted file mode 100644 index 3aabfa1c40..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/client/message/NonQpidObjectMessage.java +++ /dev/null @@ -1,235 +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.Destination; -import javax.jms.JMSException; -import javax.jms.ObjectMessage; -import javax.jms.Session; -import java.io.Serializable; -import java.util.Enumeration; - -public class NonQpidObjectMessage implements ObjectMessage { - - private ObjectMessage _realMessage; - private String _contentString; - - /** - * Allows us to construct a JMS message which - * does not inherit from the Qpid message superclasses - * and expand our unit testing of MessageConverter et al - * @param session - */ - public NonQpidObjectMessage(Session session) throws JMSException - { - _realMessage = session.createObjectMessage(); - } - - public String getJMSMessageID() throws JMSException { - return _realMessage.getJMSMessageID(); - } - - public void setJMSMessageID(String string) throws JMSException { - _realMessage.setJMSMessageID(string); - } - - public long getJMSTimestamp() throws JMSException { - return _realMessage.getJMSTimestamp(); - } - - public void setJMSTimestamp(long l) throws JMSException { - _realMessage.setJMSTimestamp(l); - } - - public byte[] getJMSCorrelationIDAsBytes() throws JMSException { - return _realMessage.getJMSCorrelationIDAsBytes(); - } - - public void setJMSCorrelationIDAsBytes(byte[] bytes) throws JMSException { - _realMessage.setJMSCorrelationIDAsBytes(bytes); - } - - public void setJMSCorrelationID(String string) throws JMSException { - _realMessage.setJMSCorrelationID(string); - } - - public String getJMSCorrelationID() throws JMSException { - return _realMessage.getJMSCorrelationID(); - } - - public Destination getJMSReplyTo() throws JMSException { - return _realMessage.getJMSReplyTo(); - } - - public void setJMSReplyTo(Destination destination) throws JMSException { - _realMessage.setJMSReplyTo(destination); - } - - public Destination getJMSDestination() throws JMSException { - return _realMessage.getJMSDestination(); - } - - public void setJMSDestination(Destination destination) throws JMSException { - _realMessage.setJMSDestination(destination); - } - - public int getJMSDeliveryMode() throws JMSException { - return _realMessage.getJMSDeliveryMode(); - } - - public void setJMSDeliveryMode(int i) throws JMSException { - _realMessage.setJMSDeliveryMode(i); - } - - public boolean getJMSRedelivered() throws JMSException { - return _realMessage.getJMSRedelivered(); - } - - public void setJMSRedelivered(boolean b) throws JMSException { - _realMessage.setJMSRedelivered(b); - } - - public String getJMSType() throws JMSException { - return _realMessage.getJMSType(); - } - - public void setJMSType(String string) throws JMSException { - _realMessage.setJMSType(string); - } - - public long getJMSExpiration() throws JMSException { - return _realMessage.getJMSExpiration(); - } - - public void setJMSExpiration(long l) throws JMSException { - _realMessage.setJMSExpiration(l); - } - - public int getJMSPriority() throws JMSException { - return _realMessage.getJMSPriority(); - } - - public void setJMSPriority(int i) throws JMSException { - _realMessage.setJMSPriority(i); - } - - public void clearProperties() throws JMSException { - _realMessage.clearProperties(); - } - - public boolean propertyExists(String string) throws JMSException { - return _realMessage.propertyExists(string); - } - - public boolean getBooleanProperty(String string) throws JMSException { - return _realMessage.getBooleanProperty(string); - } - - public byte getByteProperty(String string) throws JMSException { - return _realMessage.getByteProperty(string); - } - - public short getShortProperty(String string) throws JMSException { - return _realMessage.getShortProperty(string); - } - - public int getIntProperty(String string) throws JMSException { - return _realMessage.getIntProperty(string); - } - - public long getLongProperty(String string) throws JMSException { - return _realMessage.getLongProperty(string); - } - - public float getFloatProperty(String string) throws JMSException { - return _realMessage.getFloatProperty(string); - } - - public double getDoubleProperty(String string) throws JMSException { - return _realMessage.getDoubleProperty(string); - } - - public String getStringProperty(String string) throws JMSException { - return _realMessage.getStringProperty(string); - } - - public Object getObjectProperty(String string) throws JMSException { - return _realMessage.getObjectProperty(string); - } - - public Enumeration getPropertyNames() throws JMSException { - return _realMessage.getPropertyNames(); - } - - public void setBooleanProperty(String string, boolean b) throws JMSException { - _realMessage.setBooleanProperty(string,b); - } - - public void setByteProperty(String string, byte b) throws JMSException { - _realMessage.setByteProperty(string,b); - } - - public void setShortProperty(String string, short i) throws JMSException { - _realMessage.setShortProperty(string,i); - } - - public void setIntProperty(String string, int i) throws JMSException { - _realMessage.setIntProperty(string,i); - } - - public void setLongProperty(String string, long l) throws JMSException { - _realMessage.setLongProperty(string,l); - } - - public void setFloatProperty(String string, float v) throws JMSException { - _realMessage.setFloatProperty(string,v); - } - - public void setDoubleProperty(String string, double v) throws JMSException { - _realMessage.setDoubleProperty(string,v); - } - - public void setStringProperty(String string, String string1) throws JMSException { - _realMessage.setStringProperty(string,string1); - } - - public void setObjectProperty(String string, Object object) throws JMSException { - _realMessage.setObjectProperty(string,object); - } - - public void acknowledge() throws JMSException { - _realMessage.acknowledge(); - } - - public void clearBody() throws JMSException { - _realMessage.clearBody(); - } - - public void setObject(Serializable serializable) throws JMSException { - if (serializable instanceof String) - { - _contentString = (String)serializable; - } - } - - public Serializable getObject() throws JMSException { - return _contentString; } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java deleted file mode 100644 index 69441d2be6..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java +++ /dev/null @@ -1,235 +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.prefetch; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.Destination; -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 java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - - -public class PrefetchBehaviourTest extends QpidBrokerTestCase -{ - protected static final Logger _logger = LoggerFactory.getLogger(PrefetchBehaviourTest.class); - private Connection _normalConnection; - private AtomicBoolean _exceptionCaught; - private CountDownLatch _processingStarted; - private CountDownLatch _processingCompleted; - - protected void setUp() throws Exception - { - super.setUp(); - _normalConnection = getConnection(); - _exceptionCaught = new AtomicBoolean(); - _processingStarted = new CountDownLatch(1); - _processingCompleted = new CountDownLatch(1); - } - - /** - * Verifies that a slow processing asynchronous transacted consumer with prefetch=1 only - * gets 1 of the messages sent, with the second consumer picking up the others while the - * slow consumer is processing, i.e that prefetch=1 actually does what it says on the tin. - */ - public void testPrefetchOneWithAsynchronousTransactedConsumer() throws Exception - { - final long processingTime = 5000; - - //create a second connection with prefetch set to 1 - setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, new Integer(1).toString()); - Connection prefetch1Connection = getConnection(); - - prefetch1Connection.start(); - _normalConnection.start(); - - //create an asynchronous consumer with simulated slow processing - final Session prefetch1session = prefetch1Connection.createSession(true, Session.SESSION_TRANSACTED); - Queue queue = prefetch1session.createQueue(getTestQueueName()); - MessageConsumer prefetch1consumer = prefetch1session.createConsumer(queue); - prefetch1consumer.setMessageListener(new MessageListener() - { - public void onMessage(Message message) - { - try - { - _logger.debug("starting processing"); - _processingStarted.countDown(); - _logger.debug("processing started"); - - //simulate message processing - Thread.sleep(processingTime); - - prefetch1session.commit(); - - _processingCompleted.countDown(); - } - catch(Exception e) - { - _logger.error("Exception caught in message listener"); - _exceptionCaught.set(true); - } - } - }); - - //create producer and send 5 messages - Session producerSession = _normalConnection.createSession(true, Session.SESSION_TRANSACTED); - MessageProducer producer = producerSession.createProducer(queue); - - for (int i = 0; i < 5; i++) - { - producer.send(producerSession.createTextMessage("test")); - } - producerSession.commit(); - - //wait for the first message to start being processed by the async consumer - assertTrue("Async processing failed to start in allowed timeframe", _processingStarted.await(2000, TimeUnit.MILLISECONDS)); - _logger.debug("proceeding with test"); - - //try to consumer the other messages with another consumer while the async procesisng occurs - Session normalSession = _normalConnection.createSession(true, Session.AUTO_ACKNOWLEDGE); - MessageConsumer normalConsumer = normalSession.createConsumer(queue); - - Message msg; - // Check that other consumer gets the other 4 messages - for (int i = 0; i < 4; i++) - { - msg = normalConsumer.receive(1500); - assertNotNull("Consumer should receive 4 messages",msg); - } - msg = normalConsumer.receive(250); - assertNull("Consumer should not have received a 5th message",msg); - - //wait for the other consumer to finish to ensure it completes ok - _logger.debug("waiting for async consumer to complete"); - assertTrue("Async processing failed to complete in allowed timeframe", _processingStarted.await(processingTime + 2000, TimeUnit.MILLISECONDS)); - assertFalse("Unexpected exception during async message processing",_exceptionCaught.get()); - } - - /** - * This test was originally known as AMQConnectionTest#testPrefetchSystemProperty. - * - */ - public void testMessagesAreDistributedBetweenConsumersWithLowPrefetch() throws Exception - { - Queue queue = getTestQueue(); - - setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, new Integer(2).toString()); - - Connection connection = getConnection(); - connection.start(); - // Create Consumer A - Session consSessA = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer consumerA = consSessA.createConsumer(queue); - - // ensure message delivery to consumer A is started (required for 0-8..0-9-1) - final Message msg = consumerA.receiveNoWait(); - assertNull(msg); - - Session producerSession = connection.createSession(true, Session.SESSION_TRANSACTED); - sendMessage(producerSession, queue, 3); - - // Create Consumer B - MessageConsumer consumerB = null; - if (isBroker010()) - { - // 0-10 prefetch is per consumer so we create Consumer B on the same session as Consumer A - consumerB = consSessA.createConsumer(queue); - } - else - { - // 0-8..0-9-1 prefetch is per session so we create Consumer B on a separate session - Session consSessB = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - consumerB = consSessB.createConsumer(queue); - } - - // As message delivery to consumer A is already started, the first two messages should - // now be with consumer A. The last message will still be on the Broker as consumer A's - // credit is exhausted and message delivery for consumer B is not yet running. - - // As described by QPID-3747, for 0-10 we *must* check Consumer B before Consumer A. - // If we were to reverse the order, the SessionComplete will restore Consumer A's credit, - // and the third message could be delivered to either Consumer A or Consumer B. - - // Check that consumer B gets the last (third) message. - final Message msgConsumerB = consumerB.receive(1500); - assertNotNull("Consumer B should have received a message", msgConsumerB); - assertEquals("Consumer B received message with unexpected index", 2, msgConsumerB.getIntProperty(INDEX)); - - // Now check that consumer A has indeed got the first two messages. - for (int i = 0; i < 2; i++) - { - final Message msgConsumerA = consumerA.receive(1500); - assertNotNull("Consumer A should have received a message " + i, msgConsumerA); - assertEquals("Consumer A received message with unexpected index", i, msgConsumerA.getIntProperty(INDEX)); - } - } - - /** - * Test Goal: Verify if connection stop releases all messages in it's prefetch buffer. - * Test Strategy: Send 10 messages to a queue. Create a consumer with maxprefetch of 5, but never consume them. - * Stop the connection. Create a new connection and a consumer with maxprefetch 10 on the same queue. - * Try to receive all 10 messages. - */ - public void testConnectionStop() throws Exception - { - setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, "10"); - Connection con = getConnection(); - con.start(); - Session ssn = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - Destination queue = ssn.createQueue("ADDR:my-queue;{create: always}"); - - MessageProducer prod = ssn.createProducer(queue); - for (int i=0; i<10;i++) - { - prod.send(ssn.createTextMessage("Msg" + i)); - } - - MessageConsumer consumer = ssn.createConsumer(queue); - // This is to ensure we get the first client to prefetch. - Message msg = consumer.receive(1000); - assertNotNull("The first consumer should get one message",msg); - con.stop(); - - Connection con2 = getConnection(); - con2.start(); - Session ssn2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer consumer2 = ssn2.createConsumer(queue); - for (int i=0; i<9;i++) - { - TextMessage m = (TextMessage)consumer2.receive(1000); - assertNotNull("The second consumer should get 9 messages, but received only " + i,m); - } - } -} - diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/redelivered/RedeliveredMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/redelivered/RedeliveredMessageTest.java deleted file mode 100644 index 0f12c8c7e6..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/client/redelivered/RedeliveredMessageTest.java +++ /dev/null @@ -1,71 +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.redelivered; - -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.Session; - -public class RedeliveredMessageTest extends QpidBrokerTestCase -{ - private Connection _connection; - - public void setUp() throws Exception - { - super.setUp(); - _connection = getConnection(); - } - - public void testRedeliveredFlagOnSessionClose() throws Exception - { - Session session = _connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); - Destination destination = session.createQueue(getTestQueueName()); - MessageConsumer consumer = session.createConsumer(destination); - - final int numberOfMessages = 3; - sendMessage(session, destination, numberOfMessages); - - _connection.start(); - - for(int i = 0; i < numberOfMessages; i++) - { - final Message m = consumer.receive(1000l); - assertNotNull("Message is not recieved at " + i, m); - assertFalse("Redelivered should be not set", m.getJMSRedelivered()); - } - - session.close(); - session = _connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); - destination = session.createQueue(getTestQueueName()); - consumer = session.createConsumer(destination); - - for(int i = 0; i < numberOfMessages; i++) - { - final Message m = consumer.receive(1000l); - assertNotNull("Message is not recieved at " + i, m); - assertTrue("Redelivered should be set", m.getJMSRedelivered()); - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/session/QueueDeclareTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/session/QueueDeclareTest.java deleted file mode 100644 index fefed5b4ab..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/client/session/QueueDeclareTest.java +++ /dev/null @@ -1,68 +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.session; - -import java.util.Collections; - -import javax.jms.Connection; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.Session; - -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.url.AMQBindingURL; - -public class QueueDeclareTest extends QpidBrokerTestCase -{ - private Connection _connection; - private AMQSession _session; - - protected void setUp() throws Exception - { - super.setUp(); - - _connection = getConnection(); - _session = (AMQSession) _connection.createSession(true, Session.SESSION_TRANSACTED); - } - - public void testDeclareAndBindWhenQueueIsNotSpecifiedInDestinationUrl() throws Exception - { - AMQQueue destination = new AMQQueue(new AMQBindingURL("topic://amq.topic//?routingkey='testTopic'")); - - assertEquals("Queue name is generated in parser", AMQShortString.EMPTY_STRING, destination.getAMQQueueName()); - - _session.declareAndBind(destination, FieldTable.convertToFieldTable(Collections. emptyMap())); - - assertFalse("Unexpected queue name: [" + destination.getAMQQueueName() + "]", AMQShortString.EMPTY_STRING.equals(destination.getAMQQueueName())); - - sendMessage(_session, destination, 1); - - MessageConsumer consumer = _session.createConsumer(destination); - _connection.start(); - Message message = consumer.receive(1000l); - assertNotNull("Message not received", message); - _session.commit(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java deleted file mode 100644 index eb61e5a084..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java +++ /dev/null @@ -1,485 +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.ssl; - -import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE; -import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE_PASSWORD; -import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE; -import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD; - -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Session; - -import org.apache.qpid.client.AMQConnectionURL; -import org.apache.qpid.client.AMQTestConnection_0_10; -import org.apache.qpid.jms.ConnectionURL; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.Transport; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class SSLTest extends QpidBrokerTestCase -{ - private static final Logger LOGGER = LoggerFactory.getLogger(SSLTest.class); - - private static final String CERT_ALIAS_APP1 = "app1"; - private static final String CERT_ALIAS_APP2 = "app2"; - - @Override - protected void setUp() throws Exception - { - setSystemProperty("javax.net.debug", "ssl"); - - setSslStoreSystemProperties(); - - //We dont call super.setUp, the tests start the broker after deciding - //whether to run and then configuring it appropriately - } - - public void testCreateSSLConnectionUsingConnectionURLParams() throws Exception - { - if (shouldPerformTest()) - { - clearSslStoreSystemProperties(); - - //Start the broker (NEEDing client certificate authentication) - configureJavaBrokerIfNecessary(true, true, true, false, false); - super.setUp(); - - String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s" + - "?ssl='true'" + - "&key_store='%s'&key_store_password='%s'" + - "&trust_store='%s'&trust_store_password='%s'" + - "'"; - - url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT, - KEYSTORE,KEYSTORE_PASSWORD,TRUSTSTORE,TRUSTSTORE_PASSWORD); - - Connection con = getConnection(new AMQConnectionURL(url)); - assertNotNull("connection should be successful", con); - Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE); - assertNotNull("create session should be successful", ssn); - } - } - - public void testHostVerificationIsOnByDefault() throws Exception - { - if (shouldPerformTest()) - { - clearSslStoreSystemProperties(); - - //Start the broker (NEEDing client certificate authentication) - configureJavaBrokerIfNecessary(true, true, true, false, false); - super.setUp(); - - String url = "amqp://guest:guest@test/?brokerlist='tcp://127.0.0.1:%s" + - "?ssl='true'" + - "&key_store='%s'&key_store_password='%s'" + - "&trust_store='%s'&trust_store_password='%s'" + - "'"; - - url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT, - KEYSTORE,KEYSTORE_PASSWORD,TRUSTSTORE,TRUSTSTORE_PASSWORD); - - try - { - getConnection(new AMQConnectionURL(url)); - } - catch(JMSException e) - { - assertTrue("Unexpected exception message", e.getMessage().contains("SSL hostname verification failed")); - } - - url = "amqp://guest:guest@test/?brokerlist='tcp://127.0.0.1:%s" + - "?ssl='true'&ssl_verify_hostname='false'" + - "&key_store='%s'&key_store_password='%s'" + - "&trust_store='%s'&trust_store_password='%s'" + - "'"; - url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT, - KEYSTORE,KEYSTORE_PASSWORD,TRUSTSTORE,TRUSTSTORE_PASSWORD); - - Connection con = getConnection(new AMQConnectionURL(url)); - assertNotNull("connection should be successful", con); - Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE); - assertNotNull("create session should be successful", ssn); - } - } - - /** - * Create an SSL connection using the SSL system properties for the trust and key store, but using - * the {@link ConnectionURL} ssl='true' option to indicate use of SSL at a Connection level, - * without specifying anything at the {@link ConnectionURL#OPTIONS_BROKERLIST} level. - */ - public void testSslConnectionOption() throws Exception - { - if (shouldPerformTest()) - { - //Start the broker (NEEDing client certificate authentication) - configureJavaBrokerIfNecessary(true, true, true, false, false); - super.setUp(); - - //Create URL enabling SSL at the connection rather than brokerlist level - String url = "amqp://guest:guest@test/?ssl='true'&brokerlist='tcp://localhost:%s'"; - url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT); - - Connection con = getConnection(new AMQConnectionURL(url)); - assertNotNull("connection should be successful", con); - Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE); - assertNotNull("create session should be successful", ssn); - } - } - - /** - * Create an SSL connection using the SSL system properties for the trust and key store, but using - * the {@link ConnectionURL} ssl='true' option to indicate use of SSL at a Connection level, - * overriding the false setting at the {@link ConnectionURL#OPTIONS_BROKERLIST} level. - */ - public void testSslConnectionOptionOverridesBrokerlistOption() throws Exception - { - if (shouldPerformTest()) - { - //Start the broker (NEEDing client certificate authentication) - configureJavaBrokerIfNecessary(true, true, true, false, false); - super.setUp(); - - //Create URL enabling SSL at the connection, overriding the false at the brokerlist level - String url = "amqp://guest:guest@test/?ssl='true'&brokerlist='tcp://localhost:%s?ssl='false''"; - url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT); - - Connection con = getConnection(new AMQConnectionURL(url)); - assertNotNull("connection should be successful", con); - Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE); - assertNotNull("create session should be successful", ssn); - } - } - - public void testCreateSSLConnectionUsingSystemProperties() throws Exception - { - if (shouldPerformTest()) - { - //Start the broker (NEEDing client certificate authentication) - configureJavaBrokerIfNecessary(true, true, true, false, false); - super.setUp(); - - String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s?ssl='true''"; - - url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT); - - Connection con = getConnection(new AMQConnectionURL(url)); - assertNotNull("connection should be successful", con); - Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE); - assertNotNull("create session should be successful", ssn); - } - } - - public void testMultipleCertsInSingleStore() throws Exception - { - if (shouldPerformTest()) - { - //Start the broker (NEEDing client certificate authentication) - configureJavaBrokerIfNecessary(true, true, true, false, false); - super.setUp(); - - String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:" + - QpidBrokerTestCase.DEFAULT_SSL_PORT + - "?ssl='true'&ssl_cert_alias='" + CERT_ALIAS_APP1 + "''"; - - AMQTestConnection_0_10 con = new AMQTestConnection_0_10(url); - org.apache.qpid.transport.Connection transportCon = con.getConnection(); - String userID = transportCon.getSecurityLayer().getUserID(); - assertEquals("The correct certificate was not choosen","app1@acme.org",userID); - con.close(); - - url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:" + - QpidBrokerTestCase.DEFAULT_SSL_PORT + - "?ssl='true'&ssl_cert_alias='" + CERT_ALIAS_APP2 + "''"; - - con = new AMQTestConnection_0_10(url); - transportCon = con.getConnection(); - userID = transportCon.getSecurityLayer().getUserID(); - assertEquals("The correct certificate was not choosen","app2@acme.org",userID); - con.close(); - } - } - - public void testVerifyHostNameWithIncorrectHostname() throws Exception - { - if (shouldPerformTest()) - { - //Start the broker (WANTing client certificate authentication) - configureJavaBrokerIfNecessary(true, true, false, true, false); - super.setUp(); - - String url = "amqp://guest:guest@test/?brokerlist='tcp://127.0.0.1:" + - QpidBrokerTestCase.DEFAULT_SSL_PORT + - "?ssl='true''"; - - try - { - getConnection(new AMQConnectionURL(url)); - fail("Hostname verification failed. No exception was thrown"); - } - catch (Exception e) - { - verifyExceptionCausesContains(e, "SSL hostname verification failed"); - } - } - } - - private void verifyExceptionCausesContains(Exception e, String expectedString) - { - LOGGER.debug("verifying that the following exception contains " + expectedString, e); - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - e.printStackTrace(new PrintStream(bout)); - String strace = bout.toString(); - assertTrue("Correct exception not thrown", strace.contains(expectedString)); - } - - public void testVerifyLocalHost() throws Exception - { - if (shouldPerformTest()) - { - //Start the broker (WANTing client certificate authentication) - configureJavaBrokerIfNecessary(true, true, false, true, false); - super.setUp(); - - String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:" + - QpidBrokerTestCase.DEFAULT_SSL_PORT + - "?ssl='true''"; - - Connection con = getConnection(new AMQConnectionURL(url)); - assertNotNull("connection should have been created", con); - } - } - - public void testVerifyLocalHostLocalDomain() throws Exception - { - if (shouldPerformTest()) - { - //Start the broker (WANTing client certificate authentication) - configureJavaBrokerIfNecessary(true, true, false, true, false); - super.setUp(); - - String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost.localdomain:" + - QpidBrokerTestCase.DEFAULT_SSL_PORT + - "?ssl='true''"; - - Connection con = getConnection(new AMQConnectionURL(url)); - assertNotNull("connection should have been created", con); - } - } - - public void testCreateSSLConnectionUsingConnectionURLParamsTrustStoreOnly() throws Exception - { - if (shouldPerformTest()) - { - clearSslStoreSystemProperties(); - - //Start the broker (WANTing client certificate authentication) - configureJavaBrokerIfNecessary(true, true, false, true, false); - super.setUp(); - - - String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s" + - "?ssl='true'" + - "&trust_store='%s'&trust_store_password='%s'" + - "'"; - - url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT, TRUSTSTORE,TRUSTSTORE_PASSWORD); - - Connection con = getConnection(new AMQConnectionURL(url)); - assertNotNull("connection should be successful", con); - Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE); - assertNotNull("create session should be successful", ssn); - } - } - - /** - * Verifies that when the broker is configured to NEED client certificates, - * a client which doesn't supply one fails to connect. - */ - public void testClientCertMissingWhilstNeeding() throws Exception - { - missingClientCertWhileNeedingOrWantingTestImpl(true, false, false); - } - - /** - * Verifies that when the broker is configured to WANT client certificates, - * a client which doesn't supply one succeeds in connecting. - */ - public void testClientCertMissingWhilstWanting() throws Exception - { - missingClientCertWhileNeedingOrWantingTestImpl(false, true, true); - } - - /** - * Verifies that when the broker is configured to WANT and NEED client certificates - * that a client which doesn't supply one fails to connect. - */ - public void testClientCertMissingWhilstWantingAndNeeding() throws Exception - { - missingClientCertWhileNeedingOrWantingTestImpl(true, true, false); - } - - private void missingClientCertWhileNeedingOrWantingTestImpl(boolean needClientCerts, - boolean wantClientCerts, boolean shouldSucceed) throws Exception - { - if (shouldPerformTest()) - { - clearSslStoreSystemProperties(); - - //Start the broker - configureJavaBrokerIfNecessary(true, true, needClientCerts, wantClientCerts, false); - super.setUp(); - - String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s" + - "?ssl='true'&trust_store='%s'&trust_store_password='%s''"; - - url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT,TRUSTSTORE,TRUSTSTORE_PASSWORD); - try - { - Connection con = getConnection(new AMQConnectionURL(url)); - if(!shouldSucceed) - { - fail("Connection succeeded, expected exception was not thrown"); - } - else - { - //Use the connection to verify it works - con.createSession(true, Session.SESSION_TRANSACTED); - } - } - catch(JMSException e) - { - if(shouldSucceed) - { - _logger.error("Caught unexpected exception",e); - fail("Connection failed, unexpected exception thrown"); - } - else - { - //expected - verifyExceptionCausesContains(e, "Caused by: javax.net.ssl.SSLException:"); - } - } - } - } - - /** - * Test running TLS and unencrypted on the same port works and both TLS and non-TLS connections can be established - * - */ - public void testCreateSSLandTCPonSamePort() throws Exception - { - if (shouldPerformTest()) - { - clearSslStoreSystemProperties(); - - //Start the broker (NEEDing client certificate authentication) - configureJavaBrokerIfNecessary(true, false, false, false, true); - super.setUp(); - - String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s" + - "?ssl='true'&ssl_verify_hostname='true'" + - "&key_store='%s'&key_store_password='%s'" + - "&trust_store='%s'&trust_store_password='%s'" + - "'"; - - url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT, - KEYSTORE,KEYSTORE_PASSWORD,TRUSTSTORE,TRUSTSTORE_PASSWORD); - - Connection con = getConnection(new AMQConnectionURL(url)); - assertNotNull("connection should be successful", con); - Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE); - assertNotNull("create session should be successful", ssn); - - url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s'"; - - url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT); - - con = getConnection(new AMQConnectionURL(url)); - assertNotNull("connection should be successful", con); - ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE); - assertNotNull("create session should be successful", ssn); - - } - } - - - private boolean shouldPerformTest() - { - // We run the SSL tests on all the Java broker profiles - if(isJavaBroker()) - { - setTestClientSystemProperty(PROFILE_USE_SSL, "true"); - } - - return Boolean.getBoolean(PROFILE_USE_SSL); - } - - private void configureJavaBrokerIfNecessary(boolean sslEnabled, - boolean sslOnly, - boolean needClientAuth, - boolean wantClientAuth, - boolean samePort) throws Exception - { - if(isJavaBroker()) - { - Map sslPortAttributes = new HashMap(); - sslPortAttributes.put(Port.TRANSPORTS, samePort ? Arrays.asList(Transport.SSL, Transport.TCP) - : Collections.singleton(Transport.SSL)); - sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT); - sslPortAttributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); - sslPortAttributes.put(Port.NEED_CLIENT_AUTH, needClientAuth); - sslPortAttributes.put(Port.WANT_CLIENT_AUTH, wantClientAuth); - sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT); - sslPortAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); - sslPortAttributes.put(Port.TRUST_STORES, Collections.singleton(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE)); - getBrokerConfiguration().addObjectConfiguration(Port.class,sslPortAttributes); - } - } - - private void setSslStoreSystemProperties() - { - setSystemProperty("javax.net.ssl.keyStore", KEYSTORE); - setSystemProperty("javax.net.ssl.keyStorePassword", KEYSTORE_PASSWORD); - setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); - setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); - } - - private void clearSslStoreSystemProperties() - { - setSystemProperty("javax.net.ssl.keyStore", null); - setSystemProperty("javax.net.ssl.keyStorePassword", null); - setSystemProperty("javax.net.ssl.trustStore", null); - setSystemProperty("javax.net.ssl.trustStorePassword", null); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/jms/xa/XAResourceTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/jms/xa/XAResourceTest.java deleted file mode 100644 index e18f70b01d..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/jms/xa/XAResourceTest.java +++ /dev/null @@ -1,158 +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.jms.xa; - -import org.apache.qpid.client.AMQConnectionFactory; -import org.apache.qpid.jms.ConnectionURL; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.util.FileUtils; -import org.apache.qpid.test.unit.xa.AbstractXATestCase; -import org.apache.qpid.client.AMQXAResource; - -import org.apache.qpid.dtx.XidImpl; - -import javax.jms.XAConnection; -import javax.jms.XAConnectionFactory; -import javax.jms.XASession; -import javax.transaction.xa.XAException; -import javax.transaction.xa.XAResource; -import javax.transaction.xa.Xid; - -public class XAResourceTest extends AbstractXATestCase -{ - - private static final String FACTORY_NAME = "default"; - private static final String ALT_FACTORY_NAME = "connection2"; - - public void init() throws Exception - { - } - - public void testIsSameRMJoin() throws Exception - { - XAConnectionFactory factory = getConnectionFactory(FACTORY_NAME); - XAConnection conn1 = factory.createXAConnection("guest", "guest"); - XAConnection conn2 = factory.createXAConnection("guest", "guest"); - XAConnection conn3 = factory.createXAConnection("guest", "guest"); - - XASession session1 = conn1.createXASession(); - XASession session2 = conn2.createXASession(); - XASession session3 = conn3.createXASession(); - - AMQXAResource xaResource1 = (AMQXAResource)session1.getXAResource(); - AMQXAResource xaResource2 = (AMQXAResource)session2.getXAResource(); - AMQXAResource xaResource3 = (AMQXAResource)session3.getXAResource(); - - Xid xid = getNewXid(); - - xaResource1.start(xid, XAResource.TMNOFLAGS); - assertTrue("XAResource isSameRM", xaResource1.isSameRM(xaResource2)); - xaResource2.start(xid, XAResource.TMJOIN); - assertTrue("AMQXAResource siblings should be 1", xaResource1.getSiblings().size() == 1); - - assertTrue("AMQXAResource TMJOIN resource siblings should be 0", xaResource2.getSiblings().size() == 0); - - assertTrue("XAResource isSameRM", xaResource2.isSameRM(xaResource3)); - - - xaResource3.start(xid, XAResource.TMJOIN); - assertTrue("AMQXAResource siblings should be 1", xaResource2.getSiblings().size() == 1); - - xaResource1.end(xid, XAResource.TMSUCCESS); - assertTrue("AMQXAResource TMJOIN resource siblings should be 0", xaResource1.getSiblings().size() == 0); - - xaResource1.prepare(xid); - xaResource1.commit(xid, false); - - conn3.close(); - conn2.close(); - conn1.close(); - } - - /* - * Test with multiple XAResources originating from the same connection factory. XAResource(s) will be equal, - * as they originate from the same session. - */ - public void testIsSameRMSingleCF() throws Exception - { - XAConnectionFactory factory = getConnectionFactory(FACTORY_NAME); - XAConnection conn = factory.createXAConnection("guest","guest"); - XASession session = conn.createXASession(); - XAResource xaResource1 = session.getXAResource(); - XAResource xaResource2 = session.getXAResource(); - - assertEquals("XAResource objects not equal", xaResource1, xaResource2); - assertTrue("isSameRM not true for identical objects", xaResource1.isSameRM(xaResource2)); - - session.close(); - conn.close(); - } - - /* - * Test with multiple XAResources originating from different connection factory's and different sessions. XAResources will not be - * equal as they do not originate from the same session. As the UUID from the broker will be the same, isSameRM will be true. - * - */ - public void testIsSameRMMultiCF() throws Exception - { - startBroker(FAILING_PORT); - ConnectionURL url = getConnectionFactory(FACTORY_NAME).getConnectionURL(); - XAConnectionFactory factory = new AMQConnectionFactory(url); - XAConnectionFactory factory2 = new AMQConnectionFactory(url); - XAConnectionFactory factory3 = getConnectionFactory(ALT_FACTORY_NAME); - - XAConnection conn = factory.createXAConnection("guest","guest"); - XAConnection conn2 = factory2.createXAConnection("guest","guest"); - XAConnection conn3 = factory3.createXAConnection("guest","guest"); - - XASession session = conn.createXASession(); - XASession session2 = conn2.createXASession(); - XASession session3 = conn3.createXASession(); - - XAResource xaResource1 = session.getXAResource(); - XAResource xaResource2 = session2.getXAResource(); - XAResource xaResource3 = session3.getXAResource(); - - assertFalse("XAResource objects should not be equal", xaResource1.equals(xaResource2)); - assertTrue("isSameRM not true for identical objects", xaResource1.isSameRM(xaResource2)); - assertFalse("isSameRM true for XA Resources created by two different brokers", xaResource1.isSameRM(xaResource3)); - - conn.close(); - conn2.close(); - conn3.close(); - } - - @Override - public void tearDown() throws Exception - { - try - { - super.tearDown(); - } - finally - { - // Ensure we shutdown any secondary brokers - stopBroker(FAILING_PORT); - FileUtils.deleteDirectory(System.getProperty("QPID_WORK") + "/" + getFailingPort()); - } - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/ra/QpidRAConnectionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/ra/QpidRAConnectionTest.java deleted file mode 100644 index daee2842fa..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/ra/QpidRAConnectionTest.java +++ /dev/null @@ -1,89 +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.ra; - -import javax.jms.Connection; -import javax.jms.ConnectionFactory; -import javax.jms.Message; -import javax.jms.Session; - -import org.apache.log4j.Logger; - -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class QpidRAConnectionTest extends QpidBrokerTestCase -{ - private static final Logger _logger = Logger.getLogger(QpidRAConnectionTest.class); - - private static final String BROKER_PORT = "15672"; - - private static final String URL = "amqp://guest:guest@client/test?brokerlist='tcp://localhost:" + BROKER_PORT + "?sasl_mechs='PLAIN%25252520CRAM-MD5''"; - - public void testSessionCommitOnClosedConnectionThrowsException() throws Exception - { - QpidResourceAdapter ra = new QpidResourceAdapter(); - QpidRAManagedConnectionFactory mcf = new QpidRAManagedConnectionFactory(); - mcf.setConnectionURL(URL); - mcf.setResourceAdapter(ra); - ConnectionFactory cf = new QpidRAConnectionFactoryImpl(mcf, null); - Connection c = cf.createConnection(); - Session s = c.createSession(true, Session.SESSION_TRANSACTED); - c.close(); - - try - { - s.commit(); - fail("Exception should be thrown"); - } - catch(Exception e) - { - _logger.error("Commit threw exception", e); - assertTrue(e instanceof javax.jms.IllegalStateException); - } - - } - - public void testMessageAck() throws Exception - { - QpidResourceAdapter ra = new QpidResourceAdapter(); - QpidRAManagedConnectionFactory mcf = new QpidRAManagedConnectionFactory(); - mcf.setConnectionURL(URL); - mcf.setResourceAdapter(ra); - ConnectionFactory cf = new QpidRAConnectionFactoryImpl(mcf, null); - Connection c = cf.createConnection(); - Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE); - Message m = s.createTextMessage(); - - try - { - m.acknowledge(); - } - catch(Exception e) - { - fail("Acknowledge should not throw an exception"); - } - finally - { - s.close(); - c.close(); - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/ra/QpidRAXAResourceTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/ra/QpidRAXAResourceTest.java deleted file mode 100644 index 8f20a59b60..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/ra/QpidRAXAResourceTest.java +++ /dev/null @@ -1,55 +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.ra; - -import javax.jms.XAConnection; -import javax.jms.XAConnectionFactory; -import javax.jms.XASession; - -import org.apache.qpid.client.AMQXAResource; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class QpidRAXAResourceTest extends QpidBrokerTestCase -{ - private static final String FACTORY_NAME = "default"; - private static final String BROKER_PORT = "15672"; - private static final String URL = "amqp://guest:guest@client/test?brokerlist='tcp://localhost:" + BROKER_PORT + "?sasl_mechs='PLAIN%2520CRAM-MD5''"; - - public void testXAResourceIsSameRM() throws Exception - { - QpidResourceAdapter ra = new QpidResourceAdapter(); - QpidRAManagedConnectionFactory mcf = new QpidRAManagedConnectionFactory(); - mcf.setConnectionURL(URL); - mcf.setResourceAdapter(ra); - QpidRAManagedConnection mc = (QpidRAManagedConnection)mcf.createManagedConnection(null, null); - AMQXAResource xa1 = (AMQXAResource)mc.getXAResource(); - - XAConnectionFactory factory = getConnectionFactory(FACTORY_NAME); - XAConnection connection = factory.createXAConnection("guest", "guest"); - XASession s2 = connection.createXASession(); - AMQXAResource xaResource = (AMQXAResource)connection.createXASession().getXAResource(); - - assertTrue("QpidRAXAResource and XAResource should be from the same RM", xa1.isSameRM(xaResource)); - assertTrue("XAResource and QpidRAXAResource should be from the same RM", xaResource.isSameRM(xa1)); - - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxyTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxyTest.java deleted file mode 100644 index 7161cf1652..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxyTest.java +++ /dev/null @@ -1,113 +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.ra.admin; - -import javax.jms.Connection; -import javax.jms.ConnectionFactory; -import javax.jms.QueueConnection; -import javax.jms.QueueConnectionFactory; -import javax.jms.TopicConnection; -import javax.jms.TopicConnectionFactory; - -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class QpidConnectionFactoryProxyTest extends QpidBrokerTestCase -{ - private static final String BROKER_PORT = "15672"; - - private static final String URL = "amqp://guest:guest@client/test?brokerlist='tcp://localhost:" + BROKER_PORT + "?sasl_mechs='PLAIN%2520CRAM-MD5''"; - - public void testQueueConnectionFactory() throws Exception - { - QueueConnectionFactory cf = null; - QueueConnection c = null; - - try - { - cf = new QpidConnectionFactoryProxy(); - ((QpidConnectionFactoryProxy)cf).setConnectionURL(URL); - c = cf.createQueueConnection(); - assertTrue(c instanceof QueueConnection); - - } - finally - { - if(c != null) - { - c.close(); - } - } - } - - public void testTopicConnectionFactory() throws Exception - { - TopicConnectionFactory cf = null; - TopicConnection c = null; - - try - { - cf = new QpidConnectionFactoryProxy(); - ((QpidConnectionFactoryProxy)cf).setConnectionURL(URL); - c = cf.createTopicConnection(); - assertTrue(c instanceof TopicConnection); - - } - finally - { - if(c != null) - { - c.close(); - } - } - try - { - - } - finally - { - - } - } - - public void testConnectionFactory() throws Exception - { - ConnectionFactory cf = null; - Connection c = null; - - try - { - cf = new QpidConnectionFactoryProxy(); - ((QpidConnectionFactoryProxy)cf).setConnectionURL(URL); - c = cf.createConnection(); - assertTrue(c instanceof Connection); - - } - finally - { - if(c != null) - { - c.close(); - } - - } - } -} - diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/scripts/QpidPasswdTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/scripts/QpidPasswdTest.java deleted file mode 100644 index e483660f4c..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/scripts/QpidPasswdTest.java +++ /dev/null @@ -1,80 +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.scripts; - -import java.io.File; -import java.util.concurrent.TimeUnit; - -import org.apache.qpid.test.utils.Piper; -import org.apache.qpid.test.utils.QpidTestCase; -import org.apache.qpid.util.SystemUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class QpidPasswdTest extends QpidTestCase -{ - private static final Logger LOGGER = LoggerFactory.getLogger(QpidPasswdTest.class); - - private static final String PASSWD_SCRIPT = "qpid-passwd"; - private static final String EXPECTED_OUTPUT = "user1:rL0Y20zC+Fzt72VPzMSk2A=="; - - public void testRunScript() throws Exception - { - if(SystemUtils.isWindows()) - { - return; - } - Process process = null; - try - { - String scriptPath = - QpidTestCase.QPID_HOME + File.separatorChar - + "bin" + File.separatorChar - + PASSWD_SCRIPT; - - LOGGER.info("About to run script: " + scriptPath); - - ProcessBuilder pb = new ProcessBuilder(scriptPath, "user1", "foo"); - pb.redirectErrorStream(true); - process = pb.start(); - - Piper piper = new Piper(process.getInputStream(), System.out, EXPECTED_OUTPUT, EXPECTED_OUTPUT); - piper.start(); - - boolean finishedSuccessfully = piper.await(2, TimeUnit.SECONDS); - assertTrue( - "Script should have completed with expected output " + EXPECTED_OUTPUT + ". Check standard output for actual output.", - finishedSuccessfully); - process.waitFor(); - piper.join(); - - assertEquals("Unexpected exit value from backup script", 0, process.exitValue()); - } - finally - { - if (process != null) - { - process.getErrorStream().close(); - process.getInputStream().close(); - process.getOutputStream().close(); - } - } - - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/BrokerStartupTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/BrokerStartupTest.java deleted file mode 100644 index 9f5dd2ec39..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/BrokerStartupTest.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.server; - -import java.io.File; -import java.util.List; - -import javax.jms.Connection; -import javax.jms.Queue; -import javax.jms.Session; - -import junit.framework.AssertionFailedError; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; - -import org.apache.qpid.client.AMQConnectionURL; -import org.apache.qpid.server.logging.AbstractTestLogging; -import org.apache.qpid.util.LogMonitor; - -/** - * Series of tests to validate the external Java broker starts up as expected. - */ -public class BrokerStartupTest extends AbstractTestLogging -{ - public void setUp() throws Exception - { - // We either do this here or have a null check in tearDown. - // As when this test is run against profiles other than java it will NPE - _monitor = new LogMonitor(_outputFile); - //We explicitly do not call super.setUp as starting up the broker is - //part of the test case. - } - - /** - * This test simply tests that the broker will startup even if there is no config file (i.e. that it can use the - * currently packaged initial config file (all system tests by default generate their own config file). - * - * - * @throws Exception - */ - public void testStartupWithNoConfig() throws Exception - { - if (isJavaBroker()) - { - int port = getPort(0); - int managementPort = getManagementPort(port); - int connectorServerPort = managementPort + JMXPORT_CONNECTORSERVER_OFFSET; - - setTestSystemProperty("qpid.amqp_port",String.valueOf(port)); - setTestSystemProperty("qpid.jmx_port",String.valueOf(managementPort)); - setTestSystemProperty("qpid.rmi_port",String.valueOf(connectorServerPort)); - setTestSystemProperty("qpid.http_port",String.valueOf(DEFAULT_HTTP_MANAGEMENT_PORT)); - - File brokerConfigFile = new File(getTestConfigFile(port)); - if (brokerConfigFile.exists()) - { - // Config exists from previous test run, delete it. - brokerConfigFile.delete(); - } - - startBroker(port, null); - - AMQConnectionURL url = new AMQConnectionURL(String.format("amqp://" - + GUEST_USERNAME - + ":" - + GUEST_PASSWORD - + "@clientid/?brokerlist='localhost:%d'", port)); - Connection conn = getConnection(url); - assertNotNull(conn); - conn.close(); - } - } - /** - * Description: - * Test that providing an invalid broker logging configuration file does not - * cause the broker to enable DEBUG logging that will seriously impair - * performance - * Input: - * -l value that does not exist - *

- * Output: - *

- * No DEBUG output - *

- * Validation Steps: - *

- * 1. Start the broker and verify no DEBUG output exists - * - * @throws Exception caused by broker startup - */ - public void testInvalidLog4jConfigurationFile() throws Exception - { - // This logging startup code only occurs when you run a Java broker, - // that broker must be started via Main so not an InVM broker. - if (isJavaBroker() && isExternalBroker() && !isInternalBroker()) - { - //Remove test Log4j config from the commandline - setBrokerCommandLog4JFile(new File("invalid file")); - - // The broker has a built in default log4j configuration set up - // so if the the broker cannot load the -l value it will use default - // use this default. Test that this is correctly loaded, by - // including -Dlog4j.debug so we can validate. - setBrokerEnvironment("QPID_OPTS", "-Dlog4j.debug"); - - // Disable all client logging so we can test for broker DEBUG only. - setLoggerLevel(Logger.getRootLogger(), Level.WARN); - setLoggerLevel(Logger.getLogger("qpid.protocol"), Level.WARN); - setLoggerLevel(Logger.getLogger("org.apache.qpid"), Level.WARN); - - // Set the broker to use info level logging, which is the qpid-server - // default. Rather than debug which is the test default. - setBrokerOnlySystemProperty("amqj.server.logging.level", "info"); - // Set the logging defaults to info for this test. - setBrokerOnlySystemProperty("amqj.logging.level", "info"); - setBrokerOnlySystemProperty("root.logging.level", "info"); - - startBroker(); - - assertEquals("Log4j could not load desired configruation.", - 0, findMatches("log4j:ERROR Could not read configuration file from URL").size()); - - assertEquals("Logging did not error as expected", - 1, waitAndFindMatches("Logging configuration error: unable to read file ").size()); - - - // Perfom some action on the broker to ensure that we hit the DEBUG - // messages that we know are there. Though the current xml parsing - // will generate a LOT of DEBUG on startup. - Connection connection = getConnection(); - - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - Queue queue = session.createQueue(getTestQueueName()); - session.createConsumer(queue).close(); - - int COUNT = 10; - sendMessage(session, queue, COUNT); - - assertEquals(COUNT,drainQueue(queue)); - - List results = waitAndFindMatches("DEBUG"); - try - { - // Validation - - assertEquals("DEBUG messages should not be logged", 0, results.size()); - } - catch (AssertionFailedError afe) - { - System.err.println("Log Dump:"); - for (String log : results) - { - System.err.println(log); - } - - if (results.size() == 0) - { - System.err.println("Monitored file contents:"); - System.err.println(_monitor.readFile()); - } - - throw afe; - } - } - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/SupportedProtocolVersionsTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/SupportedProtocolVersionsTest.java deleted file mode 100644 index 42f3854d32..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/SupportedProtocolVersionsTest.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.framing.ProtocolVersion; -import org.apache.qpid.server.configuration.BrokerProperties; -import org.apache.qpid.server.model.Protocol; -import org.apache.qpid.server.model.adapter.PortFactoryTest; -import org.apache.qpid.server.plugin.AMQPProtocolVersionWrapper; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -/** - * Tests to validate it is possible to disable support for particular protocol - * versions entirely, rather than selectively excluding them on particular ports, - * and it is possible to configure the reply to an unsupported protocol initiation. - *

- * Protocol exclusion/inclusion are unit tested as part of {@link PortFactoryTest} - */ -public class SupportedProtocolVersionsTest extends QpidBrokerTestCase -{ - public void setUp() throws Exception - { - // No-op, we call super.setUp() from test methods after appropriate config overrides - } - - private void clearProtocolSupportManipulations() - { - //Remove the QBTC provided protocol manipulations, giving only the protocols which default to enabled - setSystemProperty(BrokerProperties.PROPERTY_BROKER_DEFAULT_AMQP_PROTOCOL_EXCLUDES, null); - setSystemProperty(BrokerProperties.PROPERTY_BROKER_DEFAULT_AMQP_PROTOCOL_INCLUDES, null); - } - - /** - * Test that 0-10, 0-9-1, 0-9, and 0-8 support is present when no - * attempt has yet been made to disable them, and forcing the client - * to negotiate from a particular protocol version returns a connection - * using the expected protocol version. - */ - public void testDefaultProtocolSupport() throws Exception - { - clearProtocolSupportManipulations(); - - super.setUp(); - - //Verify requesting a 0-10 connection works - setTestClientSystemProperty(ClientProperties.AMQP_VERSION, "0-10"); - AMQConnection connection = (AMQConnection) getConnection(); - assertEquals("Unexpected protocol version in use", ProtocolVersion.v0_10, connection.getProtocolVersion()); - connection.close(); - - //Verify requesting a 0-91 connection works - setTestClientSystemProperty(ClientProperties.AMQP_VERSION, "0-9-1"); - connection = (AMQConnection) getConnection(); - assertEquals("Unexpected protocol version in use", ProtocolVersion.v0_91, connection.getProtocolVersion()); - connection.close(); - - //Verify requesting a 0-9 connection works - setTestClientSystemProperty(ClientProperties.AMQP_VERSION, "0-9"); - connection = (AMQConnection) getConnection(); - assertEquals("Unexpected protocol version in use", ProtocolVersion.v0_9, connection.getProtocolVersion()); - connection.close(); - - //Verify requesting a 0-8 connection works - setTestClientSystemProperty(ClientProperties.AMQP_VERSION, "0-8"); - connection = (AMQConnection) getConnection(); - assertEquals("Unexpected protocol version in use", ProtocolVersion.v8_0, connection.getProtocolVersion()); - connection.close(); - } - - public void testDisabling010and10() throws Exception - { - clearProtocolSupportManipulations(); - - //disable 0-10 and 1-0 support - setSystemProperty(BrokerProperties.PROPERTY_BROKER_DEFAULT_AMQP_PROTOCOL_EXCLUDES, - Protocol.AMQP_1_0 + "," + Protocol.AMQP_0_10); - - super.setUp(); - - //Verify initially requesting a 0-10 connection now negotiates a 0-91 - //connection as the broker should reply with its highest supported protocol - setTestClientSystemProperty(ClientProperties.AMQP_VERSION, "0-10"); - AMQConnection connection = (AMQConnection) getConnection(); - assertEquals("Unexpected protocol version in use", ProtocolVersion.v0_91, connection.getProtocolVersion()); - connection.close(); - } - - public void testConfiguringReplyingToUnsupported010ProtocolInitiationWith09insteadOf091() throws Exception - { - clearProtocolSupportManipulations(); - - //disable 0-10 support, and set the default unsupported protocol initiation reply to 0-9 - setSystemProperty(BrokerProperties.PROPERTY_BROKER_DEFAULT_AMQP_PROTOCOL_EXCLUDES, - Protocol.AMQP_1_0 + "," + Protocol.AMQP_0_10); - setSystemProperty(BrokerProperties.PROPERTY_DEFAULT_SUPPORTED_PROTOCOL_REPLY, "v0_9"); - - super.setUp(); - - //Verify initially requesting a 0-10 connection now negotiates a 0-9 connection as the - //broker should reply with its 'default unsupported protocol initiation reply' as opposed - //to the previous behaviour of the highest supported protocol version. - setTestClientSystemProperty(ClientProperties.AMQP_VERSION, "0-10"); - AMQConnection connection = (AMQConnection) getConnection(); - assertEquals("Unexpected protocol version in use", ProtocolVersion.v0_9, connection.getProtocolVersion()); - connection.close(); - - //Verify requesting a 0-91 connection directly still works, as its support is still enabled - setTestClientSystemProperty(ClientProperties.AMQP_VERSION, "0-9-1"); - connection = (AMQConnection) getConnection(); - assertEquals("Unexpected protocol version in use", ProtocolVersion.v0_91, connection.getProtocolVersion()); - connection.close(); - } - - public void testProtocolIsExpectedBasedOnTestProfile() throws Exception - { - super.setUp(); - final AMQConnection connection = (AMQConnection) getConnection(); - final Protocol expectedBrokerProtocol = getBrokerProtocol(); - final AMQPProtocolVersionWrapper amqpProtocolVersionWrapper = new AMQPProtocolVersionWrapper(expectedBrokerProtocol); - final ProtocolVersion protocolVersion = connection.getProtocolVersion(); - assertTrue("Connection AMQP protocol " + expectedBrokerProtocol + "is not the same as the test specified protocol " + protocolVersion, - areEquivalent(amqpProtocolVersionWrapper, protocolVersion)); - connection.close(); - } - - private boolean areEquivalent(AMQPProtocolVersionWrapper amqpProtocolVersionWrapper, ProtocolVersion protocolVersion) - { - byte byteMajor = (byte)amqpProtocolVersionWrapper.getMajor(); - byte byteMinor; - if (amqpProtocolVersionWrapper.getPatch() == 0) - { - byteMinor = (byte)amqpProtocolVersionWrapper.getMinor(); - } - else - { - final StringBuilder sb = new StringBuilder(); - sb.append(amqpProtocolVersionWrapper.getMinor()); - sb.append(amqpProtocolVersionWrapper.getPatch()); - byteMinor = Byte.valueOf(sb.toString()).byteValue(); - } - return (protocolVersion.getMajorVersion() == byteMajor && protocolVersion.getMinorVersion() == byteMinor); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/exchange/ReturnUnroutableMandatoryMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/exchange/ReturnUnroutableMandatoryMessageTest.java deleted file mode 100644 index 9f145cd62c..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/exchange/ReturnUnroutableMandatoryMessageTest.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.exchange; - -import org.apache.log4j.Logger; - -import org.apache.qpid.client.AMQHeadersExchange; -import org.apache.qpid.client.AMQNoRouteException; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.url.AMQBindingURL; -import org.apache.qpid.url.BindingURL; - -import javax.jms.Connection; -import javax.jms.ExceptionListener; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.TextMessage; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class ReturnUnroutableMandatoryMessageTest extends QpidBrokerTestCase implements ExceptionListener -{ - private static final Logger _logger = Logger.getLogger(ReturnUnroutableMandatoryMessageTest.class); - - private final List _bouncedMessageList = Collections.synchronizedList(new ArrayList()); - - static - { - String workdir = System.getProperty("QPID_WORK"); - if (workdir == null || workdir.equals("")) - { - String tempdir = System.getProperty("java.io.tmpdir"); - _logger.info("QPID_WORK not set using tmp directory: " + tempdir); - System.setProperty("QPID_WORK", tempdir); - } - } - - /** - * Tests that mandatory message which are not routable are returned to the producer - * - * @throws Exception - */ - public void testReturnUnroutableMandatoryMessage_HEADERS() throws Exception - { - _bouncedMessageList.clear(); - MessageConsumer consumer = null; - AMQSession producerSession = null; - AMQHeadersExchange queue = null; - Connection con=null, con2 = null; - try - { - con = getConnection(); - - AMQSession consumerSession = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE); - - queue = new AMQHeadersExchange(new AMQBindingURL(ExchangeDefaults.HEADERS_EXCHANGE_CLASS + "://" + ExchangeDefaults.HEADERS_EXCHANGE_NAME + "/test/queue1?" + BindingURL.OPTION_ROUTING_KEY + "='F0000=1'")); - - FieldTable ft = new FieldTable(); - ft.setString("F1000", "1"); - consumerSession.declareAndBind(queue, ft); - - consumer = consumerSession.createConsumer(queue); - - //force synch to ensure the consumer has resulted in a bound queue - //((AMQSession) consumerSession).declareExchangeSynch(ExchangeDefaults.HEADERS_EXCHANGE_NAME, ExchangeDefaults.HEADERS_EXCHANGE_CLASS); - // This is the default now - - con2 = getConnection(); - - con2.setExceptionListener(this); - producerSession = (AMQSession) con2.createSession(false, Session.CLIENT_ACKNOWLEDGE); - - // Need to start the "producer" connection in order to receive bounced messages - _logger.info("Starting producer connection"); - con2.start(); - } - catch (JMSException jmse) - { - fail(jmse.getMessage()); - } - - try - { - MessageProducer nonMandatoryProducer = producerSession.createProducer(queue, false, false); - MessageProducer mandatoryProducer = producerSession.createProducer(queue); - - // First test - should neither be bounced nor routed - _logger.info("Sending non-routable non-mandatory message"); - TextMessage msg1 = producerSession.createTextMessage("msg1"); - nonMandatoryProducer.send(msg1); - - // Second test - should be bounced - _logger.info("Sending non-routable mandatory message"); - TextMessage msg2 = producerSession.createTextMessage("msg2"); - mandatoryProducer.send(msg2); - - // Third test - should be routed - _logger.info("Sending routable message"); - TextMessage msg3 = producerSession.createTextMessage("msg3"); - msg3.setStringProperty("F1000", "1"); - mandatoryProducer.send(msg3); - - _logger.info("Starting consumer connection"); - con.start(); - TextMessage tm = (TextMessage) consumer.receive(1000L); - - assertTrue("No message routed to receiver", tm != null); - assertTrue("Wrong message routed to receiver: " + tm.getText(), "msg3".equals(tm.getText())); - - try - { - Thread.sleep(1000L); - } - catch (InterruptedException e) - { - ; - } - - assertTrue("Wrong number of messages bounced (expect 1): " + _bouncedMessageList.size(), _bouncedMessageList.size() == 1); - Message m = _bouncedMessageList.get(0); - assertTrue("Wrong message bounced: " + m.toString(), m.toString().contains("msg2")); - } - catch (JMSException jmse) - { - - } - con.close(); - con2.close(); - - } - - public void testReturnUnroutableMandatoryMessage_QUEUE() throws Exception - { - _bouncedMessageList.clear(); - Connection con = getConnection(); - - AMQSession consumerSession = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE); - - AMQQueue valid_queue = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, "testReturnUnroutableMandatoryMessage_QUEUE"); - AMQQueue invalid_queue = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, "testReturnUnroutableMandatoryMessage_QUEUE_INVALID"); - MessageConsumer consumer = consumerSession.createConsumer(valid_queue); - - //force synch to ensure the consumer has resulted in a bound queue - //((AMQSession) consumerSession).declareExchangeSynch(ExchangeDefaults.HEADERS_EXCHANGE_NAME, ExchangeDefaults.HEADERS_EXCHANGE_CLASS); - // This is the default now - - Connection con2 = getConnection(); - - con2.setExceptionListener(this); - AMQSession producerSession = (AMQSession) con2.createSession(false, Session.CLIENT_ACKNOWLEDGE); - - // Need to start the "producer" connection in order to receive bounced messages - _logger.info("Starting producer connection"); - con2.start(); - - MessageProducer nonMandatoryProducer = producerSession.createProducer(valid_queue, false, false); - MessageProducer mandatoryProducer = producerSession.createProducer(invalid_queue); - - // First test - should be routed - _logger.info("Sending non-mandatory message"); - TextMessage msg1 = producerSession.createTextMessage("msg1"); - nonMandatoryProducer.send(msg1); - - // Second test - should be bounced - _logger.info("Sending non-routable mandatory message"); - TextMessage msg2 = producerSession.createTextMessage("msg2"); - mandatoryProducer.send(msg2); - - _logger.info("Starting consumer connection"); - con.start(); - TextMessage tm = (TextMessage) consumer.receive(1000L); - - assertTrue("No message routed to receiver", tm != null); - assertTrue("Wrong message routed to receiver: " + tm.getText(), "msg1".equals(tm.getText())); - - try - { - Thread.sleep(1000L); - } - catch (InterruptedException e) - { - ; - } - - assertTrue("Wrong number of messages bounced (expect 1): " + _bouncedMessageList.size(), _bouncedMessageList.size() == 1); - Message m = _bouncedMessageList.get(0); - assertTrue("Wrong message bounced: " + m.toString(), m.toString().contains("msg2")); - - con.close(); - con2.close(); - } - - public void testReturnUnroutableMandatoryMessage_TOPIC() throws Exception - { - _bouncedMessageList.clear(); - Connection con = getConnection(); - - AMQSession consumerSession = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE); - - AMQTopic valid_topic = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_CLASS, "test.Return.Unroutable.Mandatory.Message.TOPIC"); - AMQTopic invalid_topic = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_CLASS, "test.Return.Unroutable.Mandatory.Message.TOPIC.invalid"); - MessageConsumer consumer = consumerSession.createConsumer(valid_topic); - - //force synch to ensure the consumer has resulted in a bound queue - //((AMQSession) consumerSession).declareExchangeSynch(ExchangeDefaults.HEADERS_EXCHANGE_NAME, ExchangeDefaults.HEADERS_EXCHANGE_CLASS); - // This is the default now - - Connection con2 = getConnection(); - - con2.setExceptionListener(this); - AMQSession producerSession = (AMQSession) con2.createSession(false, Session.CLIENT_ACKNOWLEDGE); - - // Need to start the "producer" connection in order to receive bounced messages - _logger.info("Starting producer connection"); - con2.start(); - - MessageProducer nonMandatoryProducer = producerSession.createProducer(valid_topic, false, false); - MessageProducer mandatoryProducer = producerSession.createProducer(invalid_topic, false, true); - - // First test - should be routed - _logger.info("Sending non-mandatory message"); - TextMessage msg1 = producerSession.createTextMessage("msg1"); - nonMandatoryProducer.send(msg1); - - // Second test - should be bounced - _logger.info("Sending non-routable mandatory message"); - TextMessage msg2 = producerSession.createTextMessage("msg2"); - mandatoryProducer.send(msg2); - - _logger.info("Starting consumer connection"); - con.start(); - TextMessage tm = (TextMessage) consumer.receive(1000L); - - assertTrue("No message routed to receiver", tm != null); - assertTrue("Wrong message routed to receiver: " + tm.getText(), "msg1".equals(tm.getText())); - - try - { - Thread.sleep(1000L); - } - catch (InterruptedException e) - { - ; - } - - assertEquals("Wrong number of messages bounced: ", 1, _bouncedMessageList.size()); - Message m = _bouncedMessageList.get(0); - assertTrue("Wrong message bounced: " + m.toString(), m.toString().contains("msg2")); - - con.close(); - con2.close(); - } - - public static junit.framework.Test suite() - { - return new junit.framework.TestSuite(ReturnUnroutableMandatoryMessageTest.class); - } - - public void onException(JMSException jmsException) - { - - Exception linkedException = null; - linkedException = jmsException.getLinkedException(); - if (linkedException instanceof AMQNoRouteException) - { - AMQNoRouteException noRoute = (AMQNoRouteException) linkedException; - Message bounced = (Message) noRoute.getUndeliveredMessage(); - _bouncedMessageList.add(bounced); - _logger.info("Caught expected NoRouteException"); - } - else - { - _logger.warn("Caught exception on producer: ", jmsException); - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/failover/FailoverMethodTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/failover/FailoverMethodTest.java deleted file mode 100644 index 9e2bd28c43..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/failover/FailoverMethodTest.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.failover; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.AMQConnectionClosedException; -import org.apache.qpid.AMQDisconnectedException; -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQConnectionURL; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.util.SystemUtils; - -import javax.jms.ExceptionListener; -import javax.jms.JMSException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -public class FailoverMethodTest extends QpidBrokerTestCase implements ExceptionListener -{ - private static final Logger LOGGER = LoggerFactory.getLogger(FailoverMethodTest.class); - private CountDownLatch _failoverComplete = new CountDownLatch(1); - private final int _freePortWithNoBroker = findFreePort(); - - /** - * Test that the round robin method has the correct delays. - * The first connection will work but the localhost connection should fail but the duration it takes - * to report the failure is what is being tested. - * - */ - public void testFailoverRoundRobinDelay() throws Exception - { - if (SystemUtils.isWindows()) - { - //TODO Test requires redevelopment - timings/behaviour on windows mean it fails - return; - } - - //note: The first broker has no connect delay and the default 1 retry - // while the tcp:localhost broker has 3 retries with a 2s connect delay - String connectionString = "amqp://guest:guest@/test?brokerlist=" + - "'tcp://localhost:" + getPort() + - ";tcp://localhost:" + _freePortWithNoBroker + "?connectdelay='2000',retries='3''"; - - AMQConnectionURL url = new AMQConnectionURL(connectionString); - - try - { - long start = System.currentTimeMillis(); - AMQConnection connection = new AMQConnection(url); - - connection.setExceptionListener(this); - - LOGGER.debug("Stopping broker"); - stopBroker(); - LOGGER.debug("Stopped broker"); - - _failoverComplete.await(30, TimeUnit.SECONDS); - assertEquals("failoverLatch was not decremented in given timeframe", - 0, _failoverComplete.getCount()); - - long end = System.currentTimeMillis(); - - long duration = (end - start); - - //Failover should take more that 6 seconds. - // 3 Retries - // so VM Broker NoDelay 0 (Connect) NoDelay 0 - // then TCP NoDelay 0 Delay 1 Delay 2 Delay 3 - // so 3 delays of 2s in total for connection - // as this is a tcp connection it will take 1second per connection to fail - // so max time is 6seconds of delay plus 4 seconds of TCP Delay + 1 second of runtime. == 11 seconds - - // Ensure we actually had the delay - assertTrue("Failover took less than 6 seconds", duration > 6000); - - // Ensure we don't have delays before initial connection and reconnection. - // We allow 1 second for initial connection and failover logic on top of 6s of sleep. - assertTrue("Failover took more than 11 seconds:(" + duration + ")", duration < 11000); - } - catch (AMQException e) - { - fail(e.getMessage()); - } - } - - public void testFailoverSingleDelay() throws Exception - { - if (SystemUtils.isWindows()) - { - //TODO Test requires redevelopment - timings/behaviour on windows mean it fails - return; - } - - String connectionString = "amqp://guest:guest@/test?brokerlist='tcp://localhost:" + getPort() + "?connectdelay='2000',retries='3''"; - - AMQConnectionURL url = new AMQConnectionURL(connectionString); - - try - { - long start = System.currentTimeMillis(); - AMQConnection connection = new AMQConnection(url); - - connection.setExceptionListener(this); - - LOGGER.debug("Stopping broker"); - stopBroker(); - LOGGER.debug("Stopped broker"); - - _failoverComplete.await(30, TimeUnit.SECONDS); - assertEquals("failoverLatch was not decremented in given timeframe", - 0, _failoverComplete.getCount()); - - long end = System.currentTimeMillis(); - - long duration = (end - start); - - //Failover should take more that 6 seconds. - // 3 Retries - // so NoDelay 0 (Connect) NoDelay 0 Delay 1 Delay 2 Delay 3 - // so 3 delays of 2s in total for connection - // so max time is 6 seconds of delay + 1 second of runtime. == 7 seconds - - // Ensure we actually had the delay - assertTrue("Failover took less than 6 seconds", duration > 6000); - - // Ensure we don't have delays before initial connection and reconnection. - // We allow 3 second for initial connection and failover logic on top of 6s of sleep. - assertTrue("Failover took more than 9 seconds:(" + duration + ")", duration < 9000); - } - catch (AMQException e) - { - fail(e.getMessage()); - } - } - - - /** - * Test that setting 'nofailover' as the failover policy does not result in - * delays or connection attempts when the initial connection is lost. - * - * Test validates that there is a connection delay as required on initial - * connection. - */ - public void testNoFailover() throws Exception - { - if (SystemUtils.isWindows()) - { - //TODO Test requires redevelopment - timings/behaviour on windows mean it fails - return; - } - - int CONNECT_DELAY = 2000; - String connectionString = "amqp://guest:guest@/test?brokerlist='tcp://localhost:" + getPort() + "?connectdelay='" + CONNECT_DELAY + "'," + - "retries='3'',failover='nofailover'"; - - - AMQConnectionURL url = new AMQConnectionURL(connectionString); - - Thread brokerStart = null; - try - { - //Kill initial broker - stopBroker(); - - //Create a thread to start the broker asynchronously - brokerStart = new Thread(new Runnable() - { - public void run() - { - try - { - //Wait before starting broker - // The wait should allow at least 1 retries to fail before broker is ready - Thread.sleep(750); - startBroker(); - } - catch (Exception e) - { - LOGGER.error("Exception whilst starting broker", e); - } - } - }); - - brokerStart.start(); - long start = System.currentTimeMillis(); - //Start the connection so it will use the retries - AMQConnection connection = new AMQConnection(url); - - long end = System.currentTimeMillis(); - long duration = (end - start); - - // Check that we actually had a delay in connection - assertTrue("Initial connection should be longer than 1 delay : " + CONNECT_DELAY + " <:(" + duration + ")", duration > CONNECT_DELAY); - - - connection.setExceptionListener(this); - - //Ensure we collect the brokerStart thread - brokerStart.join(); - brokerStart = null; - - start = System.currentTimeMillis(); - - //Kill connection - stopBroker(); - - _failoverComplete.await(30, TimeUnit.SECONDS); - assertEquals("failoverLatch was not decremented in given timeframe", 0, _failoverComplete.getCount()); - - end = System.currentTimeMillis(); - - duration = (end - start); - - // Notification of the connection failure should be very quick as we are denying the ability to failover. - // It may not be as quick for Java profile tests so lets just make sure it is less than the connectiondelay - // Occasionally it takes 1s so we have to set CONNECT_DELAY to be higher to take that in to account. - assertTrue("Notification of the connection failure took was : " + CONNECT_DELAY + " >:(" + duration + ")", duration < CONNECT_DELAY); - } - catch (AMQException e) - { - fail(e.getMessage()); - } - finally - { - // Guard against the case where the broker took too long to start - // and the initial connection failed to be formed. - if (brokerStart != null) - { - brokerStart.join(); - } - } - } - - @Override - public void onException(JMSException e) - { - if (e.getLinkedException() instanceof AMQDisconnectedException || e.getLinkedException() instanceof AMQConnectionClosedException) - { - LOGGER.debug("Received AMQDisconnectedException"); - _failoverComplete.countDown(); - } - else - { - LOGGER.error("Unexpected underlying exception", e.getLinkedException()); - } - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AbstractTestLogging.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AbstractTestLogging.java deleted file mode 100644 index 8555d9c751..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AbstractTestLogging.java +++ /dev/null @@ -1,413 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.logging; - -import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.util.LogMonitor; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.text.NumberFormat; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; - -/** - * Abstract superclass for logging test set up and utility methods. - * - * So named to prevent it being selected itself as a test to run by the test suite. - */ -public class AbstractTestLogging extends QpidBrokerTestCase -{ - public static final long DEFAULT_LOG_WAIT = 2000; - public static final String TEST_LOG_PREFIX = "MESSAGE"; - protected LogMonitor _monitor; - - @Override - public void setUp() throws Exception - { - setLogMessagePrefix(); - - super.setUp(); - _monitor = new LogMonitor(_outputFile); - } - - protected void setLogMessagePrefix() - { - //set the message prefix to facilitate scraping from the munged test output. - setSystemProperty("qpid.logging.prefix", TEST_LOG_PREFIX); - } - - @Override - public void tearDown() throws Exception - { - _monitor.close(); - super.tearDown(); - } - - /** - * assert that the requested log message has not occured - * - * @param log - * - * @throws IOException - */ - public void assertLoggingNotYetOccured(String log) throws IOException - { - // Ensure the alert has not occured yet - assertEquals("Message has already occured:" + log, 0, - findMatches(log).size()); - } - - protected void validateMessageID(String id, String log) - { - assertEquals("Incorrect message", id, getMessageID(log)); - } - - protected String getMessageID(String log) - { - String message = fromMessage(log); - - return message.substring(0, message.indexOf(" ")); - } - - /** - * Return the first channel id from the log string - * ' ch;X' if there is no channel id return -1. - * - * @param log the log string to search. - * - * @return channel id or -1 if no channel id exists. - */ - protected int getChannelID(String log) - { - int start = log.indexOf("ch:") + 3; - - // If we do a check for ] as the boundary we will get cases where log - // is presented with the bounding. If we don't match a ] then we can use - // the end of the string as the boundary. - int end = log.indexOf("]", start); - if (end == -1) - { - end = log.length(); - } - return parseInt(log, start, end); - } - - protected String fromMessage(String log) - {; - int startSubject = log.indexOf("]") + 1; - int start = log.indexOf("]", startSubject) + 1; - - // If we don't have a subject then the second indexOf will return 0 - // in which case we can use the end of the actor as the index. - if (start == 0) - { - start = startSubject; - } - - return log.substring(start).trim(); - } - - /** - * Extract the Subject from the Log Message. - * - * The subject is the second block inclosed in brackets '[ ]'. - * - * If there is no Subject or the second block of brackets '[ ]' cannot be - * identified then an empty String ("") is returned. - * - * The brackets '[ ]' are not included in the returned String. - * - * @param log The log message to process - * - * @return the Subject string or the empty string ("") if the subject can't be identified. - */ - protected String fromSubject(String log) - { - int start = log.indexOf("[") + 1; - // Take the second index - start = log.indexOf("[", start) + 1; - - // There may not be a subject so in that case return nothing. - if (start == 0) - { - return ""; - } - - int end = log.indexOf("]", start); - try - { - return log.substring(start, end); - } - catch (IndexOutOfBoundsException iobe) - { - return ""; - } - } - - /** - * Extract the actor segment from the log message. - * The Actor segment is the first section enclosed in '[ ]'. - * - * No analysis is performed to ensure that the first '[ ]' section of the - * given log is really an Actor segment. - * - * The brackets '[ ]' are not included in the returned String. - * - * @param log the Log Message - * - * @return the Actor segment or "" if unable to locate '[ ]' section - */ - protected String fromActor(String log) - { - int start = log.indexOf("[") + 1; - int end = log.indexOf("]", start); - try - { - return log.substring(start, end).trim(); - } - catch (IndexOutOfBoundsException iobe) - { - return ""; - } - } - - /** - * Return the message String from the given message section - * - * @param log the Message Section - * - * @return the Message String. - */ - protected String getMessageString(String log) - { - // Remove the Log ID from the returned String - int start = log.indexOf(":") + 1; - - return log.substring(start).trim(); - } - - /** - * Given our log message extract the connection ID: - * - * The log string will contain the connectionID identified by 'con:' - * - * So extract the value shown here by X: - * - * 'con:X(' - * - * Extract the value between the ':' and '(' and process it as an Integer - * - * If we are unable to find the right index or process the substring as an - * Integer then return -1. - * - * @param log the log String to process - * - * @return the connection ID or -1. - */ - protected int getConnectionID(String log) - { - int conIDStart = log.indexOf("con:") + 4; - int conIDEnd = log.indexOf("(", conIDStart); - return parseInt(log, conIDStart, conIDEnd); - } - - /** - * Extract the log entry from the raw log line which will contain other - * log4j formatting. - * - * This formatting may impead our testing process so extract the log message - * as we know it to be formatted. - * - * This starts with the string MESSAGE - * - * @param rawLog the raw log - * - * @return the log we are expecting to be printed without the log4j prefixes - */ - protected String getLog(String rawLog) - { - int start = rawLog.indexOf(TEST_LOG_PREFIX); - return rawLog.substring(start); - } - - /** - * Extract the log entry from the result set. Positions are 0-based. - * - * @param results list of log message results to extract from - * @param position position in the list of the message to extract - * @return the message string - */ - protected String getLogMessage(List results, int position) - { - return getLog(results.get(position)); - } - - /** - * Extract the nth-from-last log entry from the result set. - * - * @param results list of log message results to extract from - * @param positionFromEnd position from end of the message list to extract (eg 0 for last) - * @return the message string - */ - protected String getLogMessageFromEnd(List results, int positionFromEnd) - { - int resultSize = results.size(); - return getLogMessage(results, resultSize - 1 - positionFromEnd); - } - - protected List findMatches(String toFind) throws IOException - { - return _monitor.findMatches(toFind); - } - - protected List waitAndFindMatches(String toFind) throws IOException - { - return waitAndFindMatches(toFind, DEFAULT_LOG_WAIT); - } - - protected List waitAndFindMatches(String toFind, long wait) throws IOException - { - return _monitor.waitAndFindMatches(toFind, wait); - } - - public boolean waitForMessage(String message) throws FileNotFoundException, IOException - { - return waitForMessage(message, DEFAULT_LOG_WAIT); - } - - public boolean waitForMessage(String message, long wait) throws FileNotFoundException, IOException - { - return _monitor.waitForMessage(message, wait); - } - - /** - * Given a list of messages that have been pulled out of a log file - * Process the results splitting the log statements in to lists based on the - * actor's connection ID. - * - * So for each log entry extract the Connecition ID from the Actor of the log - * - * Then use that as a key to a HashMap storing the list of log messages for - * that connection. - * - * @param logMessages The list of mixed connection log messages - * - * @return Map indexed by connection id to a list of log messages just for that connection. - */ - protected HashMap> splitResultsOnConnectionID(List logMessages) - { - HashMap> connectionSplitList = new HashMap>(); - - for (String log : logMessages) - { - // Get the connectionID from the Actor in the Message Log. - int cID = getConnectionID(fromActor(getLog(log))); - - List connectionData = connectionSplitList.get(cID); - - // Create the initial List if we don't have one already - if (connectionData == null) - { - connectionData = new LinkedList(); - connectionSplitList.put(cID, connectionData); - } - - // Store the log - connectionData.add(log); - } - - return connectionSplitList; - } - - /** - * Filter the give result set by the specficifed virtualhost. - * This is done using the getSlice to identify the virtualhost (vh) in the - * log message - * - * @param results full list of logs - * @param virtualHostName the virtualhostName to filter on - * - * @return the list of messages only for that virtualhost - */ - protected List filterResultsByVirtualHost(List results, String virtualHostName) - { - List filteredResults = new LinkedList(); - Iterator iterator = results.iterator(); - - while (iterator.hasNext()) - { - String log = iterator.next(); - - if (AbstractTestLogSubject.getSlice("vh", log).equals(virtualHostName)) - { - filteredResults.add(log); - } - } - - return filteredResults; - } - - /** - * Dump the log results. - */ - protected void dumpLogs(List results) throws IOException - { - dumpLogs(results, null); - } - - /** - * Dump the log results or if there are none, the contents of the - * monitored log file if the monitor is non-null. - */ - protected void dumpLogs(List results, LogMonitor monitor) throws IOException - { - System.err.println("Log Dump:"); - for (String log : results) - { - System.err.println(log); - } - - if (results.isEmpty() && monitor != null) - { - System.err.println("Monitored file contents:"); - System.err.println(monitor.readFile()); - } - } - - private int parseInt(final String logSubstring, final int start, final int end) - { - try - { - final NumberFormat format = NumberFormat.getInstance(Locale.getDefault()); - final Number number = format.parse(logSubstring.substring(start, end)); - return number.intValue(); - } - catch (Exception e) - { - return -1; - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AccessControlLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AccessControlLoggingTest.java deleted file mode 100644 index a0188626ee..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AccessControlLoggingTest.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.logging; - -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.security.acl.AbstractACLTestCase; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Session; -import java.util.List; - -/** - * ACL version 2/3 file testing to verify that ACL actor logging works correctly. - * - * This suite of tests validate that the AccessControl messages occur correctly - * and according to the following format: - * - *

- * ACL-1001 : Allowed Operation Object {PROPERTIES}
- * ACL-1002 : Denied Operation Object {PROPERTIES}
- * 
- */ -public class AccessControlLoggingTest extends AbstractTestLogging -{ - private static final String ACL_LOG_PREFIX = "ACL-"; - private static final String USER = "client"; - private static final String PASS = "guest"; - - public void setUp() throws Exception - { - // Write out ACL for this test - AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW client ACCESS VIRTUALHOST", - "ACL ALLOW client CREATE QUEUE name='allow'", - "ACL ALLOW-LOG client CREATE QUEUE name='allow-log'", - "ACL DENY client CREATE QUEUE name='deny'", - "ACL DENY-LOG client CREATE QUEUE name='deny-log'"); - - super.setUp(); - - } - - @Override - public void tearDown() throws Exception - { - try - { - super.tearDown(); - } - catch (JMSException e) - { - //we're throwing this away as it can happen in this test as the state manager remembers exceptions - //that we provoked with authentication failures, where the test passes - we can ignore on con close - } - } - - /** - * Test that {@code allow} ACL entries do not log anything. - */ - public void testAllow() throws Exception - { - Connection conn = getConnection(USER, PASS); - Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - conn.start(); - ((AMQSession) sess).createQueue(new AMQShortString("allow"), false, false, false); - - List matches = findMatches(ACL_LOG_PREFIX); - - assertTrue("Should be no ACL log messages", matches.isEmpty()); - } - - /** - * Test that {@code allow-log} ACL entries log correctly. - */ - public void testAllowLog() throws Exception - { - Connection conn = getConnection(USER, PASS); - Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - conn.start(); - ((AMQSession) sess).createQueue(new AMQShortString("allow-log"), false, false, false); - - List matches = findMatches(ACL_LOG_PREFIX); - - assertEquals("Should only be one ACL log message", 1, matches.size()); - - String log = getLogMessage(matches, 0); - String actor = fromActor(log); - String subject = fromSubject(log); - String message = getMessageString(fromMessage(log)); - - validateMessageID(ACL_LOG_PREFIX + 1001, log); - - assertTrue("Actor " + actor + " should contain the user identity: " + USER, actor.contains(USER)); - assertTrue("Subject should be empty", subject.length() == 0); - assertTrue("Message should start with 'Allowed'", message.startsWith("Allowed")); - assertTrue("Message should contain 'Create Queue'", message.contains("Create Queue")); - assertTrue("Message should have contained the queue name", message.contains("allow-log")); - } - - /** - * Test that {@code deny-log} ACL entries log correctly. - */ - public void testDenyLog() throws Exception - { - Connection conn = getConnection(USER, PASS); - Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - conn.start(); - try { - ((AMQSession) sess).createQueue(new AMQShortString("deny-log"), false, false, false); - fail("Should have denied queue creation"); - } - catch (AMQException amqe) - { - // Denied, so exception thrown - assertEquals("Expected ACCESS_REFUSED error code", AMQConstant.ACCESS_REFUSED, amqe.getErrorCode()); - } - - List matches = findMatches(ACL_LOG_PREFIX); - - assertEquals("Should only be one ACL log message", 1, matches.size()); - - String log = getLogMessage(matches, 0); - String actor = fromActor(log); - String subject = fromSubject(log); - String message = getMessageString(fromMessage(log)); - - validateMessageID(ACL_LOG_PREFIX + 1002, log); - - assertTrue("Actor " + actor + " should contain the user identity: " + USER, actor.contains(USER)); - assertTrue("Subject should be empty", subject.length() == 0); - assertTrue("Message should start with 'Denied'", message.startsWith("Denied")); - assertTrue("Message should contain 'Create Queue'", message.contains("Create Queue")); - assertTrue("Message should have contained the queue name", message.contains("deny-log")); - } - - /** - * Test that {@code deny} ACL entries do not log anything. - */ - public void testDeny() throws Exception - { - Connection conn = getConnection(USER, PASS); - Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - conn.start(); - try { - ((AMQSession) sess).createQueue(new AMQShortString("deny"), false, false, false); - fail("Should have denied queue creation"); - } - catch (AMQException amqe) - { - // Denied, so exception thrown - assertEquals("Expected ACCESS_REFUSED error code", AMQConstant.ACCESS_REFUSED, amqe.getErrorCode()); - } - - List matches = findMatches(ACL_LOG_PREFIX); - - assertTrue("Should be no ACL log messages", matches.isEmpty()); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AlertingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AlertingTest.java deleted file mode 100644 index 336dedb422..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AlertingTest.java +++ /dev/null @@ -1,196 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.server.logging; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import javax.jms.Connection; -import javax.jms.Queue; -import javax.jms.Session; - -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.server.management.plugin.HttpManagement; -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.model.Plugin; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager; -import org.apache.qpid.systest.rest.RestTestHelper; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class AlertingTest extends AbstractTestLogging -{ - - private Session _session; - private Connection _connection; - private Queue _destination; - private int _numMessages; - - private static final int ALERT_LOG_WAIT_PERIOD = 5000; - private static final String MESSAGE_COUNT_ALERT = "MESSAGE_COUNT_ALERT"; - - public void setUp() throws Exception - { - _numMessages = 50; - setTestSystemProperty("virtualhost.housekeepingCheckPeriod", String.valueOf(ALERT_LOG_WAIT_PERIOD)); - setTestSystemProperty("queue.alertThresholdQueueDepthMessages", String.valueOf(_numMessages)); - - // Then we do the normal setup stuff like starting the broker, getting a connection etc. - super.setUp(); - - setupConnection(); - } - - /** - * Create a new connection and ensure that our destination queue is created - * and bound. - * - * Note that the tests here that restart the broker rely on persistence. - * However, the queue creation here is transient. So the queue will not be - * rebound on restart. Hence the consumer creation here rather than just the - * once. - * - * The persistent messages will recreate the queue but not bind it (as it - * was not a durable queue) However, the consumer creation here will ensure - * that the queue is correctly bound and can receive new messages. - * - * @throws Exception - */ - private void setupConnection() - throws Exception - { - _connection = getConnection(); - _session = _connection.createSession(true, Session.SESSION_TRANSACTED); - _destination = _session.createQueue(getTestQueueName()); - - // Consumer is only used to actually create the destination - _session.createConsumer(_destination).close(); - } - - /** - * Checks the log file for MESSAGE_COUNT_ALERT, fails() the test if it's not found and - * places the entire contents in the message to help debug cruise control failures. - * - * @throws Exception - */ - private void wasAlertFired() throws Exception - { - if (!waitForMessage(MESSAGE_COUNT_ALERT, ALERT_LOG_WAIT_PERIOD)) - { - StringBuffer message = new StringBuffer("Could not find 'MESSAGE_COUNT_ALERT' in log file: " + _monitor.getMonitoredFile().getAbsolutePath()); - fail(message.toString()); - } - } - - public void testAlertingReallyWorks() throws Exception - { - // Send 5 messages, make sure that the alert was fired properly. - sendMessage(_session, _destination, _numMessages + 1); - _session.commit(); - wasAlertFired(); - } - - public void testAlertingReallyWorksWithRestart() throws Exception - { - sendMessage(_session, _destination, _numMessages + 1); - _session.commit(); - _connection.close(); - stopBroker(); - - // Rest the monitoring clearing the current output file. - _monitor.markDiscardPoint(); - startBroker(); - wasAlertFired(); - } - - /** - * Test that if the alert value is change from the previous value we can - * still get alerts. - * - * Test sends two messages to the broker then restarts the broker with new - * configuration. - * - * Validates that we only have two messages on the queue and then sends - * enough messages to trigger the alert. - * - * The alert is then validate. - * - * - * @throws Exception - */ - public void testAlertingReallyWorksWithChanges() throws Exception - { - // send some messages and nuke the logs - sendMessage(_session, _destination, 2); - _session.commit(); - // To prevent any failover/retry/connection dropped errors - _connection.close(); - - stopBroker(); - - _monitor.markDiscardPoint(); - - RestTestHelper restTestHelper = new RestTestHelper(findFreePort()); - TestBrokerConfiguration config = getBrokerConfiguration(); - config.addHttpManagementConfiguration(); - config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.PORT, restTestHelper.getHttpPort()); - config.removeObjectConfiguration(Port.class, TestBrokerConfiguration.ENTRY_NAME_JMX_PORT); - config.removeObjectConfiguration(Port.class, TestBrokerConfiguration.ENTRY_NAME_RMI_PORT); - - Map anonymousProviderAttributes = new HashMap(); - anonymousProviderAttributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); - anonymousProviderAttributes.put(AuthenticationProvider.NAME, "testAnonymous"); - config.addObjectConfiguration(AuthenticationProvider.class, anonymousProviderAttributes); - - // set password authentication provider on http port for the tests - config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER, - TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); - config.setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); - config.setSaved(false); - restTestHelper.setUsernameAndPassword("webadmin", "webadmin"); - - startBroker(); - - setupConnection(); - - // Validate the queue depth is as expected - long messageCount = ((AMQSession) _session).getQueueDepth((AMQDestination) _destination); - assertEquals("Broker has invalid message count for test", 2, messageCount); - - // Ensure the alert has not occurred yet - assertLoggingNotYetOccured(MESSAGE_COUNT_ALERT); - - // Change max message count to 5, start broker and make sure that that's triggered at the right time - TestBrokerConfiguration brokerConfiguration = getBrokerConfiguration(); - setTestSystemProperty("queue.alertThresholdQueueDepthMessages","5"); - brokerConfiguration.setSaved(false); - - restTestHelper.submitRequest("queue/test/test/" + getTestQueueName(), "PUT", Collections.singletonMap(org.apache.qpid.server.model.Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, 5)); - // Trigger the new value - sendMessage(_session, _destination, 3); - _session.commit(); - - // Validate that the alert occurred. - wasAlertFired(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BindingLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BindingLoggingTest.java deleted file mode 100644 index 646c17d1f2..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BindingLoggingTest.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.logging; - -import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Queue; -import javax.jms.Session; -import javax.jms.Topic; -import java.io.IOException; -import java.util.List; - -/** - * Binding - * - * The Binding test suite validates that the follow log messages as specified in the Functional Specification. - * - * This suite of tests validate that the Binding messages occur correctly and according to the following format: - * - * BND-1001 : Create [: Arguments : ] - * BND-1002 : Deleted - */ -public class BindingLoggingTest extends AbstractTestLogging -{ - - static final String BND_PREFIX = "BND-"; - - private Connection _connection; - private Session _session; - private Queue _queue; - private Topic _topic; - - @Override - public void setUp() throws Exception - { - super.setUp(); - //Ignore broker startup messages - _monitor.markDiscardPoint(); - - _connection = getConnection(); - - _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - _queue = _session.createQueue(getName()); - _topic = (Topic) getInitialContext().lookup(TOPIC); - } - - private void validateLogMessage(String log, String messageID, String message, String exchange, String rkey, String queueName) - { - validateMessageID(messageID, log); - - String subject = fromSubject(log); - - assertEquals("Queue not correct.", queueName, - AbstractTestLogSubject.getSlice("qu", subject)); - assertEquals("Routing Key not correct.", rkey, - AbstractTestLogSubject.getSlice("rk", subject)); - assertEquals("Virtualhost not correct.", "/test", - AbstractTestLogSubject.getSlice("vh", subject)); - assertEquals("Exchange not correct.", exchange, - AbstractTestLogSubject.getSlice("ex", subject)); - - assertEquals("Log Message not as expected", message, getMessageString(fromMessage(log))); - } - - /** - * testBindingCreate - * - * Description: - * The binding of a Queue and an Exchange is done via a Binding. When this Binding is created a BND-1001 Create message will be logged. - * Input: - * - * 1. Running Broker - * 2. New Client requests that a Queue is bound to a new exchange. - * Output: - * - * BND-1001 : Create : Arguments : {x-filter-jms-selector=} - * - * Validation Steps: - * 3. The BND ID is correct - * 4. This will be the first message for the given binding - */ - public void testBindingCreate() throws JMSException, IOException - { - _session.createConsumer(_queue).close(); - - List results = waitAndFindMatches(BND_PREFIX); - - assertEquals("Result set larger than expected.", 1, results.size()); - - String messageID = "BND-1001"; - String queueName = _queue.getQueueName(); - String exchange = "direct/amq.direct"; - String message = "Create"; - validateLogMessage(getLogMessage(results, 0), messageID, message, exchange, queueName, queueName); - } - - /** - * Description: - * A Binding can be made with a set of arguments. When this occurs we logged the key,value pairs as part of the Binding log message. When the subscriber with a JMS Selector consumes from an exclusive queue such as a topic. The binding is made with the JMS Selector as an argument. - * Input: - * - * 1. Running Broker - * 2. Java Client consumes from a topic with a JMS selector. - * Output: - * - * BND-1001 : Create : Arguments : {x-filter-jms-selector=} - * - * Validation Steps: - * 3. The BND ID is correct - * 4. The JMS Selector argument is present in the message - * 5. This will be the first message for the given binding - */ - public void testBindingCreateWithArguments() throws JMSException, IOException - { - final String SELECTOR = "Selector='True'"; - - _session.createDurableSubscriber(_topic, getName(), SELECTOR, false).close(); - - List results = waitAndFindMatches(BND_PREFIX); - - assertEquals("Result set larger than expected.", 1, results.size()); - - String messageID = "BND-1001"; - - // Perform full testing on the binding - String message = getMessageString(fromMessage(getLogMessage(results, 0))); - - validateLogMessage(getLogMessage(results, 0), messageID, message, - "topic/amq.topic", "topic", "clientid:" + getName()); - - assertTrue("JMSSelector not identified in binding:"+message, message.contains("jms-selector")); - assertTrue("Selector not part of binding.:"+message, message.contains(SELECTOR)); - - } - - /** - * Description: - * Bindings can be deleted so that a queue can be rebound with a different set of values. - * Input: - * - * 1. Running Broker - * 2. AMQP UnBind Request is made - * Output: - * - * BND-1002 : Deleted - * - * Validation Steps: - * 3. The BND ID is correct - * 4. There must have been a BND-1001 Create message first. - * 5. This will be the last message for the given binding - */ - public void testBindingDelete() throws JMSException, IOException - { - //Closing a consumer on a temporary queue will cause it to autodelete - // and so unbind. - _session.createConsumer(_session.createTemporaryQueue()).close(); - - if(isBroker010()) - { - //auto-delete is at session close for 0-10 - _session.close(); - } - - //wait for the deletion messages to be logged - waitForMessage("BND-1002"); - - //gather all the BND messages - List results = waitAndFindMatches(BND_PREFIX); - - // We will have two binds as we bind all queues to the default exchange - assertEquals("Result not as expected." + results, 2, results.size()); - - - String messageID = "BND-1001"; - String message = "Create"; - - String log = getLogMessage(results, 0); - validateMessageID(messageID, log); - assertEquals("Log Message not as expected", message, getMessageString(fromMessage(log))); - - String DIRECT = "direct/amq.direct"; - - messageID = "BND-1002"; - message = "Deleted"; - - log = getLogMessage(results, 1); - validateMessageID(messageID, log); - - String subject = fromSubject(log); - - validateBindingDeleteArguments(subject, "/test"); - - assertEquals("Log Message not as expected", message, getMessageString(fromMessage(log))); - - } - - private void validateBindingDeleteArguments(String subject, String vhostName) - { - String routingKey = AbstractTestLogSubject.getSlice("rk", subject); - - assertTrue("Routing Key does not start with TempQueue:"+routingKey, - routingKey.startsWith("TempQueue")); - assertEquals("Virtualhost not correct.", vhostName, - AbstractTestLogSubject.getSlice("vh", subject)); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BrokerLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BrokerLoggingTest.java deleted file mode 100644 index 4952c4e10e..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/BrokerLoggingTest.java +++ /dev/null @@ -1,1035 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.server.logging; - -import junit.framework.AssertionFailedError; - -import org.apache.qpid.server.BrokerOptions; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.Transport; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.transport.ConnectionException; -import org.apache.qpid.util.LogMonitor; - -import java.io.IOException; -import java.net.Socket; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Broker Test Suite - * - * The Broker test suite validates that the follow log messages as specified in the Functional Specification. - * - * BRK-1001 : Startup : Version: Build: - * BRK-1002 : Starting : Listening on port - * BRK-1003 : Shutting down : port - * BRK-1004 : Ready - * BRK-1005 : Stopped - * BRK-1006 : Using configuration : - * BRK-1007 : Using logging configuration : - * - * These messages should only occur during startup. The tests need to verify the order of messages. In the case of the BRK-1002 and BRK-1003 the respective ports should only be available between the two log messages. - */ -public class BrokerLoggingTest extends AbstractTestLogging -{ - private static final String BROKER_MESSAGE_LOG_REG_EXP = ".*\\[\\w*\\] (BRK\\-\\d*) .*"; - private static final Pattern BROKER_MESSAGE_LOG_PATTERN = Pattern.compile(BROKER_MESSAGE_LOG_REG_EXP); - private static final String BRK_LOG_PREFIX = "BRK-"; - - public void setUp() throws Exception - { - setLogMessagePrefix(); - - // We either do this here or have a null check in tearDown. - // As when this test is run against profiles other than java it will NPE - _monitor = new LogMonitor(_outputFile); - //We explicitly do not call super.setUp as starting up the broker is - //part of the test case. - } - - /** - * Description: - * On startup the broker must report the active configuration file. The - * logging system must output this so that we can know what configuration - * is being used for this broker instance. - * - * Input: - * The value of -c specified on the command line. - * Output: - * MESSAGE BRK-1006 : Using configuration : - * Constraints: - * This MUST BE the first BRK log message. - * - * Validation Steps: - * 1. This is first BRK log message. - * 2. The BRK ID is correct - * 3. The config file is the full path to the file specified on - * the commandline. - * - * @throws Exception caused by broker startup - */ - public void testBrokerStartupConfiguration() throws Exception - { - String TESTID="BRK-1006"; - - if (isJavaBroker()) - { - startBroker(); - - // Now we can create the monitor as _outputFile will now be defined - _monitor = new LogMonitor(_outputFile); - - - String configFilePath = getConfigPath(); - - // Ensure we wait for TESTID to be logged - waitAndFindMatches(TESTID); - - List results = waitAndFindMatches(BRK_LOG_PREFIX); - try - { - // Validation - - assertTrue("BRKer message not logged", results.size() > 0); - - String log = getLogMessage(results, 0); - - //1 - validateMessageID(TESTID, log); - - //2 - results = findMatches(TESTID); - assertEquals("More than one configuration message found.", - 1, results.size()); - - //3 - assertTrue("Config file details not correctly logged, got " - + log + " but expected it to end with " + configFilePath, - log.endsWith(configFilePath)); - } - catch (AssertionFailedError afe) - { - dumpLogs(results, _monitor); - - throw afe; - } - } - } - - private String getConfigPath() - { - return getPathRelativeToWorkingDirectory(getTestConfigFile(DEFAULT_PORT)); - } - - /** - * Description: - * On startup the broker must report correctly report the log4j file in use. This is important as it can help diagnose why logging messages are not being reported. - * Input: - * No custom -l value should be provided on the command line so that the default value is correctly reported. - * Output: - * - * MESSAGE BRK-1007 : Using logging configuration : <$QPID_HOME>/etc/log4j.xml - * - * Validation Steps: - * - * 1. The BRK ID is correct - * 2. This occurs before the BRK-1001 startup message. - * 3. The log4j file is the full path to the file specified on the commandline. - * - * @throws Exception caused by broker startup - */ - public void testBrokerStartupDefaultLog4j() throws Exception - { - if (isJavaBroker() && isExternalBroker() && !isInternalBroker()) - { - String TESTID = "BRK-1007"; - - _brokerCommandHelper.removeBrokerCommandLog4JFile(); - - startBroker(); - - // Now we can create the monitor as _outputFile will now be defined - _monitor = new LogMonitor(_outputFile); - - // Ensure broker has fully started up. - getConnection(); - - // Ensure we wait for TESTID to be logged - waitAndFindMatches(TESTID); - - List results = waitAndFindMatches(BRK_LOG_PREFIX); - try - { - // Validation - - assertTrue("BRKer message not logged", results.size() > 0); - - boolean validation = false; - for (String rawLog : results) - { - // We don't care about messages after we have our log config - if (validation) - { - break; - } - - String log = getLog(rawLog); - - // Ensure we do not have a BRK-1001 message before - if (!getMessageID(log).equals(TESTID)) - { - assertFalse(getMessageID(log).equals("BRK-1001")); - continue; - } - - //1 - validateMessageID(TESTID, log); - - //2 - //There will be 1 copy of this startup message (via SystemOut) - assertEquals("Unexpected log4j configuration message count.", - 1, findMatches(TESTID).size()); - - //3 - String defaultLog4j = System.getProperty(QPID_HOME) + "/" + BrokerOptions.DEFAULT_LOG_CONFIG_FILE; - assertTrue("Log4j file(" + defaultLog4j + ") details not correctly logged:" + getMessageString(log), - getMessageString(log).endsWith(defaultLog4j)); - - validation = true; - } - - assertTrue("Validation not performed: " + TESTID + " not logged", validation); - } - catch (AssertionFailedError afe) - { - dumpLogs(results, _monitor); - - throw afe; - } - } - } - - /** - * Description: - * On startup the broker must report correctly report the log4j file in use. This is important as it can help diagnose why logging messages are not being reported. The broker must also be capable of correctly recognising the command line property to specify the custom logging configuration. - * Input: - * The value of -l specified on the command line. - * Output: - * - * MESSAGE BRK-1007 : Using logging configuration : - * - * Validation Steps: - * - * 1. The BRK ID is correct - * 2. This should occur before the BRK-1001 : Startup message - * 3. The log4j file is the full path to the file specified on the commandline. - * - * @throws Exception caused by broker startup - */ - public void testBrokerStartupCustomLog4j() throws Exception - { - // This logging startup code only occurs when you run a Java broker - if (isJavaBroker()) - { - String customLog4j = getBrokerCommandLog4JFile().getAbsolutePath(); - - String TESTID = "BRK-1007"; - - startBroker(); - - // Now we can create the monitor as _outputFile will now be defined - _monitor = new LogMonitor(_outputFile); - - - // Ensure broker has fully started up. - getConnection(); - - // Ensure we wait for TESTID to be logged - waitAndFindMatches(TESTID); - - List results = waitAndFindMatches(BRK_LOG_PREFIX); - try - { - // Validation - - assertTrue("BRKer message not logged", results.size() > 0); - - boolean validation = false; - for (String rawLog : results) - { - // We don't care about messages after we have our log config - if (validation) - { - break; - } - String log = getLog(rawLog); - - // Ensure we do not have a BRK-1001 message before - if (!getMessageID(log).equals(TESTID)) - { - assertFalse(getMessageID(log).equals("BRK-1001")); - continue; - } - - //1 - validateMessageID(TESTID, log); - - //2 - //There will be 1 copy of this startup message (via SystemOut) - assertEquals("Unexpected log4j configuration message count.", - 1, findMatches(TESTID).size()); - - //3 - String messageString = getMessageString(log); - assertTrue("Log4j file details not correctly logged. Message '" - + messageString + "' should contain '" +customLog4j + "'", - messageString.endsWith(customLog4j)); - - validation = true; - } - - assertTrue("Validation not performed: " + TESTID + " not logged", validation); - } - catch (AssertionFailedError afe) - { - dumpLogs(results, _monitor); - - throw afe; - } - } - } - - /** - * Description: On startup the broker reports the broker version number and svn build revision. This information is retrieved from the resource 'qpidversion.properties' which is located via the classloader. - * Input: The 'qpidversion.properties' file located on the classpath. - * Output: - * - * MESSAGE BRK-1001 : Startup : qpid Version: 0.6 Build: 767150 - * - * Validation Steps: - * - * 1. The BRK ID is correct - * 2. This occurs before any BRK-1002 listening messages are reported. - * - * @throws Exception caused by broker startup - */ - public void testBrokerStartupStartup() throws Exception - { - // This logging startup code only occurs when you run a Java broker, - // that broker must be started via Main so not an InVM broker. - if (isJavaBroker()) - { - String TESTID = "BRK-1001"; - - startBroker(); - - // Now we can create the monitor as _outputFile will now be defined - _monitor = new LogMonitor(_outputFile); - - // Ensure we wait for TESTID to be logged - waitAndFindMatches(TESTID); - - // Retrieve all BRK- log messages so we can check for an erroneous - // BRK-1002 message. - List results = findMatches(BRK_LOG_PREFIX); - - try - { - // Validation - - assertTrue("BRKer message not logged", results.size() > 0); - - boolean validation = false; - for (String rawLog : results) - { - if (validation) - { - //Stop checking once we have got to our startup test - break; - } - String log = getLog(rawLog); - - // Ensure we do not have a BRK-1002 message - if (!getMessageID(log).equals(TESTID)) - { - assertFalse(getMessageID(log).equals("BRK-1002")); - continue; - } - - //1 - validateMessageID(TESTID, log); - - //2 - //There will be 2 copies of the startup message (one via SystemOut, and one via Log4J) - assertEquals("Unexpected startup message count", - 2, findMatches(TESTID).size()); - - validation = true; - } - - assertTrue("Validation not performed: " + TESTID + " not logged", validation); - } - catch (AssertionFailedError afe) - { - dumpLogs(results, _monitor); - - throw afe; - } - } - } - - /** - * Description: - * On startup the broker may listen on a number of ports and protocols. Each of these must be reported as they are made available. - * Input: - * The default configuration with no SSL - * Output: - * - * MESSAGE BRK-1002 : Starting : Listening on TCP port 5672 - * - * Constraints: - * Additional broker configuration will occur between the Startup(BRK-1001) and Starting(BRK-1002) messages depending on what VirtualHosts are configured. - * Validation Steps: - * - * 1. The BRK ID is correct - * 2. This occurs after the BRK-1001 startup message - * 3. Using the default configuration a single BRK-1002 will be printed showing values TCP / 5672 - * - * @throws Exception caused by broker startup - */ - public void testBrokerStartupListeningTCPDefault() throws Exception - { - if (isJavaBroker()) - { - String TESTID = "BRK-1002"; - - startBroker(); - - // Now we can create the monitor as _outputFile will now be defined - _monitor = new LogMonitor(_outputFile); - - // Ensure broker has fully started up. - getConnection(); - - // Ensure we wait for TESTID to be logged - waitAndFindMatches(TESTID); - - // Retrieve all BRK- log messages so we can check for an erroneous - // BRK-1002 message. - List results = findMatches(BRK_LOG_PREFIX); - try - { - // Validation - - assertTrue("BRKer message not logged", results.size() > 0); - - boolean validation = false; - boolean foundBRK1001 = false; - for (String rawLog : results) - { - String log = getLog(rawLog); - - // using custom method to get id as getMessageId() fails to correctly identify id - // because of using brackets for protocols - String id = getBrokerLogId(log); - // Ensure we do not have a BRK-1002 message - if (!id.equals(TESTID)) - { - if (id.equals("BRK-1001")) - { - foundBRK1001 = true; - } - continue; - } - - assertTrue("BRK-1001 not logged before this message", foundBRK1001); - - //1 - assertEquals("Incorrect message", TESTID, id); - - //2 - //There will be 2 copies of the startup message (one via SystemOut, and one via Log4J) - assertEquals("Unexpected listen message count", - 2, findMatches(TESTID).size()); - - //3 - String message = getMessageString(log); - assertTrue("Expected Listen log not correct" + message, - message.endsWith("Listening on TCP port " + getPort())); - - validation = true; - } - - assertTrue("Validation not performed: " + TESTID + " not logged", validation); - } - catch (AssertionFailedError afe) - { - dumpLogs(results, _monitor); - - throw afe; - } - } - } - - private String getBrokerLogId(String log) - { - Matcher m = BROKER_MESSAGE_LOG_PATTERN.matcher(log); - if (m.matches()) - { - return m.group(1); - } - return getMessageID(log); - } - - /** - * Description: - * On startup the broker may listen on a number of ports and protocols. Each of these must be reported as they are made available. - * Input: - * The default configuration with SSL enabled - * Output: - * - * MESSAGE BRK-1002 : Starting : Listening on TCP port 5672 - * MESSAGE BRK-1002 : Starting : Listening on TCP/SSL port 8672 - * - * Constraints: - * Additional broker configuration will occur between the Startup(BRK-1001) and Starting(BRK-1002) messages depending on what VirtualHosts are configured. - * Validation Steps: - * - * 1. The BRK ID is correct - * 2. This occurs after the BRK-1001 startup message - * 3. With SSL enabled in the configuration two BRK-1002 will be printed (order is not specified) - * 1. One showing values [TCP] 5672 - * 2. One showing values [SSL] 5671 - * - * @throws Exception caused by broker startup - */ - public void testBrokerStartupListeningTCPSSL() throws Exception - { - if (isJavaBroker()) - { - String TESTID = "BRK-1002"; - - // Enable SSL on the connection - Map sslPortAttributes = new HashMap(); - sslPortAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); - sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT); - sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT); - sslPortAttributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); - sslPortAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); - getBrokerConfiguration().addObjectConfiguration(Port.class, sslPortAttributes); - - startBroker(); - - // Now we can create the monitor as _outputFile will now be defined - _monitor = new LogMonitor(_outputFile); - - // Ensure broker has fully started up. - getConnection(); - - // Ensure we wait for TESTID to be logged - waitAndFindMatches(TESTID); - - // Retrieve all BRK- log messages so we can check for an erroneous - // BRK-1002 message. - List results = findMatches(BRK_LOG_PREFIX); - try - { - // Validation - - assertTrue("BRKer message not logged", results.size() > 0); - - boolean validation = false; - boolean foundBRK1001 = false; - for (String rawLog : results) - { - String log = getLog(rawLog); - - String id = getBrokerLogId(log); - // Ensure we do not have a BRK-1002 message - if (!id.equals(TESTID)) - { - if (id.equals("BRK-1001")) - { - foundBRK1001 = true; - } - continue; - } - - assertTrue("BRK-1001 not logged before this message", foundBRK1001); - - //1 - assertEquals("Incorrect message", TESTID, id); - - //2 - //There will be 4 copies of the startup message (two via SystemOut, and two via Log4J) - List listenMessages = findMatches(TESTID); - assertEquals("Four listen messages should be found.", - 4, listenMessages .size()); - - int tcpStarted = 0; - int sslStarted = 0; - - for (String message : listenMessages) - { - if (message.endsWith("Listening on TCP port " + getPort())) - { - tcpStarted++; - } - if (message.endsWith("Listening on SSL port " + DEFAULT_SSL_PORT)) - { - sslStarted++; - } - } - - assertEquals("Unexpected number of logs 'Listening on TCP port'", 2, tcpStarted); - assertEquals("Unexpected number of logs 'Listening on SSL port'", 2, sslStarted); - - //4 Test ports open - testSocketOpen(getPort()); - testSocketOpen(DEFAULT_SSL_PORT); - - validation = true; - } - - assertTrue("Validation not performed: " + TESTID + " not logged", validation); - } - catch (AssertionFailedError afe) - { - dumpLogs(results, _monitor); - - throw afe; - } - } - } - - /** - * Description: - * The final message the broker will print when it has performed all initialisation and listener startups will be to log the BRK-1004 Ready message - * Input: - * No input, all successful broker startups will show BRK-1004 messages. - * Output: - * - * 2009-07-09 15:50:20 +0100 MESSAGE BRK-1004 : Qpid Broker Ready - * - * Validation Steps: - * - * 1. The BRK ID is correct - * 2. This occurs after the BRK-1001 startup message - * 3. This must be the last message the broker prints after startup. Currently, if there is no further interaction with the broker then there should be no more logging. - * - * @throws Exception caused by broker startup - */ - public void testBrokerStartupReady() throws Exception - { - if (isJavaBroker()) - { - String TESTID = "BRK-1004"; - - startBroker(); - - //Ensure the broker has fully started up. - getConnection(); - // Ensure we wait for TESTID to be logged - waitAndFindMatches(TESTID); - - // Retrieve all BRK- log messages so we can check for an erroneous - // BRK-1001 message. - List results = findMatches(BRK_LOG_PREFIX); - try - { - // Validation - - assertTrue("BRKer message not logged", results.size() > 0); - - boolean validationComplete = false; - boolean foundBRK1001 = false; - - for (int i=0; i < results.size(); i++) - { - String rawLog = results.get(i); - String log = getLog(rawLog); - - // Ensure we do not have a BRK-1001 message - if (!getMessageID(log).equals(TESTID)) - { - if (getMessageID(log).equals("BRK-1001")) - { - foundBRK1001 = true; - } - continue; - } - - assertTrue("BRK-1001 not logged before this message", foundBRK1001); - - //1 - validateMessageID(TESTID, log); - - //2 - assertEquals("Ready message not present", "Qpid Broker Ready", getMessageString(log)); - - //There will be 2 copies of the startup message (one via SystemOut, and one via Log4J) - assertEquals("Unexpected ready message count", - 2, findMatches(TESTID).size()); - assertEquals("The ready messages should have been the last 2 messages", results.size() - 2, i); - - validationComplete = true; - break; - } - - assertTrue("Validation not performed: " + TESTID + " not logged", validationComplete); - } - catch (AssertionFailedError afe) - { - dumpLogs(results, _monitor); - - throw afe; - } - } - } - - /** - * Description: - * On startup the broker may listen on a number of ports and protocols. Each of these must then report a shutting down message as they stop listening. - * Input: - * The default configuration with no SSL - * Output: - * - * MESSAGE BRK-1003 : Shutting down : TCP port 5672 - * - * Validation Steps: - * - * 1. The BRK ID is correct - * 2. Only TCP is reported with the default configuration with no SSL. - * 3. The default port is correct - * 4. The port is not accessible after this message - * - * @throws Exception caused by broker startup - */ - public void testBrokerShutdownListeningTCPDefault() throws Exception - { - if (isJavaBroker() && isInternalBroker()) - { - String TESTID = "BRK-1003"; - - startBroker(); - - // Now we can create the monitor as _outputFile will now be defined - _monitor = new LogMonitor(_outputFile); - - stopBroker(); - - //Give broker time to shutdown and flush log - checkSocketClosed(getPort()); - - List results = waitAndFindMatches(BRK_LOG_PREFIX); - try - { - // Validation - - assertTrue("BRKer message not logged", results.size() > 0); - - boolean validation = false; - boolean foundBRK1001 = false; - for (String rawLog : results) - { - String log = getLog(rawLog); - - // Ensure we do not have a BRK-1002 message - if (!getMessageID(log).equals(TESTID)) - { - if (getMessageID(log).equals("BRK-1001")) - { - foundBRK1001 = true; - } - continue; - } - - assertTrue("BRK-1001 not logged before this message", foundBRK1001); - - //1 - validateMessageID(TESTID, log); - - //2 - assertEquals("More than one listen message found.", - 1, findMatches(TESTID).size()); - - //3 - String message = getMessageString(log); - assertTrue("Expected shutdown log not correct" + message, - message.endsWith("TCP port " + getPort())); - - //4 - checkSocketClosed(getPort()); - - validation = true; - } - - assertTrue("Validation not performed: " + TESTID + " not logged", validation); - } - catch (AssertionFailedError afe) - { - dumpLogs(results, _monitor); - - throw afe; - } - } - } - - /** - * Description: - * On startup the broker may listen on a number of ports and protocols. Each of these must be reported as they are made available. - * Input: - * The default configuration with SSL enabled - * Output: - * - * MESSAGE BRK-1002 : Starting : Listening on TCP port 5672 - * MESSAGE BRK-1002 : Starting : Listening on TCP/SSL port 8672 - * - * Constraints: - * Additional broker configuration will occur between the Startup(BRK-1001) and Starting(BRK-1002) messages depending on what VirtualHosts are configured. - * Validation Steps: - * - * 1. The BRK ID is correct - * 2. This occurs after the BRK-1001 startup message - * 3. With SSL enabled in the configuration two BRK-1002 will be printed (order is not specified) - * 1. One showing values TCP / 5672 - * 2. One showing values TCP/SSL / 5672 - * - * @throws Exception caused by broker startup - */ - public void testBrokerShutdownListeningTCPSSL() throws Exception - { - if (isJavaBroker() && isInternalBroker()) - { - String TESTID = "BRK-1003"; - - // Enable SSL on the connection - Map sslPortAttributes = new HashMap(); - sslPortAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); - sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT); - sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT); - sslPortAttributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); - sslPortAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); - getBrokerConfiguration().addObjectConfiguration(Port.class, sslPortAttributes); - - startBroker(); - - // Now we can create the monitor as _outputFile will now be defined - _monitor = new LogMonitor(_outputFile); - - -// //Clear any startup messages as we don't need them for validation -// _monitor.reset(); - //Stop the broker to get the log messages for testing - stopBroker(); - - //Give broker time to shutdown and flush log - checkSocketClosed(getPort()); - - List results = waitAndFindMatches(TESTID); - try - { - // Validation - - assertTrue(TESTID + " messages not logged", results.size() > 0); - - String log = getLog(results.get(0)); - - //1 - validateMessageID(TESTID, log); - - //2 - List listenMessages = findMatches(TESTID); - assertEquals("Two shutdown messages should be found.", - 2, listenMessages.size()); - - int tcpShuttingDown = 0; - int sslShuttingDown = 0; - - for (String m : listenMessages) - { - if (m.endsWith("Shutting down : TCP port " + getPort())) - { - tcpShuttingDown++; - } - if (m.endsWith("Shutting down : SSL port " + DEFAULT_SSL_PORT)) - { - sslShuttingDown++; - } - } - - assertEquals("Unexpected number of logs 'Shutting down : TCP port'", 1, tcpShuttingDown); - assertEquals("Unexpected number of logs 'Shutting down : SSL port'", 1, sslShuttingDown); - - //4 - //Test Port closed - checkSocketClosed(getPort()); - //Test SSL Port closed - checkSocketClosed(DEFAULT_SSL_PORT); - } - catch (AssertionFailedError afe) - { - dumpLogs(results, _monitor); - - throw afe; - } - } - } - - /** - * Description: - * Input: - * No input, all clean broker shutdowns will show BRK-1005 messages. - * Output: - * - * MESSAGE BRK-1005 : Stopped - * - * Constraints: - * This is the LAST message the broker will log. - * Validation Steps: - * - * 1. The BRK ID is correct - * 2. This is the last message the broker will log. - * - * @throws Exception caused by broker startup - */ - public void testBrokerShutdownStopped() throws Exception - { - if (isJavaBroker() && isInternalBroker()) - { - String TESTID = "BRK-1005"; - - startBroker(); - - // Now we can create the monitor as _outputFile will now be defined - _monitor = new LogMonitor(_outputFile); - - getConnection().close(); - - stopBroker(); - - // Ensure the broker has shutdown before retreving results - checkSocketClosed(getPort()); - - waitAndFindMatches(TESTID); - - List results = waitAndFindMatches(BRK_LOG_PREFIX); - try - { - // Validation - - assertTrue("BRKer message not logged", results.size() > 0); - - boolean validation = false; - for (String rawLog : results) - { - assertFalse("More broker log statements present after ready message", validation); - String log = getLog(rawLog); - - // Ignore all logs until we get to the test id. - if (!getMessageID(log).equals(TESTID)) - { - continue; - } - - //1 - validateMessageID(TESTID, log); - - //2 - assertEquals("More than one ready message found.", - 1, findMatches(TESTID).size()); - - //3 - assertEquals("Stopped message not present", "Stopped", getMessageString(log)); - - validation = true; - } - - assertTrue("Validation not performed: " + TESTID + " not logged", validation); - } - catch (AssertionFailedError afe) - { - dumpLogs(results, _monitor); - - throw afe; - } - } - } - - /** - * Test that a socket on the given port is closed. - * - * Does this by attempting to connect to the port and expecting a - * ConnectionRefused IOException or a ConnectionException - * - * @param port the port number - */ - private void checkSocketClosed(int port) - { - try - { - Socket socket = new Socket((String) null, port); - fail("Socket not closed on port:" + port); - } - catch (ConnectionException e) - { - //normal path - } - catch (IOException e) - { - if (!e.getMessage().startsWith("Connection refused")) - { - fail("Socket not closed on port:" + port + ":" + e.getMessage()); - // Keep stack trace for diagnosis. - e.printStackTrace(System.err); - } - } - } - - /** - * Test that a socket on the given port is open. - * - * Does this by attempting to connect to the port and expecting a - * The connection to succeed. - * It then closes the socket and expects that to work cleanly. - * - * @param port the port number - */ - private void testSocketOpen(int port) - { - try - { - Socket socket = new Socket((String) null, port); - socket.close(); - } - catch (IOException e) - { - fail("Unable to open and close socket to port:" + port - + ". Due to:" + e.getMessage()); - } - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ChannelLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ChannelLoggingTest.java deleted file mode 100644 index 047151684f..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ChannelLoggingTest.java +++ /dev/null @@ -1,417 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.logging; - -import org.apache.qpid.AMQChannelClosedException; -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQSession; - -import javax.jms.Connection; -import javax.jms.MessageConsumer; -import javax.jms.Queue; -import javax.jms.Session; -import java.util.List; -import java.util.regex.Pattern; - -public class ChannelLoggingTest extends AbstractTestLogging -{ - private static final String CHANNEL_CLOSE_FORCED_MESSAGE_PATTERN = "CHN-1003 : Close : \\d* - .*"; - private static final String CHANNEL_PREFIX = "CHN-"; - - // No explicit startup configuration is required for this test - // so no setUp() method - - /** - * Description: - * When a new Channel (JMS Session) is created this will be logged as a CHN-1001 Create message. The messages will contain the prefetch details about this new Channel. - * Input: - * - * 1. Running Broker - * 2. New JMS Session/Channel creation - * - * Output: - * CHN-1001 : Create - * CHN-1004 : Prefetch Size (bytes) {0,number} : Count {1,number} - * - * Validation Steps: - * 1. The CHN ID is correct - * 2. The prefetch value matches that defined by the requesting client. - * - * @throws Exception - if an error occurs - */ - public void testChannelCreate() throws Exception - { - assertLoggingNotYetOccured(CHANNEL_PREFIX); - - Connection connection = getConnection(); - - int PREFETCH = 12; - - // Test that calling session.close gives us the expected output - ((AMQConnection)connection).createSession(false, Session.AUTO_ACKNOWLEDGE,PREFETCH); - - // Wait to ensure that the CHN-1001 message is logged - waitForMessage("CHN-1001"); - - List results = findMatches("CHN-1001"); - - // Validation - assertEquals("CHN-1001 messages not logged", 1, results.size()); - - String log = getLogMessage(results, 0); - // MESSAGE [con:0(guest@anonymous(3273383)/test)/ch:1] CHN-1001 : Create - validateMessageID("CHN-1001", log); - final String fromActor = fromActor(log); - final int channelID = getChannelID(fromActor); - assertEquals("Incorrect Channel in actor:"+fromActor(log), isBroker010()? 0 : 1, channelID); - - if (!isBroker010()) - { - // Wait to ensure that the CHN-1004 message is logged - waitForMessage("CHN-1004"); - - results = findMatches("CHN-1004"); - - // Validation - assertEquals("CHN-1004 messages not logged", 1, results.size()); - log = getLogMessage(results, 0); - // MESSAGE [con:0(guest@anonymous(3273383)/test)/ch:1] CHN-1004 : Prefetch Size (bytes) {0,number} : Count {1,number} - validateMessageID("CHN-1004", log); - assertEquals("Incorrect Channel in actor:"+fromActor(log), 1, getChannelID(fromActor(log))); - assertTrue("Prefetch Count not correct",getMessageString(fromMessage(log)).endsWith("Count "+PREFETCH)); - } - - connection.close(); - } - - /** - * Description: - * The Java Broker implements consumer flow control for all ack modes except - * No-Ack. When a client connects the session's flow is initially set to - * Stopped. Verify this message appears - * - * Input: - * 1. Running broker - * 2. Create consumer - * Output: - * - * CHN-1002 : Flow Stopped - * - * Validation Steps: - * 4. The CHN ID is correct - * - * @throws Exception - if an error occurs - */ - - public void testChannelStartsFlowStopped() throws Exception - { - assertLoggingNotYetOccured(CHANNEL_PREFIX); - - Connection connection = getConnection(); - - // Create a session to fill up - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - Queue queue = (Queue) getInitialContext().lookup(QUEUE); - MessageConsumer consumer = session.createConsumer(queue); - - connection.start(); - - // Wait to ensure that the CHN-1002 message is logged - waitForMessage("CHN-1002"); - - List results = findMatches(CHANNEL_PREFIX); - - assertTrue("No CHN messages logged", results.size() > 0); - - // The last channel message should be: - // - // INFO - MESSAGE [con:0(guest@anonymous(4205299)/test)/ch:1] [con:0(guest@anonymous(4205299)/test)/ch:1] CHN-1002 : Flow Stopped - - // Verify the last channel message is stopped - validateChannelStart(results, false); - } - - private void validateChannelStart(List results, boolean flowStarted) - { - String log = getLogMessageFromEnd(results, 0); - - String flow = flowStarted ? "Started" : "Stopped"; - validateMessageID("CHN-1002", log); - assertEquals("Message should be Flow " + flow, "Flow " + flow, getMessageString(fromMessage(log))); - } - - /** - * Description: - * The Java Broker implements consumer flow control for all ack modes except - * No-Ack. When the client first attempts to receive a message then the Flow - * status of the Session is set to Started. - * - * Input: - * 1. Running broker - * 2. Create a consumer - * 3. Attempt to receive a message - * Output: - * - * CHN-1002 : Flow Started - * - * Validation Steps: - * 4. The CHN ID is correct - * - * @throws Exception - if an error occurs - */ - - public void testChannelStartConsumerFlowStarted() throws Exception - { - assertLoggingNotYetOccured(CHANNEL_PREFIX); - - Connection connection = getConnection(); - - // Create a session to fill up - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - Queue queue = (Queue) getInitialContext().lookup(QUEUE); - MessageConsumer consumer = session.createConsumer(queue); - - connection.start(); - - //Call receive to send the Flow On message - consumer.receiveNoWait(); - - //Wait for up to 2 seconds for message to appear - // ignore response as we will use the findMatches afterwards just - // incase it did take more than 2 seconds to log. - _monitor.waitForMessage(CHANNEL_PREFIX, 2000); - - // Wait to ensure that the CHN-1002 message is logged - waitForMessage("CHN-1002"); - - List results = findMatches(CHANNEL_PREFIX); - - assertTrue("No CHN messages logged", results.size() > 0); - - // The last two channel messages(before the close) should be: - // - // INFO [qpid.message] MESSAGE [con:1(guest@/127.0.0.1:49869/test)/ch:1] [con:1(guest@/127.0.0.1:49869/test)/ch:1] CHN-1002 : Flow Stopped - // INFO [qpid.message] MESSAGE [con:1(guest@/127.0.0.1:49869/test)/ch:1] [con:1(guest@/127.0.0.1:49869/test)/ch:1] CHN-1002 : Flow Started - - // Verify the last channel msg is Started. - validateChannelStart(results, true); - } - - /** - * Description: - * When the client gracefully closes the Connection then a CHN-1003 Close - * message will be issued. This must be the last message logged for this - * Channel. - * Input: - * 1. Running Broker - * 2. Connected Client - * 3. Client then requests that the Connection is closed - * Output: - * - * CHN-1003 : Close - * - * Validation Steps: - * 4. The MST ID is correct - * 5. This must be the last message logged for this Channel. - * - * @throws Exception - if an error occurs - */ - public void testChannelCloseViaConnectionClose() throws Exception - { - assertLoggingNotYetOccured(CHANNEL_PREFIX); - - Connection connection = getConnection(); - - // Create a session - connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - // Close the connection to verify the created session closing is logged. - connection.close(); - - // Wait to ensure that the CHN-1003 message is logged - waitForMessage("CHN-1003"); - - List results = findMatches(CHANNEL_PREFIX); - - assertTrue("No CHN messages logged", results.size() > 0); - - // The last two channel messages should be: - // - // INFO - MESSAGE [con:0(guest@anonymous(4205299)/test)/ch:1] [con:0(guest@anonymous(4205299)/test)/ch:1] CHN-1002 : Flow On - - // Verify - validateChannelClose(results); - } - - /** - * Description: - * When the client gracefully closes the Connection then a CHN-1003 Close - * message will be issued. This must be the last message logged for this - * Channel. - * Input: - * 1. Running Broker - * 2. Connected Client - * 3. Client then requests that the Channel is closed - * Output: - * - * CHN-1003 : Close - * - * Validation Steps: - * 4. The MST ID is correct - * 5. This must be the last message logged for this Channel. - * - * @throws Exception - if an error occurs - */ - public void testChannelCloseViaChannelClose() throws Exception - { - assertLoggingNotYetOccured(CHANNEL_PREFIX); - - Connection connection = getConnection(); - - // Create a session and then close it - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - waitForMessage("CHN-1001"); - - // Wait to ensure that the CHN-1003 message is logged - session.close(); - waitForMessage("CHN-1003"); - - List results = findMatches(CHANNEL_PREFIX); - - assertTrue("No CHN messages logged", results.size() > 0); - - // Verify - validateChannelClose(results); - } - - public void testChannelClosedOnQueueArgumentsMismatch() throws Exception - { - assertLoggingNotYetOccured(CHANNEL_PREFIX); - - Connection connection = getConnection(); - - // Create a session and then close it - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - waitForMessage("CHN-1001"); - - String testQueueName = getTestQueueName(); - - Queue nonDurableQueue = (Queue) session.createQueue("direct://amq.direct/" + testQueueName + "/" + testQueueName - + "?durable='false'"); - - ((AMQSession)session).declareAndBind((AMQDestination)nonDurableQueue); - - Queue durableQueue = (Queue) session.createQueue("direct://amq.direct/" + testQueueName + "/" + testQueueName - + "?durable='true'"); - try - { - ((AMQSession)session).declareAndBind((AMQDestination) durableQueue); - fail("Exception not thrown"); - } - catch (AMQChannelClosedException acce) - { - // pass - } - catch (Exception e) - { - fail("Wrong exception thrown " + e); - } - waitForMessage("CHN-1003"); - - List results = findMatches(CHANNEL_PREFIX); - assertTrue("No CHN messages logged", results.size() > 0); - - String closeLog = results.get(results.size() -1); - int closeMessageID = closeLog.indexOf("CHN-1003"); - assertFalse("CHN-1003 is not found", closeMessageID == -1); - - String closeMessage = closeLog.substring(closeMessageID); - assertTrue("Unexpected close channel message :" + closeMessage, Pattern.matches(CHANNEL_CLOSE_FORCED_MESSAGE_PATTERN, closeMessage)); - - session.close(); - connection.close(); - } - - public void testChannelClosedOnExclusiveQueueDeclaredOnDifferentSession() throws Exception - { - assertLoggingNotYetOccured(CHANNEL_PREFIX); - - Connection connection = getConnection(); - - // Create a session and then close it - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - waitForMessage("CHN-1001"); - - Session session2 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - waitForMessage("CHN-1001"); - - String testQueueName = getTestQueueName(); - - Queue queue = (Queue) session.createQueue("direct://amq.direct/" + testQueueName + "/" + testQueueName - + "?exclusive='true'"); - - ((AMQSession)session).declareAndBind((AMQDestination)queue); - - try - { - ((AMQSession)session2).declareAndBind((AMQDestination) queue); - fail("Exception not thrown"); - } - catch (AMQException acce) - { - // pass - } - catch (Exception e) - { - fail("Wrong exception thrown " + e); - } - waitForMessage("CHN-1003"); - - List results = findMatches(CHANNEL_PREFIX); - assertTrue("No CHN messages logged", results.size() > 0); - - String closeLog = results.get(results.size() -1); - int closeMessageID = closeLog.indexOf("CHN-1003"); - assertFalse("CHN-1003 is not found", closeMessageID == -1); - - String closeMessage = closeLog.substring(closeMessageID); - assertTrue("Unexpected close channel message :" + closeMessage, Pattern.matches(CHANNEL_CLOSE_FORCED_MESSAGE_PATTERN, closeMessage)); - - session.close(); - connection.close(); - } - private void validateChannelClose(List results) - { - String open = getLogMessage(results, 0); - String close = getLogMessageFromEnd(results, 0); - - validateMessageID("CHN-1001", open); - validateMessageID("CHN-1003", close); - assertEquals("Message should be Close", "Close", getMessageString(fromMessage(close))); - assertEquals("Incorrect Channel ID closed", isBroker010()? 0 : 1, getChannelID(fromSubject(close))); - assertEquals("Channel IDs should be the same", getChannelID(fromActor(open)), getChannelID(fromSubject(close))); - assertEquals("Connection IDs should be the same", getConnectionID(fromActor(open)), getConnectionID(fromSubject(close))); - } -} \ No newline at end of file diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ConnectionLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ConnectionLoggingTest.java deleted file mode 100644 index 0be1f69948..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ConnectionLoggingTest.java +++ /dev/null @@ -1,198 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.server.logging; - -import javax.jms.Connection; - -import org.apache.qpid.common.QpidProperties; - -import java.util.HashMap; -import java.util.List; -import java.util.TreeSet; - -public class ConnectionLoggingTest extends AbstractTestLogging -{ - private static final String CONNECTION_PREFIX = "CON-"; - - // No explicit startup configuration is required for this test - // so no setUp() method - - /** - * Description: - * When a new connection is made to the broker this must be logged. - * - * Input: - * 1. Running Broker - * 2. Connecting client - * Output: - * CON-1001 : Open : Client ID {0}[ : Protocol Version : {1}] - * - * Validation Steps: - * 1. The CON ID is correct - * 2. This is the first CON message for that Connection - * - * @throws Exception - if an error occurs - */ - public void testConnectionOpen() throws Exception - { - assertLoggingNotYetOccured(CONNECTION_PREFIX); - - Connection connection = getConnection(); - String clientid = connection.getClientID(); - - // Wait until opened - waitForMessage("CON-1001"); - - // Close the connection - connection.close(); - - // Wait to ensure that the desired message is logged - waitForMessage("CON-1002"); - - List results = waitAndFindMatches("CON-1001"); - - // MESSAGE [con:1(/127.0.0.1:46927)] CON-1001 : Open - // MESSAGE [con:1(/127.0.0.1:46927)] CON-1001 : Open : Protocol Version : 0-9 - // MESSAGE [con:1(/127.0.0.1:46927)] CON-1001 : Open : Client ID : clientid : Protocol Version : 0-9 : Client Version : 1.2.3_4 - // MESSAGE [con:0(/127.0.0.1:46927)] CON-1002 : Close - - HashMap> connectionData = splitResultsOnConnectionID(results); - - // Get the last Integer from keySet of the ConnectionData - int connectionID = new TreeSet(connectionData.keySet()).last(); - - //Use just the data from the last connection for the test - results = connectionData.get(connectionID); - - assertEquals("Unexpected CON-1001 messages count", 3, results.size()); - - String log = getLogMessage(results, 0); - // MESSAGE [con:1(/127.0.0.1:52540)] CON-1001 : Open - //1 & 2 - validateMessageID("CON-1001",log); - - // validate the last three CON-1001 messages. - // MESSAGE [con:1(/127.0.0.1:52540)] CON-1001 : Open : Client ID : clientid : Protocol Version : 0-9 : Client Version : 1.2.3_4 : Client Product : product - validateConnectionOpen(results, 0, true, true, clientid, true, QpidProperties.getReleaseVersion(), true, QpidProperties.getProductName()); - - // MESSAGE [con:1(/127.0.0.1:52540)] CON-1001 : Open : Protocol Version : 0-9 - validateConnectionOpen(results, 1, true, false, null, false, null, false, null); - - // MESSAGE [con:1(/127.0.0.1:52540)] CON-1001 : Open - validateConnectionOpen(results, 2, false, false, null, false, null, false, null); - } - - private void validateConnectionOpen(List results, int positionFromEnd, - boolean protocolVersionPresent, boolean clientIdOptionPresent, String clientIdValue, - boolean clientVersionPresent, String clientVersionValue, boolean clientProductPresent, String clientProductValue) - { - String log = getLogMessageFromEnd(results, positionFromEnd); - - validateMessageID("CON-1001",log); - - assertEquals("unexpected Client ID option state", clientIdOptionPresent, fromMessage(log).contains("Client ID :")); - - if(clientIdOptionPresent && clientIdValue != null) - { - assertTrue("Client ID value is not present: " + clientIdValue, fromMessage(log).contains(clientIdValue)); - } - - assertEquals("unexpected Protocol Version option state", - protocolVersionPresent, fromMessage(log).contains("Protocol Version :")); - //fixme there is no way currently to find out the negotiated protocol version - // The delegate is the versioned class ((AMQConnection)connection)._delegate - - assertEquals("unexpected Client Version option state", clientVersionPresent, fromMessage(log).contains("Client Version :")); - - if(clientVersionPresent && clientVersionValue != null) - { - assertTrue("Client version value is not present: " + clientVersionValue, fromMessage(log).contains(clientVersionValue)); - } - - assertEquals("unexpected Client Product option state", clientVersionPresent, fromMessage(log).contains("Client Product :")); - - if(clientProductPresent && clientProductValue != null) - { - assertTrue("Client product value is not present: " + clientProductValue, fromMessage(log).contains(clientProductValue)); - } - } - - /** - * Description: - * When a connected client closes the connection this will be logged as a CON-1002 message. - * Input: - * - * 1. Running Broker - * 2. Connected Client - * Output: - * - * CON-1002 : Close - * - * Validation Steps: - * 3. The CON ID is correct - * 4. This must be the last CON message for the Connection - * 5. It must be preceded by a CON-1001 for this Connection - */ - public void testConnectionClose() throws Exception - { - assertLoggingNotYetOccured(CONNECTION_PREFIX); - - Connection connection = getConnection(); - - // Wait until opened - waitForMessage("CON-1001"); - - // Close the conneciton - connection.close(); - - // Wait to ensure that the desired message is logged - waitForMessage("CON-1002"); - - List results = findMatches(CONNECTION_PREFIX); - - // Validation - - // We should have at least four messages - assertTrue("CON messages not logged:" + results.size(), results.size() >= 4); - - // Validate Close message occurs - String log = getLogMessageFromEnd(results, 0); - validateMessageID("CON-1002",log); - assertTrue("Message does not end with close:" + log, log.endsWith("Close")); - - // Extract connection ID to validate there is a CON-1001 messasge for it - final String logSubject = fromSubject(log); - int closeConnectionID = getConnectionID(logSubject); - assertTrue("Could not get the connection id from CLOSE message: " + logSubject, closeConnectionID != -1); - - //Previous log message should be the open - log = getLogMessageFromEnd(results, 1); - // MESSAGE [con:1(/127.0.0.1:52540)] CON-1001 : Open : Client ID : clientid : Protocol Version : 0-9 - validateMessageID("CON-1001",log); - - // Extract connection ID to validate it matches the CON-1002 messasge - int openConnectionID = getConnectionID(fromActor(log)); - assertTrue("Could not find connection id in OPEN", openConnectionID != -1); - - // Check connection ids match - assertEquals("Connection IDs do not match", closeConnectionID, openConnectionID); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ConsumerLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ConsumerLoggingTest.java deleted file mode 100644 index f321b4e8e0..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ConsumerLoggingTest.java +++ /dev/null @@ -1,407 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.logging; - -import javax.jms.QueueBrowser; -import junit.framework.AssertionFailedError; - -import org.apache.qpid.client.AMQConnection; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.Queue; -import javax.jms.Session; -import javax.jms.Topic; -import java.io.IOException; -import java.util.List; - -/** - * Subscription - * - * The Subscription test suite validates that the follow log messages as specified in the Functional Specification. - * - * This suite of tests validate that the Subscription messages occur correctly and according to the following format: - * - * SUB-1001 : Create : [Durable] [Arguments : ] - * SUB-1002 : Close - * SUB-1003 : State : - */ -public class ConsumerLoggingTest extends AbstractTestLogging -{ - static final String SUB_PREFIX = "SUB-"; - - private Connection _connection; - private Session _session; - private Queue _queue; - private Topic _topic; - - @Override - public void setUp() throws Exception - { - super.setUp(); - //Remove broker startup logging messages - _monitor.markDiscardPoint(); - - _connection = getConnection(); - - _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - _queue = _session.createQueue(getTestQueueName() + "Queue"); - _topic = _session.createTopic(getTestQueueName() + "Topic"); - } - - /** - * Description: - * When a Subscription is created it will be logged. This test validates that Subscribing to a transient queue is correctly logged. - * Input: - * - * 1. Running Broker - * 2. Create a new Subscription to a transient queue/topic. - * Output: 6 - * - * SUB-1001 : Create - * - * Validation Steps: - * 3. The SUB ID is correct - * - * @throws java.io.IOException - if there is a problem getting the matches - * @throws javax.jms.JMSException - if there is a problem creating the consumer - */ - public void testSubscriptionCreate() throws JMSException, IOException - { - _session.createConsumer(_queue); - - //Validate - - //Ensure that we wait for the SUB log message - waitAndFindMatches("SUB-1001"); - - List results = findMatches(SUB_PREFIX); - - assertEquals("Result set larger than expected.", 1, results.size()); - - String log = getLogMessage(results, 0); - - validateMessageID("SUB-1001", log); - - assertEquals("Log Message not as expected", "Create", getMessageString(fromMessage(log))); - } - - /** - * Description: - * The creation of a Durable Subscription, such as a JMS DurableTopicSubscriber will result in an extra Durable tag being included in the Create log message - * Input: - * - * 1. Running Broker - * 2. Creation of a JMS DurableTopicSubiber - * Output: - * - * SUB-1001 : Create : Durable - * - * Validation Steps: - * 3. The SUB ID is correct - * 4. The Durable tag is present in the message - * NOTE: A Subscription is not Durable, the queue it consumes from is. - * - * @throws java.io.IOException - if there is a problem getting the matches - * @throws javax.jms.JMSException - if there is a problem creating the consumer - */ - public void testSubscriptionCreateDurable() throws JMSException, IOException - { - _session.createDurableSubscriber(_topic, getName()); - - //Validate - //Ensure that we wait for the SUB log message - waitAndFindMatches("SUB-1001"); - - List results = findMatches(SUB_PREFIX); - - assertEquals("Result set not as expected.", 1, results.size()); - - String log = getLogMessage(results, 0); - - validateMessageID("SUB-1001", log); - - String message = getMessageString(fromMessage(log)); - assertTrue("Durable not on log message:" + message, message.contains("Durable")); - } - - /** - * Description: - * The creation of a Subscriber with a JMS Selector will result in the Argument field being populated. These argument key/value pairs are then shown in the log message. - * Input: - * - * 1. Running Broker - * 2. Subscriber created with a JMS Selector. - * Output: - * - * SUB-1001 : Create : Arguments : - * - * Validation Steps: - * 3. The SUB ID is correct - * 4. Argument tag is present in the message - * - * @throws java.io.IOException - if there is a problem getting the matches - * @throws javax.jms.JMSException - if there is a problem creating the consumer - */ - public void testSubscriptionCreateWithArguments() throws JMSException, IOException - { - final String SELECTOR = "Selector='True'"; - _session.createConsumer(_queue, SELECTOR); - - //Validate - - //Ensure that we wait for the SUB log message - waitAndFindMatches("SUB-1001"); - - List results = findMatches(SUB_PREFIX); - - assertEquals("Result set larger than expected.", 1, results.size()); - - String log = getLogMessage(results, 0); - - validateMessageID("SUB-1001", log); - - String message = getMessageString(fromMessage(log)); - assertTrue("Selector not on log message:" + message, message.contains(SELECTOR)); - } - - /** - * Description: - * The final combination of SUB-1001 Create messages involves the creation of a Durable Subscription that also contains a set of Arguments, such as those provided via a JMS Selector. - * Input: - * - * 1. Running Broker - * 2. Java Client creates a Durable Subscription with Selector - * Output: - * - * SUB-1001 : Create : Durable Arguments : - * - * Validation Steps: - * 3. The SUB ID is correct - * 4. The tag Durable is present in the message - * 5. The Arguments are present in the message - * - * @throws java.io.IOException - if there is a problem getting the matches - * @throws javax.jms.JMSException - if there is a problem creating the consumer - */ - public void testSubscriptionCreateDurableWithArguments() throws JMSException, IOException - { - final String SELECTOR = "Selector='True'"; - _session.createDurableSubscriber(_topic, getName(), SELECTOR, false); - - //Validate - - //Ensure that we wait for the SUB log message - waitAndFindMatches("SUB-1001"); - - List results = findMatches(SUB_PREFIX); - - assertEquals("Result set larger than expected.", 1, results.size()); - - String log = getLogMessage(results, 0); - - validateMessageID("SUB-1001", log); - - String message = getMessageString(fromMessage(log)); - assertTrue("Durable not on log message:" + message, message.contains("Durable")); - assertTrue("Selector not on log message:" + message, message.contains(SELECTOR)); - } - - /** - * Description: - * When a Subscription is closed it will log this so that it can be correlated with the Create. - * Input: - * - * 1. Running Broker - * 2. Client with a subscription. - * 3. The subscription is then closed. - * Output: - * - * SUB-1002 : Close - * - * Validation Steps: - * 1. The SUB ID is correct - * 2. There must be a SUB-1001 Create message preceding this message - * 3. This must be the last message from the given Subscription - * - * @throws java.io.IOException - if there is a problem getting the matches - * @throws javax.jms.JMSException - if there is a problem creating the consumer - */ - public void testSubscriptionClose() throws JMSException, IOException - { - _session.createConsumer(_queue).close(); - - //Validate - //Ensure that we wait for the SUB log message - waitAndFindMatches("SUB-1002"); - - List results = findMatches(SUB_PREFIX); - - //3 - assertEquals("Result set larger than expected.", 2, results.size()); - - // 2 - String log = getLogMessage(results, 0); - validateMessageID("SUB-1001", log); - // 1 - log = getLogMessage(results, 1); - validateMessageID("SUB-1002", log); - - String message = getMessageString(fromMessage(log)); - assertEquals("Log message is not close", "Close", message); - - } - - /** - * Description: - * When a Subscription fills its prefetch it will become suspended. This - * will be logged as a SUB-1003 message. - * Input: - * - * 1. Running broker - * 2. Message Producer to put more data on the queue than the client's prefetch - * 3. Client that ensures that its prefetch becomes full - * Output: - * - * SUB-1003 : State : - * - * Validation Steps: - * 1. The SUB ID is correct - * 2. The state is correct - * - * @throws java.io.IOException - if there is a problem getting the matches - * @throws javax.jms.JMSException - if there is a problem creating the consumer - */ - public void testSubscriptionSuspend() throws Exception, IOException - { - //Close session with large prefetch - _connection.createSession(false, Session.AUTO_ACKNOWLEDGE).close(); - - int PREFETCH = 15; - - //Create new session with small prefetch - _session = ((AMQConnection) _connection).createSession(true, Session.SESSION_TRANSACTED, PREFETCH); - - MessageConsumer consumer = _session.createConsumer(_queue); - - _connection.start(); - - //Start the dispatcher & Unflow the channel. - consumer.receiveNoWait(); - - //Fill the prefetch and two extra so that our receive bellow allows the - // subscription to become active - // Previously we set this to 17 so that it would return to a suspended - // state. However, testing has shown that the state change can occur - // sufficiently quickly that logging does not occur consistently enough - // for testing. - int SEND_COUNT = 16; - sendMessage(_session, _queue, SEND_COUNT); - _session.commit(); - // Retreive the first message, and start the flow of messages - Message msg = consumer.receive(1000); - assertNotNull("First message not retreived", msg); - _session.commit(); - - // Drain the queue to ensure there is time for the ACTIVE log message - // Check that we can received all the messages - int receivedCount = 0; - while (msg != null) - { - receivedCount++; - msg = consumer.receive(1000); - _session.commit(); - } - - //Validate we received all the messages - assertEquals("Not all sent messages received.", SEND_COUNT, receivedCount); - - // Fill the queue again to suspend the consumer - sendMessage(_session, _queue, SEND_COUNT); - _session.commit(); - - //Validate - List results = waitAndFindMatches("SUB-1003"); - - try - { - // Validation expects three messages. - // The Actor can be any one of the following depending on the exactly what is going on on the broker. - // Ideally we would test that we can get all of them but setting up - // the timing to do this in a consistent way is not benefitial. - // Ensuring the State is as expected is sufficient. -// INFO - MESSAGE [vh(/test)/qu(example.queue)] [sub:6(qu(example.queue))] SUB-1003 : State : -// INFO - MESSAGE [con:6(guest@anonymous(26562441)/test)/ch:3] [sub:6(qu(example.queue))] SUB-1003 : State : -// INFO - MESSAGE [sub:6(vh(test)/qu(example.queue))] [sub:6(qu(example.queue))] SUB-1003 : State : - - assertEquals("Result set not expected size:", 3, results.size()); - - // Validate Initial Suspension - String expectedState = "SUSPENDED"; - String log = getLogMessage(results, 0); - validateSubscriptionState(log, expectedState); - - // After being suspended the subscription should become active. - expectedState = "ACTIVE"; - log = getLogMessage(results, 1); - validateSubscriptionState(log, expectedState); - - // Validate that it was re-suspended - expectedState = "SUSPENDED"; - log = getLogMessage(results, 2); - validateSubscriptionState(log, expectedState); - // We only need validate the state. - } - catch (AssertionFailedError afe) - { - System.err.println("Log Dump:"); - for (String log : results) - { - System.err.println(log); - } - throw afe; - } - _connection.close(); - } - - /** - * Validate that the given log statement is a well formatted SUB-1003 - * message. That means the ID and expected state are correct. - * - * @param log the log to test - * @param expectedState the state that should be logged. - */ - private void validateSubscriptionState(String log, String expectedState) - { - validateMessageID("SUB-1003", log); - String logMessage = getMessageString(fromMessage(log)); - assertTrue("Log Message does not start with 'State'" + logMessage, - logMessage.startsWith("State")); - - assertTrue("Log Message does not have expected State of '" - + expectedState + "'" + logMessage, - logMessage.endsWith(expectedState)); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/DurableQueueLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/DurableQueueLoggingTest.java deleted file mode 100644 index dcc1837c5b..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/DurableQueueLoggingTest.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.server.logging; - -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.framing.AMQShortString; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Queue; -import javax.jms.Session; -import javax.naming.NamingException; -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * The Queue test suite validates that the follow log messages as specified in - * the Functional Specification. - * - * This suite of tests validate that the Queue messages occur correctly and - * according to the following format: - * - * QUE-1001 : Create : [AutoDelete] [Durable|Transient] [Priority:] [Owner:] - */ -public class DurableQueueLoggingTest extends AbstractTestLogging -{ - protected String DURABLE = "Durable"; - protected String TRANSIENT = "Transient"; - protected boolean _durable; - - protected Connection _connection; - protected Session _session; - private static final String QUEUE_PREFIX = "QUE-"; - private static int PRIORITIES = 6; - - public void setUp() throws Exception - { - super.setUp(); - //Ensure we only have logs from our test - _monitor.markDiscardPoint(); - - _connection = getConnection(); - _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - _durable = true; - } - - /** - * Description: - * When a simple transient queue is created then a QUE-1001 create message - * is expected to be logged. - * Input: - * 1. Running broker - * 2. Persistent Queue is created from a client - * Output: - * - * QUE-1001 : Create : Owner: '' Durable - * - * Validation Steps: - * 3. The QUE ID is correct - * 4. The Durable tag is present in the message - * 5. The Owner is as expected - * - * @throws javax.jms.JMSException - * @throws javax.naming.NamingException - * @throws java.io.IOException - */ - public void testQueueCreateDurableExclusive() throws NamingException, JMSException, IOException - { - String queueName= getTestQueueName(); - // To force a queue Creation Event we need to create a consumer. - Queue queue = (Queue) _session.createQueue("direct://amq.direct/" + queueName + "/" + queueName + "?durable='" + _durable + "'&exclusive='true'"); - - _session.createConsumer(queue); - - List results = waitForMesssage(); - - String clientID = _connection.getClientID(); - assertNotNull("clientID should not be null", clientID); - - // in 0-8/9/9-1 an exclusive queue will be deleted when the connection is closed, so auto-delete is true. - // in 0-10 an exclusive queue outlasts the creating connection and so is not auto-delete - // the queue only has owner as the client-id in 0-8/9/91 where exclusivity is taken to mean exclusive to the - // client-id in perpetuity. For 0-10 exclusive means exclusive to a session. - validateQueueProperties(results, false, !(isBroker010() || _durable), (_durable && !isBroker010()) ? clientID : null); - } - - /** - * Description: - * When a simple transient queue is created then a QUE-1001 create message - * is expected to be logged. - * Input: - * 1. Running broker - * 2. Persistent Queue is created from a client - * Output: - * - * QUE-1001 : Create : Owner: '' Durable - * - * Validation Steps: - * 3. The QUE ID is correct - * 4. The Durable tag is present in the message - * 5. The Owner is as expected - * - * @throws javax.jms.JMSException - * @throws javax.naming.NamingException - * @throws java.io.IOException - */ - public void testQueueCreateDurable() throws NamingException, JMSException, IOException - { - String queueName = getTestQueueName(); - - // To force a queue Creation Event we need to create a consumer. - Queue queue = (Queue) _session.createQueue("direct://amq.direct/" + queueName + "/" + queueName + "?durable='" + _durable + "'"); - - _session.createConsumer(queue); - - List results = waitForMesssage(); - - validateQueueProperties(results, false, false, null); - } - - /** - * Description: - * When a simple transient queue is created then a QUE-1001 create message - * is expected to be logged. - * Input: - * 1. Running broker - * 2. AutoDelete Persistent Queue is created from a client - * Output: - * - * QUE-1001 : Create : Owner: '' AutoDelete Durable - * - * Validation Steps: - * 3. The QUE ID is correct - * 4. The Durable tag is present in the message - * 5. The Owner is as expected - * 6. The AutoDelete tag is present in the message - * - * @throws javax.jms.JMSException - * @throws javax.naming.NamingException - * @throws java.io.IOException - */ - public void testQueueCreatePersistentAutoDelete() throws NamingException, JMSException, IOException - { - String queueName = getTestQueueName(); - // To force a queue Creation Event we need to create a consumer. - Queue queue = (Queue) _session.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='"+_durable+"'&autodelete='true'"); - - _session.createConsumer(queue); - - List results = waitForMesssage(); - - validateQueueProperties(results, false, true, null); - } - - /** - * Description: - * When a simple transient queue is created then a QUE-1001 create message - * is expected to be logged. - * Input: - * 1. Running broker - * 2. Persistent Queue is created from a client - * Output: - * - * QUE-1001 : Create : Owner: '' Durable Priority: - * - * Validation Steps: - * 3. The QUE ID is correct - * 4. The Durable tag is present in the message - * 5. The Owner is as expected - * 6. The Priority level is correctly set - * - * @throws javax.jms.JMSException - * @throws javax.naming.NamingException - * @throws java.io.IOException - */ - public void testCreateQueuePersistentPriority() throws NamingException, JMSException, IOException, AMQException - { - // To Create a Priority queue we need to use AMQSession specific code - final Map arguments = new HashMap(); - arguments.put("x-qpid-priorities", PRIORITIES); - // Need to create a queue that does not exist so use test name - final String queueName = getTestQueueName(); - ((AMQSession) _session).createQueue(new AMQShortString(queueName), false, _durable, false, arguments); - - Queue queue = (Queue) _session.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='"+_durable+"'&autodelete='false'"); - - - //Need to create a Consumer to ensure that the log has had time to write - // as the above Create is Asynchronous - _session.createConsumer(queue); - - List results = waitForMesssage(); - - // Only 1 Queue message should hav been logged - assertEquals("Result set size not as expected", 1, results.size()); - - validateQueueProperties(results, true, false, null); - } - - /** - * Description: - * When a simple transient queue is created then a QUE-1001 create message - * is expected to be logged. - * Input: - * 1. Running broker - * 2. AutoDelete Persistent Queue is created from a client - * Output: - * - * QUE-1001 : Create : Owner: '' Durable Priority: - * - * Validation Steps: - * 3. The QUE ID is correct - * 4. The Durable tag is present in the message - * 5. The Owner is as expected - * 6. The AutoDelete tag is present in the message - * 7. The Priority level is correctly set - * - * @throws javax.jms.JMSException - * @throws javax.naming.NamingException - * @throws java.io.IOException - */ - public void testCreateQueuePersistentAutoDeletePriority() throws NamingException, JMSException, IOException, AMQException - { - // To Create a Priority queue we need to use AMQSession specific code - final Map arguments = new HashMap(); - arguments.put("x-qpid-priorities", PRIORITIES); - // Need to create a queue that does not exist so use test name - final String queueName = getTestQueueName() + "-autoDeletePriority"; - ((AMQSession) _session).createQueue(new AMQShortString(queueName), true, _durable, false, arguments); - - Queue queue = (Queue) _session.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='"+_durable+"'&autodelete='true'"); - - - //Need to create a Consumer to ensure that the log has had time to write - // as the above Create is Asynchronous - _session.createConsumer(queue); - - List results = waitForMesssage(); - - validateQueueProperties(results, true, true, null); - } - - private List waitForMesssage() throws IOException - { - // Validation - // Ensure we have received the QUE log msg. - waitForMessage("QUE-1001"); - - List results = findMatches(QUEUE_PREFIX); - - // Only 1 Queue message should hav been logged - assertEquals("Result set size not as expected", 1, results.size()); - - return results; - } - - public void validateQueueProperties(List results, boolean hasPriority, boolean hasAutodelete, String clientID) - { - String log = getLogMessage(results, 0); - - // Message Should be a QUE-1001 - validateMessageID("QUE-1001", log); - - // Queue is Durable - assertEquals(DURABLE + " keyword not correct in log entry", - _durable, fromMessage(log).contains(DURABLE)); - - assertEquals(TRANSIENT + " keyword not correct in log entry.", - !_durable, fromMessage(log).contains(TRANSIENT)); - - // Queue is Priority - assertEquals("Unexpected priority status:" + fromMessage(log), hasPriority, - fromMessage(log).contains("Priority: " + PRIORITIES)); - - // Queue is AutoDelete - assertEquals("Unexpected AutoDelete status:" + fromMessage(log), hasAutodelete, - fromMessage(log).contains("AutoDelete")); - - if(clientID != null) - { - assertTrue("Queue does not have correct owner value:" + fromMessage(log), - fromMessage(log).contains("Owner: " + clientID)); - } - else - { - assertFalse("Queue should not contain Owner tag:" + fromMessage(log), - fromMessage(log).contains("Owner")); - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ExchangeLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ExchangeLoggingTest.java deleted file mode 100644 index edffa7c0c0..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ExchangeLoggingTest.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.logging; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.AMQSession_0_10; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ExchangeDeleteBody; -import org.apache.qpid.framing.ExchangeDeleteOkBody; -import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.Session; -import javax.jms.TextMessage; -import java.io.IOException; -import java.util.List; - -/** - * Exchange - * - * The Exchange test suite validates that the follow log messages as specified in the Functional Specification. - * - * This suite of tests validate that the Exchange messages occur correctly and according to the following format: - * - * EXH-1001 : Create : [Durable] Type: Name: - * EXH-1002 : Deleted - */ -public class ExchangeLoggingTest extends AbstractTestLogging -{ - - static final String EXH_PREFIX = "EXH-"; - - private Connection _connection; - private Session _session; - private Queue _queue; - private String _name; - private String _type; - - @Override - public void setUp() throws Exception - { - super.setUp(); - - _connection = getConnection(); - - _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - _type = "direct"; - _name = getTestQueueName()+ "-exchange"; - - _queue = _session.createQueue(_type + "://" + _name + "/queue/queue"); - - } - - /** - * Description: - * When a durable exchange is created an EXH-1001 message is logged with the Durable tag. This will be the first message from this exchange. - * Input: - * - * 1. Running broker - * 2. Client requests a durable exchange be created. - * Output: - * - * EXH-1001 : Create : Durable Type: Name: - * - * Validation Steps: - * 3. The EXH ID is correct - * 4. The Durable tag is present in the message - */ - - public void testExchangeCreateDurable() throws JMSException, IOException - { - // The client cannot create durable exchanges lets just look at the - // ones the broker creates at startup. - - // They should all be durable - - // Ensure we have received the EXH log msg. - waitForMessage("EXH-1001"); - - List results = findMatches(EXH_PREFIX); - - assertTrue("No Results found for Exchange.", results.size()>0); - - validateExchangeCreate(results, true, false); - } - - /** - * Description: - * When an exchange is created an EXH-1001 message is logged. This will be the first message from this exchange. - * Input: - * - * 1. Running broker - * 2. Client requests an exchange be created. - * Output: - * - * EXH-1001 : Create : Type: Name: - * - * Validation Steps: - * 3. The EXH ID is correct - */ - public void testExchangeCreate() throws JMSException, IOException - { - //Ignore broker startup messages - _monitor.markDiscardPoint(); - - _session.createConsumer(_queue); - // Ensure we have received the EXH log msg. - waitForMessage("EXH-1001"); - - List results = findMatches(EXH_PREFIX); - - assertEquals("Result set larger than expected.", 1, results.size()); - - validateExchangeCreate(results, false, true); - } - - private void validateExchangeCreate(List results, boolean durable, boolean checkNameAndType) - { - String log = getLogMessage(results, 0); - String message = getMessageString(fromMessage(log)); - - validateMessageID("EXH-1001", log); - - assertTrue("Log Message does not start with create:" + message, - message.startsWith("Create")); - - assertEquals("Unexpected Durable state:" + message, durable, - message.contains("Durable")); - - if(checkNameAndType) - { - assertTrue("Log Message does not contain Type:" + message, - message.contains("Type: " + _type)); - assertTrue("Log Message does not contain Name:" + message, - message.contains("Name: " + _name)); - } - } - - /** - * Description: - * An Exchange can be deleted through an AMQP ExchangeDelete method. When this is successful an EXH-1002 Delete message will be logged. This will be the last message from this exchange. - * Input: - * - * 1. Running broker - * 2. A new Exchange has been created - * 3. Client requests that the new exchange be deleted. - * Output: - * - * EXH-1002 : Deleted - * - * Validation Steps: - * 4. The EXH ID is correct - * 5. There is a corresponding EXH-1001 Create message logged. - */ - public void testExchangeDelete() throws Exception, IOException - { - //Ignore broker startup messages - _monitor.markDiscardPoint(); - - //create the exchange by creating a consumer - _session.createConsumer(_queue); - - //now delete the exchange - if(isBroker010()) - { - ((AMQSession_0_10) _session).sendExchangeDelete(_name, false); - } - else - { - MethodRegistry_8_0 registry = new MethodRegistry_8_0(); - - ExchangeDeleteBody body = registry.createExchangeDeleteBody(0, new AMQShortString(_name), false, true); - - AMQFrame exchangeDeclare = body.generateFrame(((AMQSession)_session).getChannelId()); - - ((AMQConnection) _connection).getProtocolHandler().syncWrite(exchangeDeclare, ExchangeDeleteOkBody.class); - } - - //Wait and ensure we get our last EXH-1002 msg - waitForMessage("EXH-1002"); - - List results = findMatches(EXH_PREFIX); - - assertEquals("Result set larger than expected.", 2, results.size()); - - validateExchangeCreate(results, false, false); - - String log = getLogMessage(results, 1); - validateMessageID("EXH-1002", log); - - String message = getMessageString(fromMessage(log)); - assertEquals("Log Message not as expected", "Deleted", message); - - } - - public void testDiscardedMessage() throws Exception - { - //Ignore broker startup messages - _monitor.markDiscardPoint(); - - if (!isBroker010()) - { - // Default 0-8..-0-9-1 behaviour is for messages to be rejected (returned to client). - setTestClientSystemProperty("qpid.default_mandatory", "false"); - } - - _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - // Do not create consumer so queue is not created and message will be discarded. - final MessageProducer producer = _session.createProducer(_queue); - - // Sending message - final TextMessage msg = _session.createTextMessage("msg"); - producer.send(msg); - - final String expectedMessageBody = "Discarded Message : Name: " + _name + " Routing Key: " + _queue.getQueueName(); - - // Ensure we have received the EXH log msg. - waitForMessage("EXH-1003"); - - List results = findMatches(EXH_PREFIX); - assertEquals("Result set larger than expected.", 2, results.size()); - - final String log = getLogMessage(results, 1); - validateMessageID("EXH-1003", log); - - final String message = getMessageString(fromMessage(log)); - assertEquals("Log Message not as expected", expectedMessageBody, message); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/QueueLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/QueueLoggingTest.java deleted file mode 100644 index 1c7b4c6be8..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/QueueLoggingTest.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.logging; - -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.failover.FailoverException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Queue; -import javax.jms.Session; -import javax.naming.NamingException; -import java.io.IOException; -import java.util.List; - -/** - * The Queue test suite validates that the follow log messages as specified in - * the Functional Specification. - * - * This suite of tests validate that the Queue messages occur correctly and - * according to the following format: - * - * QUE-1002 : Deleted - */ -public class QueueLoggingTest extends AbstractTestLogging -{ - protected Connection _connection; - protected Session _session; - private static final String QUEUE_PREFIX = "QUE-"; - - public void setUp() throws Exception - { - super.setUp(); - //Remove broker startup logging messages - _monitor.markDiscardPoint(); - - _connection = getConnection(); - _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - } - - /** - * Description: - * An explict QueueDelete request must result in a QUE-1002 Deleted message - * being logged. This can be done via an explict AMQP QueueDelete method. - * Input: - * - * 1. Running Broker - * 2. Queue created on the broker with no subscribers - * 3. Client requests the queue be deleted via a QueueDelete - * Output: - * - * QUE-1002 : Deleted - * - * Validation Steps: - * - * 4. The QUE ID is correct - * - * @throws java.io.IOException - * @throws javax.jms.JMSException - * @throws javax.naming.NamingException - */ - public void testQueueDelete() throws NamingException, JMSException, IOException, FailoverException, AMQException - { - // To force a queue Creation Event we need to create a consumer. - Queue queue = _session.createQueue(getTestQueueName()); - - _session.createConsumer(queue); - - // Delete Queue - ((AMQSession)_session).sendQueueDelete(new AMQShortString(queue.getQueueName())); - - //Perform a synchronous action to ensure that the above log will be on disk - _session.close(); - - // Validation - //Ensure that we wait for the QUE log message - waitAndFindMatches("QUE-1002"); - - List results = findMatches(QUEUE_PREFIX); - - // Only 1 Queue message should hav been logged - assertEquals("Result set size not as expected", 2, results.size()); - - String log = getLogMessage(results, 0); - - // Message Should be a QUE-1001 - validateMessageID("QUE-1001", log); - - String createdQueueName = AbstractTestLogSubject.getSlice("qu", fromSubject(log)); - - log = getLogMessage(results, 1); - // Message Should be a QUE-1002 - validateMessageID("QUE-1002", log); - - assertEquals("Log Message is incorrect ", "Deleted", getMessageString(fromMessage(log))); - - assertEquals("Queue Delete not for created queue:", createdQueueName, - AbstractTestLogSubject.getSlice("qu", fromSubject(log))); - } - - - /** - * Description: - * An explict QueueDelete request must result in a QUE-1002 Deleted message - * being logged. This can be done via an explict AMQP QueueDelete method. - * Input: - * - * 1. Running Broker - * 2. Queue created on the broker with no subscribers - * 3. Client creates a temporary queue then disconnects - * Output: - * - * QUE-1002 : Deleted - * - * Validation Steps: - * - * 4. The QUE ID is correct - * - * @throws java.io.IOException - * @throws javax.jms.JMSException - * @throws javax.naming.NamingException - */ - public void testQueueAutoDelete() throws NamingException, JMSException, IOException - { - // Create a temporary queue so that when we consume from it and - // then close the consumer it will be autoDeleted. - _session.createConsumer(_session.createTemporaryQueue()).close(); - - if(isBroker010()) - { - //auto-delete is at session close for 0-10 - _session.close(); - } - - // Validation - //Ensure that we wait for the QUE log message - waitAndFindMatches("QUE-1002"); - - List results = findMatches(QUEUE_PREFIX); - - // Only 1 Queue message should hav been logged - assertEquals("Result set size not as expected", 2, results.size()); - - String log = getLogMessage(results, 0); - - // Message Should be a QUE-1001 - validateMessageID("QUE-1001", log); - - String createdQueueName = AbstractTestLogSubject.getSlice("qu", fromSubject(log)); - - log = getLogMessage(results, 1); - // Message Should be a QUE-1002 - validateMessageID("QUE-1002", log); - - assertEquals("Log Message is incorrect ", "Deleted", getMessageString(fromMessage(log))); - - assertEquals("Queue Delete not for created queue:", createdQueueName, - AbstractTestLogSubject.getSlice("qu", fromSubject(log))); - - } - -} \ No newline at end of file diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/TransientQueueLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/TransientQueueLoggingTest.java deleted file mode 100644 index 29f74c5818..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/TransientQueueLoggingTest.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.logging; - -public class TransientQueueLoggingTest extends DurableQueueLoggingTest -{ - public void setUp() throws Exception - { - super.setUp(); - _durable = false; - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java deleted file mode 100644 index 25dd5fd2f8..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ - -package org.apache.qpid.server.logging; - -import junit.framework.AssertionFailedError; - - -import java.util.Arrays; -import java.util.List; - -/** - * Virtualhost Test Cases - * The virtualhost test suite validates that the follow log messages as specified in the Functional Specification. - *

- * This suite of tests validate that the management console messages occur correctly and according to the following format: - *

- * VHT-1001 : Created : - * VHT-1002 : Work directory : - * VHT-1003 : Closed - */ -public class VirtualHostLoggingTest extends AbstractTestLogging -{ - private static final String VHT_PREFIX = "VHT-"; - - /** - * Description: - * Testing can be performed using the default configuration. The goal is to validate that for each virtualhost defined in the configuration file a VHT-1001 Created message is provided. - * Input: - * The default configuration file - * Output: - *

- * VHT-1001 : Created : - * Validation Steps: - *

- * The VHT ID is correct - * A VHT-1001 is printed for each virtualhost defined in the configuration file. - * This must be the first message for the specified virtualhost. - * - * @throws Exception caused by broker startup - */ - public void testVirtualhostCreation() throws Exception - { - //Wait for the correct VHT message to arrive. - waitForMessage(VHT_PREFIX + "1001"); - - //Validate each vhost logs a creation - List results = findMatches(VHT_PREFIX + "1001"); - - try - { - List vhosts = Arrays.asList("test"); - - assertEquals("Each vhost did not create a store.", vhosts.size(), results.size()); - - for (int index = 0; index < results.size(); index++) - { - // Retrieve the vhostname from the log entry message 'Created : ' - String result = getLogMessage(results, index); - String vhostName = getMessageString(fromMessage(result)).split(" ")[2]; - - assertTrue("Virtualhost named in log not found in config file:" + vhostName + ":" + vhosts, vhosts.contains(vhostName)); - } - } - catch (AssertionFailedError afe) - { - dumpLogs(results, _monitor); - - throw afe; - } - } - - /** - * Description: - * Testing can be performed using the default configuration. During broker shutdown a VHT-1002 Closed message will be printed for each of the configured virtualhosts. For every virtualhost that was started a close must be logged. After the close message has been printed no further logging will be performed by this virtualhost. - * Input: - * The default configuration file - * Output: - *

- * VHT-1002 : Closed - * Validation Steps: - *

- * The VHT ID is correct - * This is the last VHT message for the given virtualhost. - * - * @throws Exception caused by broker startup - */ - public void testVirtualhostClosure() throws Exception - { - if (isJavaBroker() && isInternalBroker()) - { - stopBroker(); - - // Wait for the correct VHT message to arrive. - waitForMessage(VHT_PREFIX + "1002"); - - // Validate each vhost logs a closure - List results = findMatches(VHT_PREFIX + "1002"); - - try - { - assertEquals("Each vhost did not close their store.", 1, results.size()); - } - catch (AssertionFailedError afe) - { - dumpLogs(results, _monitor); - throw afe; - } - } - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/message/MessageProtocolConversionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/message/MessageProtocolConversionTest.java deleted file mode 100644 index 2a5f8b9b95..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/message/MessageProtocolConversionTest.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.message; - -import org.apache.qpid.AMQException; -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.*; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; - -public class MessageProtocolConversionTest extends QpidBrokerTestCase -{ - - private static final int TIMEOUT = 1500; - private Connection _connection_0_9_1; - private Connection _connection_0_10; - - private static final boolean BOOLEAN_TEST_VAL = true; - private static final byte BYTE_TEST_VAL = (byte) 4; - private static final byte[] BYTES_TEST_VAL = {5, 4, 3, 2, 1}; - private static final char CHAR_TEST_VAL = 'x'; - private static final double DOUBLE_TEST_VAL = Double.MAX_VALUE; - private static final float FLOAT_TEST_VAL = Float.MAX_VALUE; - private static final int INT_TEST_VAL = -73; - private static final long LONG_TEST_VAL = Long.MIN_VALUE / 2l; - private static final short SHORT_TEST_VAL = -586; - private static final String STRING_TEST_VAL = "This is a test text message"; - - @Override - public void setUp() throws Exception - { - super.setUp(); - setTestSystemProperty(ClientProperties.AMQP_VERSION, "0-10"); - _connection_0_10 = getConnection(); - setTestSystemProperty(ClientProperties.AMQP_VERSION, "0-9-1"); - _connection_0_9_1 = getConnection(); - } - - public void test0_9_1_to_0_10_conversion() throws JMSException, AMQException - { - doConversionTests(_connection_0_9_1, _connection_0_10); - } - - public void test_0_10_to_0_9_1_conversion() throws JMSException, AMQException - { - - doConversionTests(_connection_0_10, _connection_0_9_1); - } - - private void doConversionTests(Connection producerConn, Connection consumerConn) throws JMSException, AMQException - { - Session producerSession = producerConn.createSession(false, Session.AUTO_ACKNOWLEDGE); - Session consumerSession = consumerConn.createSession(false, Session.AUTO_ACKNOWLEDGE); - - Queue queue = getTestQueue(); - - MessageProducer producer = producerSession.createProducer(queue); - MessageConsumer consumer = consumerSession.createConsumer(queue); - - consumerConn.start(); - producerConn.start(); - - // Text Message - - Message m = producerSession.createTextMessage(STRING_TEST_VAL); - producer.send(m); - m = consumer.receive(TIMEOUT); - - assertNotNull("Expected text message did not arrive", m); - assertTrue("Received message not an instance of TextMessage (" + m.getClass().getName() + " instead)", m instanceof TextMessage); - assertEquals("Message text not as expected", STRING_TEST_VAL, ((TextMessage) m).getText()); - - // Map Message - - MapMessage mapMessage = producerSession.createMapMessage(); - mapMessage.setBoolean("boolean", BOOLEAN_TEST_VAL); - mapMessage.setByte("byte", BYTE_TEST_VAL); - mapMessage.setBytes("bytes", BYTES_TEST_VAL); - mapMessage.setChar("char", CHAR_TEST_VAL); - mapMessage.setDouble("double", DOUBLE_TEST_VAL); - mapMessage.setFloat("float", FLOAT_TEST_VAL); - mapMessage.setInt("int", INT_TEST_VAL); - mapMessage.setLong("long", LONG_TEST_VAL); - mapMessage.setShort("short", SHORT_TEST_VAL); - mapMessage.setString("string", STRING_TEST_VAL); - - producer.send(mapMessage); - - m = consumer.receive(TIMEOUT); - - assertNotNull("Expected map message message did not arrive", m); - assertTrue("Received message not an instance of MapMessage (" + m.getClass().getName() + " instead)", m instanceof MapMessage); - MapMessage receivedMapMessage = (MapMessage) m; - assertEquals("Map message boolean value not as expected", BOOLEAN_TEST_VAL, receivedMapMessage.getBoolean("boolean")); - assertEquals("Map message byte value not as expected", BYTE_TEST_VAL, receivedMapMessage.getByte("byte")); - assertTrue("Map message bytes value not as expected", Arrays.equals(BYTES_TEST_VAL, receivedMapMessage.getBytes("bytes"))); - assertEquals("Map message char value not as expected", CHAR_TEST_VAL, receivedMapMessage.getChar("char")); - assertEquals("Map message double value not as expected", DOUBLE_TEST_VAL, receivedMapMessage.getDouble("double")); - assertEquals("Map message float value not as expected", FLOAT_TEST_VAL, receivedMapMessage.getFloat("float")); - assertEquals("Map message int value not as expected", INT_TEST_VAL, receivedMapMessage.getInt("int")); - assertEquals("Map message long value not as expected", LONG_TEST_VAL, receivedMapMessage.getLong("long")); - assertEquals("Map message short value not as expected", SHORT_TEST_VAL, receivedMapMessage.getShort("short")); - assertEquals("Map message string value not as expected", STRING_TEST_VAL, receivedMapMessage.getString("string")); - ArrayList expectedNames = Collections.list(mapMessage.getMapNames()); - Collections.sort(expectedNames); - ArrayList actualNames = Collections.list(receivedMapMessage.getMapNames()); - Collections.sort(actualNames); - assertEquals("Map message keys not as expected", expectedNames, actualNames); - - // Stream Message - - StreamMessage streamMessage = producerSession.createStreamMessage(); - streamMessage.writeString(STRING_TEST_VAL); - streamMessage.writeShort(SHORT_TEST_VAL); - streamMessage.writeLong(LONG_TEST_VAL); - streamMessage.writeInt(INT_TEST_VAL); - streamMessage.writeFloat(FLOAT_TEST_VAL); - streamMessage.writeDouble(DOUBLE_TEST_VAL); - streamMessage.writeChar(CHAR_TEST_VAL); - streamMessage.writeBytes(BYTES_TEST_VAL); - streamMessage.writeByte(BYTE_TEST_VAL); - streamMessage.writeBoolean(BOOLEAN_TEST_VAL); - - producer.send(streamMessage); - - m = consumer.receive(TIMEOUT); - - assertNotNull("Expected stream message message did not arrive", m); - assertTrue("Received message not an instance of StreamMessage (" + m.getClass().getName() + " instead)", m instanceof StreamMessage); - StreamMessage receivedStreamMessage = (StreamMessage) m; - - assertEquals("Stream message read string not as expected", STRING_TEST_VAL, receivedStreamMessage.readString()); - assertEquals("Stream message read short not as expected", SHORT_TEST_VAL, receivedStreamMessage.readShort()); - assertEquals("Stream message read long not as expected", LONG_TEST_VAL, receivedStreamMessage.readLong()); - assertEquals("Stream message read int not as expected", INT_TEST_VAL, receivedStreamMessage.readInt()); - assertEquals("Stream message read float not as expected", FLOAT_TEST_VAL, receivedStreamMessage.readFloat()); - assertEquals("Stream message read double not as expected", DOUBLE_TEST_VAL, receivedStreamMessage.readDouble()); - assertEquals("Stream message read char not as expected", CHAR_TEST_VAL, receivedStreamMessage.readChar()); - byte[] bytesVal = new byte[BYTES_TEST_VAL.length]; - receivedStreamMessage.readBytes(bytesVal); - assertTrue("Stream message read bytes not as expected", Arrays.equals(BYTES_TEST_VAL, bytesVal)); - assertEquals("Stream message read byte not as expected", BYTE_TEST_VAL, receivedStreamMessage.readByte()); - assertEquals("Stream message read boolean not as expected", BOOLEAN_TEST_VAL, receivedStreamMessage.readBoolean()); - - try - { - receivedStreamMessage.readByte(); - fail("Unexpected remaining bytes in stream message"); - } - catch(MessageEOFException e) - { - // pass - } - - // Object Message - - ObjectMessage objectMessage = producerSession.createObjectMessage(); - objectMessage.setObject(STRING_TEST_VAL); - - producer.send(objectMessage); - - m = consumer.receive(TIMEOUT); - - assertNotNull("Expected object message message did not arrive", m); - assertTrue("Received message not an instance of ObjectMessage (" + m.getClass().getName() + " instead)", m instanceof ObjectMessage); - ObjectMessage receivedObjectMessage = (ObjectMessage) m; - assertEquals("Object message value not as expected", STRING_TEST_VAL, receivedObjectMessage.getObject()); - - - // Bytes Message - - BytesMessage bytesMessage = producerSession.createBytesMessage(); - bytesMessage.writeBytes(BYTES_TEST_VAL); - - producer.send(bytesMessage); - - m = consumer.receive(TIMEOUT); - - assertNotNull("Expected bytes message message did not arrive", m); - assertTrue("Received message not an instance of BytesMessage (" + m.getClass().getName() + " instead)", m instanceof BytesMessage); - BytesMessage receivedBytesMessage = (BytesMessage) m; - bytesVal = new byte[BYTES_TEST_VAL.length]; - receivedBytesMessage.readBytes(bytesVal); - assertTrue("Bytes message read bytes not as expected", Arrays.equals(BYTES_TEST_VAL, bytesVal)); - - try - { - receivedBytesMessage.readByte(); - fail("Unexpected remaining bytes in stream message"); - } - catch(MessageEOFException e) - { - // pass - } - - // Headers / properties tests - - Message msg = producerSession.createMessage(); - msg.setJMSCorrelationID("testCorrelationId"); - msg.setJMSDeliveryMode(DeliveryMode.NON_PERSISTENT); - msg.setJMSPriority(7); - msg.setJMSType("testType"); - - msg.setBooleanProperty("boolean", BOOLEAN_TEST_VAL); - msg.setByteProperty("byte", BYTE_TEST_VAL); - msg.setDoubleProperty("double", DOUBLE_TEST_VAL); - msg.setFloatProperty("float", FLOAT_TEST_VAL); - msg.setIntProperty("int", INT_TEST_VAL); - msg.setLongProperty("long", LONG_TEST_VAL); - msg.setShortProperty("short", SHORT_TEST_VAL); - msg.setStringProperty("string", STRING_TEST_VAL); - - producer.send(msg); - - m = consumer.receive(TIMEOUT); - assertNotNull("Expected message did not arrive", m); - assertEquals("JMSMessageID differs", msg.getJMSMessageID(), m.getJMSMessageID()); - assertEquals("JMSCorrelationID differs",msg.getJMSCorrelationID(),m.getJMSCorrelationID()); - assertEquals("JMSDeliveryMode differs",msg.getJMSDeliveryMode(),m.getJMSDeliveryMode()); - assertEquals("JMSPriority differs",msg.getJMSPriority(),m.getJMSPriority()); - assertEquals("JMSType differs",msg.getJMSType(),m.getJMSType()); - - assertEquals("Message boolean property not as expected", BOOLEAN_TEST_VAL, m.getBooleanProperty("boolean")); - assertEquals("Message byte property not as expected", BYTE_TEST_VAL, m.getByteProperty("byte")); - assertEquals("Message double property not as expected", DOUBLE_TEST_VAL, m.getDoubleProperty("double")); - assertEquals("Message float property not as expected", FLOAT_TEST_VAL, m.getFloatProperty("float")); - assertEquals("Message int property not as expected", INT_TEST_VAL, m.getIntProperty("int")); - assertEquals("Message long property not as expected", LONG_TEST_VAL, m.getLongProperty("long")); - assertEquals("Message short property not as expected", SHORT_TEST_VAL, m.getShortProperty("short")); - assertEquals("Message string property not as expected", STRING_TEST_VAL, m.getStringProperty("string")); - - ArrayList sentPropNames = Collections.list(msg.getPropertyNames()); - Collections.sort(sentPropNames); - ArrayList receivedPropNames = Collections.list(m.getPropertyNames()); - Collections.sort(receivedPropNames); - - // Shouldn't really need to do this, the client should be hiding these from us - removeSyntheticProperties(sentPropNames); - removeSyntheticProperties(receivedPropNames); - - assertEquals("Property names were not as expected", sentPropNames, receivedPropNames); - - // Test Reply To Queue - - Destination replyToDestination = producerSession.createTemporaryQueue(); - MessageConsumer replyToConsumer = producerSession.createConsumer(replyToDestination); - msg = producerSession.createMessage(); - msg.setJMSReplyTo(replyToDestination); - producer.send(msg); - - m = consumer.receive(TIMEOUT); - assertNotNull("Expected message did not arrive", m); - assertNotNull("Message does not have ReplyTo set", m.getJMSReplyTo()); - - MessageProducer responseProducer = consumerSession.createProducer(m.getJMSReplyTo()); - responseProducer.send(consumerSession.createMessage()); - - assertNotNull("Expected response message did not arrive", replyToConsumer.receive(TIMEOUT)); - - // Test Reply To Topic - - replyToDestination = producerSession.createTemporaryTopic(); - replyToConsumer = producerSession.createConsumer(replyToDestination); - msg = producerSession.createMessage(); - msg.setJMSReplyTo(replyToDestination); - producer.send(msg); - - m = consumer.receive(TIMEOUT); - assertNotNull("Expected message did not arrive", m); - assertNotNull("Message does not have ReplyTo set", m.getJMSReplyTo()); - - responseProducer = consumerSession.createProducer(m.getJMSReplyTo()); - responseProducer.send(consumerSession.createMessage()); - - assertNotNull("Expected response message did not arrive", replyToConsumer.receive(TIMEOUT)); - - - } - - private void removeSyntheticProperties(ArrayList propNames) - { - Iterator nameIter = propNames.iterator(); - while(nameIter.hasNext()) - { - String propName = nameIter.next(); - if(propName.startsWith("x-jms") || propName.startsWith("JMS_QPID")) - { - nameIter.remove(); - } - } - } - - @Override - public void tearDown() throws Exception - { - _connection_0_9_1.close(); - _connection_0_10.close(); - super.tearDown(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/persistent/NoLocalAfterRecoveryTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/persistent/NoLocalAfterRecoveryTest.java deleted file mode 100644 index 82b421a531..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/persistent/NoLocalAfterRecoveryTest.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.persistent; - -import java.util.ArrayList; -import java.util.List; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.Session; -import javax.jms.Topic; -import javax.jms.TopicSubscriber; - -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -/** - * Verifies that after recovery, a new Connection with no-local in use is - * able to receive messages sent prior to the broker restart. - */ -public class NoLocalAfterRecoveryTest extends QpidBrokerTestCase -{ - protected final String MY_TOPIC_SUBSCRIPTION_NAME = getTestQueueName(); - protected static final int SEND_COUNT = 10; - - public void testNoLocalNotQueued() throws Exception - { - if(!isBrokerStorePersistent()) - { - fail("This test requires a broker with a persistent store"); - } - - Connection connection = getConnection(); - Session session = connection.createSession(true, Session.SESSION_TRANSACTED); - Topic topic = session.createTopic(MY_TOPIC_SUBSCRIPTION_NAME); - - TopicSubscriber noLocalSubscriber = session. - createDurableSubscriber(topic, MY_TOPIC_SUBSCRIPTION_NAME + "-NoLocal", - null, true); - - TopicSubscriber normalSubscriber = session. - createDurableSubscriber(topic, MY_TOPIC_SUBSCRIPTION_NAME + "-Normal", - null, false); - - sendMessage(session, topic, SEND_COUNT); - - // Check messages can be received as expected. - connection.start(); - - //As the no-local subscriber was on the same connection the messages were - //published on, tit will receive no messages as they will be discarded on the broker - List received = receiveMessage(noLocalSubscriber, SEND_COUNT); - assertEquals("No Local Subscriber Received messages", 0, received.size()); - - received = receiveMessage(normalSubscriber, SEND_COUNT); - assertEquals("Normal Subscriber Received no messages", - SEND_COUNT, received.size()); - session.commit(); - - normalSubscriber.close(); - connection.close(); - - //Ensure the no-local subscribers messages were discarded by restarting the broker - //and reconnecting to the subscription to ensure they were not recovered. - restartBroker(); - - Connection connection2 = getConnection(); - connection2.start(); - - Session session2 = connection2.createSession(true, Session.SESSION_TRANSACTED); - Topic topic2 = session2.createTopic(MY_TOPIC_SUBSCRIPTION_NAME); - - TopicSubscriber noLocalSubscriber2 = session2. - createDurableSubscriber(topic2, MY_TOPIC_SUBSCRIPTION_NAME + "-NoLocal", - null, true); - - // The NO-local subscriber should not get any messages - received = receiveMessage(noLocalSubscriber2, SEND_COUNT); - session2.commit(); - assertEquals("No Local Subscriber Received messages", 0, received.size()); - - noLocalSubscriber2.close(); - - - } - - - public void testNonNoLocalQueued() throws Exception - { - if(!isBrokerStorePersistent()) - { - fail("This test requires a broker with a persistent store"); - } - - Connection connection = getConnection(); - Session session = connection.createSession(true, Session.SESSION_TRANSACTED); - Topic topic = session.createTopic(MY_TOPIC_SUBSCRIPTION_NAME); - - TopicSubscriber noLocalSubscriber = - session.createDurableSubscriber(topic, MY_TOPIC_SUBSCRIPTION_NAME + "-NoLocal", null, true); - - - sendMessage(session, topic, SEND_COUNT); - - // Check messages can be received as expected. - connection.start(); - - List received = receiveMessage(noLocalSubscriber, SEND_COUNT); - assertEquals("No Local Subscriber Received messages", 0, received.size()); - - - - session.commit(); - - Connection connection3 = getConnection(); - Session session3 = connection3.createSession(true, Session.SESSION_TRANSACTED); - sendMessage(session3, topic, SEND_COUNT); - - - connection.close(); - - //We didn't receive the messages on the durable queue for the no-local subscriber - //so they are still on the broker. Restart the broker, prompting their recovery. - restartBroker(); - - Connection connection2 = getConnection(); - connection2.start(); - - Session session2 = connection2.createSession(true, Session.SESSION_TRANSACTED); - Topic topic2 = session2.createTopic(MY_TOPIC_SUBSCRIPTION_NAME); - - TopicSubscriber noLocalSubscriber2 = - session2.createDurableSubscriber(topic2, MY_TOPIC_SUBSCRIPTION_NAME + "-NoLocal",null, true); - - // The NO-local subscriber should receive messages sent from connection3 - received = receiveMessage(noLocalSubscriber2, SEND_COUNT); - session2.commit(); - assertEquals("No Local Subscriber did not receive expected messages", SEND_COUNT, received.size()); - - noLocalSubscriber2.close(); - - - } - - protected List receiveMessage(MessageConsumer messageConsumer, - int count) throws JMSException - { - - List receivedMessages = new ArrayList(count); - for (int i = 0; i < count; i++) - { - Message received = messageConsumer.receive(1000); - - if (received != null) - { - receivedMessages.add(received); - } - else - { - break; - } - } - - return receivedMessages; - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactoryTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactoryTest.java deleted file mode 100644 index c771e84f52..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactoryTest.java +++ /dev/null @@ -1,308 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.server.protocol; - -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.nio.ByteBuffer; -import java.security.Principal; -import java.util.EnumSet; -import java.util.Iterator; -import java.util.Set; - -import org.apache.qpid.protocol.ServerProtocolEngine; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.Protocol; -import org.apache.qpid.server.util.BrokerTestHelper; -import org.apache.qpid.server.virtualhost.VirtualHostImpl; -import org.apache.qpid.test.utils.QpidTestCase; -import org.apache.qpid.transport.Sender; -import org.apache.qpid.transport.network.NetworkConnection; - -public class MultiVersionProtocolEngineFactoryTest extends QpidTestCase -{ - private VirtualHostImpl _virtualHost; - private Broker _broker; - - @Override - protected void setUp() throws Exception - { - super.setUp(); - BrokerTestHelper.setUp(); - _broker = BrokerTestHelper.createBrokerMock(); - when(_broker.getAttribute(Broker.DEFAULT_VIRTUAL_HOST)).thenReturn("default"); - when(_broker.getDefaultVirtualHost()).thenReturn("default"); - when(_broker.getContextValue(eq(Long.class), eq(Broker.BROKER_FRAME_SIZE))).thenReturn(0xffffl); - - } - - @Override - protected void tearDown() throws Exception - { - BrokerTestHelper.tearDown(); - super.tearDown(); - } - - private static final byte[] AMQP_0_8_HEADER = - new byte[] { (byte) 'A', - (byte) 'M', - (byte) 'Q', - (byte) 'P', - (byte) 1, - (byte) 1, - (byte) 8, - (byte) 0 - }; - - private static final byte[] AMQP_0_9_HEADER = - new byte[] { (byte) 'A', - (byte) 'M', - (byte) 'Q', - (byte) 'P', - (byte) 1, - (byte) 1, - (byte) 0, - (byte) 9 - }; - - private static final byte[] AMQP_0_9_1_HEADER = - new byte[] { (byte) 'A', - (byte) 'M', - (byte) 'Q', - (byte) 'P', - (byte) 0, - (byte) 0, - (byte) 9, - (byte) 1 - }; - - - private static final byte[] AMQP_0_10_HEADER = - new byte[] { (byte) 'A', - (byte) 'M', - (byte) 'Q', - (byte) 'P', - (byte) 1, - (byte) 1, - (byte) 0, - (byte) 10 - }; - - - private static final byte[] AMQP_1_0_0_HEADER = - new byte[] { - (byte)'A', - (byte)'M', - (byte)'Q', - (byte)'P', - (byte) 0, - (byte) 1, - (byte) 0, - (byte) 0 - }; - - - private byte[] getAmqpHeader(final Protocol version) - { - switch(version) - { - case AMQP_0_8: - return AMQP_0_8_HEADER; - case AMQP_0_9: - return AMQP_0_9_HEADER; - case AMQP_0_9_1: - return AMQP_0_9_1_HEADER; - case AMQP_0_10: - return AMQP_0_10_HEADER; - case AMQP_1_0: - return AMQP_1_0_0_HEADER; - default: - fail("unknown AMQP version, appropriate header must be added for new protocol version"); - return null; - } - } - - /** - * Test to verify that connections established using a MultiVersionProtocolEngine are assigned - * IDs from a common sequence, independent of the protocol version under use. - */ - public void testDifferentProtocolVersionsShareCommonIDNumberingSequence() - { - Set protocols = getAllAMQPProtocols(); - - Port port = mock(Port.class); - when(port.getContextValue(eq(Long.class),eq(Port.CONNECTION_MAXIMUM_AUTHENTICATION_DELAY))).thenReturn(10000l); - MultiVersionProtocolEngineFactory factory = - new MultiVersionProtocolEngineFactory(_broker, null, false, false, protocols, null, port, - org.apache.qpid.server.model.Transport.TCP); - - //create a dummy to retrieve the 'current' ID number - long previousId = factory.newProtocolEngine().getConnectionId(); - - //create a protocol engine and send the AMQP header for all supported AMQP verisons, - //ensuring the ID assigned increases as expected - for(Protocol protocol : protocols) - { - long expectedID = previousId + 1; - byte[] header = getAmqpHeader(protocol); - assertNotNull("protocol header should not be null", header); - - ServerProtocolEngine engine = factory.newProtocolEngine(); - TestNetworkConnection conn = new TestNetworkConnection(); - engine.setNetworkConnection(conn, conn.getSender()); - assertEquals("ID did not increment as expected", expectedID, engine.getConnectionId()); - - //actually feed in the AMQP header for this protocol version, and ensure the ID remains consistent - engine.received(ByteBuffer.wrap(header)); - assertEquals("ID was not as expected following receipt of the AMQP version header", expectedID, engine.getConnectionId()); - - previousId = expectedID; - engine.closed(); - } - } - - protected Set getAllAMQPProtocols() - { - Set protocols = EnumSet.allOf(Protocol.class); - Iterator protoIter = protocols.iterator(); - while(protoIter.hasNext()) - { - Protocol protocol = protoIter.next(); - if(protocol.getProtocolType() != Protocol.ProtocolType.AMQP) - { - protoIter.remove(); - } - } - return protocols; - } - - /** - * Test to verify that when requesting a ProtocolEngineFactory to produce engines having a default reply to unsupported - * version initiations, there is enforcement that the default reply is itself a supported protocol version. - */ - public void testUnsupportedDefaultReplyCausesIllegalArgumentException() - { - Set versions = getAllAMQPProtocols(); - versions.remove(Protocol.AMQP_0_9); - - try - { - new MultiVersionProtocolEngineFactory(_broker, null, false, false, versions, Protocol.AMQP_0_9, null, - org.apache.qpid.server.model.Transport.TCP); - fail("should not have been allowed to create the factory"); - } - catch(IllegalArgumentException iae) - { - //expected - } - } - - private static class TestNetworkConnection implements NetworkConnection - { - private String _remoteHost = "127.0.0.1"; - private String _localHost = "127.0.0.1"; - private int _port = 1; - private final Sender _sender; - - public TestNetworkConnection() - { - _sender = new Sender() - { - public void setIdleTimeout(int i) - { - } - - public void send(ByteBuffer msg) - { - } - - public void flush() - { - } - - public void close() - { - } - }; - } - - @Override - public SocketAddress getLocalAddress() - { - return new InetSocketAddress(_localHost, _port); - } - - @Override - public SocketAddress getRemoteAddress() - { - return new InetSocketAddress(_remoteHost, _port); - } - - @Override - public void setMaxReadIdle(int idleTime) - { - } - - @Override - public Principal getPeerPrincipal() - { - return null; - } - - @Override - public int getMaxReadIdle() - { - return 0; - } - - @Override - public int getMaxWriteIdle() - { - return 0; - } - - @Override - public void setMaxWriteIdle(int idleTime) - { - } - - @Override - public void close() - { - } - - @Override - public Sender getSender() - { - return _sender; - } - - @Override - public void start() - { - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/DeepQueueConsumeWithSelector.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/DeepQueueConsumeWithSelector.java deleted file mode 100644 index 21e3bfa055..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/DeepQueueConsumeWithSelector.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageListener; -import javax.jms.Queue; -import javax.jms.Session; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -/** - * Test DeapQueueConsumerWithSelector - * Summary: - * Prior to M4 the broker had a different queue model which pre-processed the - * messages on the queue for any connecting subscription that had a selector. - * - * If the queue had a lot of data then this may take a long time to process - * to such an extent that the subscription creation may time out. During this - * pre-process phase the virtualhost would be come unresposive. - * - * Our solution was to allow the timeout to be adjusted QPID-1119, which allowed - * the subscription to connect but did not address the unresponsiveness. - * - * The new queue model introduced in M4 resolved this. - * - * This test is to validate that the new queueing model does indeed remove the - * long pre-processing phase and allow immediate subscription so that there is - * no unresponsive period. - * - * Test Strategy: - * - * Add 100k messages to the queue with a numberic header property that will - * allow later subscribers to use as in a selector. - * - * Connect the subscriber and time how long it takes to connect. - * - * Finally consume all the messages from the queue to clean up. - */ -public class DeepQueueConsumeWithSelector extends QpidBrokerTestCase implements MessageListener -{ - - private static final int MESSAGE_COUNT = 10000; - private static final int BATCH_SIZE = MESSAGE_COUNT / 10; - - private CountDownLatch _receviedLatch = new CountDownLatch(MESSAGE_COUNT); - - protected long SYNC_WRITE_TIMEOUT = 120000L; - - - public void setUp() throws Exception - { - //Set the syncWrite timeout to be just larger than the delay on the commitTran. - setSystemProperty("amqj.default_syncwrite_timeout", String.valueOf(SYNC_WRITE_TIMEOUT)); - - super.setUp(); - } - - public void test() throws Exception - { - // Create Connection - Connection connection = getConnection(); - Session session = ((AMQConnection)connection).createSession(true, Session.SESSION_TRANSACTED, 100000); - - Queue queue = (Queue) getInitialContext().lookup("queue"); - - // Validate that the destination exists - session.createConsumer(queue).close(); - - // Send Messages - sendMessage(session, queue, MESSAGE_COUNT, BATCH_SIZE); - - session.close(); - - session = ((AMQConnection) connection).createSession(false, Session.AUTO_ACKNOWLEDGE);//, 100000); - - - // Setup Selector to perform a few calculations which will slow it down - String selector = "((\"" + INDEX + "\" % 1) = 0) AND ('" + INDEX + "' IS NOT NULL) AND ('" + INDEX + "' <> -1)"; - - // Setup timing - long start = System.nanoTime(); - - System.err.println("Create Consumer"); - // Connect Consumer - MessageConsumer consumer = session.createConsumer(queue, selector); - consumer.setMessageListener(this); - - // Validate timing details - long end = System.nanoTime(); - - System.err.println("Subscription time took:" + (end - start)); - - // Consume Messages - connection.start(); - - - - assertTrue("Messages took to long to be received :"+_receviedLatch.getCount(), - _receviedLatch.await(SYNC_WRITE_TIMEOUT, TimeUnit.MILLISECONDS )); - - } - - @Override - public Message createNextMessage(Session session, int msgCount) throws JMSException - { - Message message = super.createNextMessage(session,msgCount); - - if ((msgCount % BATCH_SIZE) == 0 ) - { - System.err.println("Sent:"+msgCount); - } - - return message; - } - - public void onMessage(Message message) - { - _receviedLatch.countDown(); - int msgCount = 0; - try - { - msgCount = message.getIntProperty(INDEX); - } - catch (JMSException e) - { - //ignore - } - if ((msgCount % BATCH_SIZE) == 0 ) - { - System.err.println("Received:"+msgCount); - } - - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/LastValueQueueTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/LastValueQueueTest.java deleted file mode 100644 index dc30c02951..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/LastValueQueueTest.java +++ /dev/null @@ -1,574 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.queue; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.url.AMQBindingURL; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.Session; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -public class LastValueQueueTest extends QpidBrokerTestCase -{ - private static final Logger LOGGER = Logger.getLogger(LastValueQueueTest.class); - - private static final String MESSAGE_SEQUENCE_NUMBER_PROPERTY = "msg"; - private static final String KEY_PROPERTY = "key"; - - private static final int MSG_COUNT = 400; - - private String _queueName; - private Queue _queue; - private Connection _producerConnection; - private MessageProducer _producer; - private Session _producerSession; - private Connection _consumerConnection; - private Session _consumerSession; - private MessageConsumer _consumer; - - protected void setUp() throws Exception - { - super.setUp(); - - _queueName = getTestQueueName(); - _producerConnection = getConnection(); - _producerSession = _producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - } - - public void testConflation() throws Exception - { - _consumerConnection = getConnection(); - _consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - createConflationQueue(_producerSession); - _producer = _producerSession.createProducer(_queue); - - for (int msg = 0; msg < MSG_COUNT; msg++) - { - _producer.send(nextMessage(msg, _producerSession)); - } - - _producer.close(); - _producerSession.close(); - _producerConnection.close(); - - _consumer = _consumerSession.createConsumer(_queue); - _consumerConnection.start(); - Message received; - - List messages = new ArrayList(); - while((received = _consumer.receive(1000))!=null) - { - messages.add(received); - } - - assertEquals("Unexpected number of messages received",10,messages.size()); - - for(int i = 0 ; i < 10; i++) - { - Message msg = messages.get(i); - assertEquals("Unexpected message number received", MSG_COUNT - 10 + i, msg.getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY)); - } - } - - public void testConflationWithRelease() throws Exception - { - _consumerConnection = getConnection(); - _consumerSession = _consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); - - - createConflationQueue(_producerSession); - _producer = _producerSession.createProducer(_queue); - - for (int msg = 0; msg < MSG_COUNT/2; msg++) - { - _producer.send(nextMessage(msg, _producerSession)); - - } - - // HACK to do something synchronous - ((AMQSession)_producerSession).sync(); - - _consumer = _consumerSession.createConsumer(_queue); - _consumerConnection.start(); - Message received; - List messages = new ArrayList(); - while((received = _consumer.receive(1000))!=null) - { - messages.add(received); - } - - assertEquals("Unexpected number of messages received",10,messages.size()); - - for(int i = 0 ; i < 10; i++) - { - Message msg = messages.get(i); - assertEquals("Unexpected message number received", MSG_COUNT/2 - 10 + i, msg.getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY)); - } - - _consumerSession.close(); - _consumerConnection.close(); - - - _consumerConnection = getConnection(); - _consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - - for (int msg = MSG_COUNT/2; msg < MSG_COUNT; msg++) - { - _producer.send(nextMessage(msg, _producerSession)); - } - - - // HACK to do something synchronous - ((AMQSession)_producerSession).sync(); - - _consumer = _consumerSession.createConsumer(_queue); - _consumerConnection.start(); - - messages = new ArrayList(); - while((received = _consumer.receive(1000))!=null) - { - messages.add(received); - } - - assertEquals("Unexpected number of messages received",10,messages.size()); - - for(int i = 0 ; i < 10; i++) - { - Message msg = messages.get(i); - assertEquals("Unexpected message number received", MSG_COUNT - 10 + i, msg.getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY)); - } - - } - - - public void testConflationWithReleaseAfterNewPublish() throws Exception - { - _consumerConnection = getConnection(); - _consumerSession = _consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); - - - createConflationQueue(_producerSession); - _producer = _producerSession.createProducer(_queue); - - for (int msg = 0; msg < MSG_COUNT/2; msg++) - { - _producer.send(nextMessage(msg, _producerSession)); - } - - // HACK to do something synchronous - ((AMQSession)_producerSession).sync(); - - _consumer = _consumerSession.createConsumer(_queue); - _consumerConnection.start(); - Message received; - List messages = new ArrayList(); - while((received = _consumer.receive(1000))!=null) - { - messages.add(received); - } - - assertEquals("Unexpected number of messages received",10,messages.size()); - - for(int i = 0 ; i < 10; i++) - { - Message msg = messages.get(i); - assertEquals("Unexpected message number received", MSG_COUNT/2 - 10 + i, msg.getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY)); - } - - _consumer.close(); - - for (int msg = MSG_COUNT/2; msg < MSG_COUNT; msg++) - { - _producer.send(nextMessage(msg, _producerSession)); - } - - // HACK to do something synchronous - ((AMQSession)_producerSession).sync(); - - - // this causes the "old" messages to be released - _consumerSession.close(); - _consumerConnection.close(); - - - _consumerConnection = getConnection(); - _consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - - - _consumer = _consumerSession.createConsumer(_queue); - _consumerConnection.start(); - - messages = new ArrayList(); - while((received = _consumer.receive(1000))!=null) - { - messages.add(received); - } - - assertEquals("Unexpected number of messages received",10,messages.size()); - - for(int i = 0 ; i < 10; i++) - { - Message msg = messages.get(i); - assertEquals("Unexpected message number received", MSG_COUNT - 10 + i, msg.getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY)); - } - - } - - public void testConflatedQueueDepth() throws Exception - { - _consumerConnection = getConnection(); - _consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - createConflationQueue(_producerSession); - _producer = _producerSession.createProducer(_queue); - - for (int msg = 0; msg < MSG_COUNT; msg++) - { - _producer.send(nextMessage(msg, _producerSession)); - } - - final long queueDepth = ((AMQSession)_producerSession).getQueueDepth((AMQDestination)_queue, true); - - assertEquals(10, queueDepth); - } - - public void testConflationBrowser() throws Exception - { - _consumerConnection = getConnection(); - _consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - - createConflationQueue(_producerSession); - _producer = _producerSession.createProducer(_queue); - - for (int msg = 0; msg < MSG_COUNT; msg++) - { - _producer.send(nextMessage(msg, _producerSession)); - - } - - ((AMQSession)_producerSession).sync(); - - AMQBindingURL url = new AMQBindingURL("direct://amq.direct//"+_queueName+"?browse='true'&durable='true'"); - AMQQueue browseQueue = new AMQQueue(url); - - _consumer = _consumerSession.createConsumer(browseQueue); - _consumerConnection.start(); - Message received; - List messages = new ArrayList(); - while((received = _consumer.receive(1000))!=null) - { - messages.add(received); - } - - assertEquals("Unexpected number of messages received",10,messages.size()); - - for(int i = 0 ; i < 10; i++) - { - Message msg = messages.get(i); - assertEquals("Unexpected message number received", MSG_COUNT - 10 + i, msg.getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY)); - } - - messages.clear(); - - _producer.send(nextMessage(MSG_COUNT, _producerSession)); - - ((AMQSession)_producerSession).sync(); - - while((received = _consumer.receive(1000))!=null) - { - messages.add(received); - } - assertEquals("Unexpected number of messages received",1,messages.size()); - assertEquals("Unexpected message number received", MSG_COUNT, messages.get(0).getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY)); - - - _producer.close(); - _producerSession.close(); - _producerConnection.close(); - } - - public void testConflation2Browsers() throws Exception - { - _consumerConnection = getConnection(); - _consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - - createConflationQueue(_producerSession); - _producer = _producerSession.createProducer(_queue); - - for (int msg = 0; msg < MSG_COUNT; msg++) - { - _producer.send(nextMessage(msg, _producerSession)); - } - - ((AMQSession)_producerSession).sync(); - - AMQBindingURL url = new AMQBindingURL("direct://amq.direct//"+_queueName+"?browse='true'&durable='true'"); - AMQQueue browseQueue = new AMQQueue(url); - - _consumer = _consumerSession.createConsumer(browseQueue); - MessageConsumer consumer2 = _consumerSession.createConsumer(browseQueue); - _consumerConnection.start(); - List messages = new ArrayList(); - List messages2 = new ArrayList(); - Message received = _consumer.receive(1000); - Message received2 = consumer2.receive(1000); - - while(received!=null || received2!=null) - { - if(received != null) - { - messages.add(received); - } - if(received2 != null) - { - messages2.add(received2); - } - - - received = _consumer.receive(1000); - received2 = consumer2.receive(1000); - - } - - assertEquals("Unexpected number of messages received on first browser",10,messages.size()); - assertEquals("Unexpected number of messages received on second browser",10,messages2.size()); - - for(int i = 0 ; i < 10; i++) - { - Message msg = messages.get(i); - assertEquals("Unexpected message number received on first browser", MSG_COUNT - 10 + i, msg.getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY)); - msg = messages2.get(i); - assertEquals("Unexpected message number received on second browser", MSG_COUNT - 10 + i, msg.getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY)); - } - - - _producer.close(); - _producerSession.close(); - _producerConnection.close(); - } - - public void testParallelProductionAndConsumption() throws Exception - { - createConflationQueue(_producerSession); - - // Start producing threads that send messages - BackgroundMessageProducer messageProducer1 = new BackgroundMessageProducer("Message sender1"); - messageProducer1.startSendingMessages(); - BackgroundMessageProducer messageProducer2 = new BackgroundMessageProducer("Message sender2"); - messageProducer2.startSendingMessages(); - - Map lastReceivedMessages = receiveMessages(messageProducer1); - - messageProducer1.join(); - messageProducer2.join(); - - final Map lastSentMessages1 = messageProducer1.getMessageSequenceNumbersByKey(); - assertEquals("Unexpected number of last sent messages sent by producer1", 2, lastSentMessages1.size()); - final Map lastSentMessages2 = messageProducer2.getMessageSequenceNumbersByKey(); - assertEquals(lastSentMessages1, lastSentMessages2); - - assertEquals("The last message sent for each key should match the last message received for that key", - lastSentMessages1, lastReceivedMessages); - - assertNull("Unexpected exception from background producer thread", messageProducer1.getException()); - } - - private Map receiveMessages(BackgroundMessageProducer producer) throws Exception - { - producer.waitUntilQuarterOfMessagesSentToEncourageConflation(); - - _consumerConnection = getConnection(); - int smallPrefetchToEncourageConflation = 1; - _consumerSession = ((AMQConnection)_consumerConnection).createSession(false, Session.AUTO_ACKNOWLEDGE, smallPrefetchToEncourageConflation); - - LOGGER.info("Starting to receive"); - - _consumer = _consumerSession.createConsumer(_queue); - _consumerConnection.start(); - - Map messageSequenceNumbersByKey = new HashMap(); - - Message message; - int numberOfShutdownsReceived = 0; - int numberOfMessagesReceived = 0; - while(numberOfShutdownsReceived < 2) - { - message = _consumer.receive(10000); - assertNotNull(message); - - if (message.propertyExists(BackgroundMessageProducer.SHUTDOWN)) - { - numberOfShutdownsReceived++; - } - else - { - numberOfMessagesReceived++; - putMessageInMap(message, messageSequenceNumbersByKey); - } - } - - LOGGER.info("Finished receiving. Received " + numberOfMessagesReceived + " message(s) in total"); - - return messageSequenceNumbersByKey; - } - - private void putMessageInMap(Message message, Map messageSequenceNumbersByKey) throws JMSException - { - String keyValue = message.getStringProperty(KEY_PROPERTY); - Integer messageSequenceNumber = message.getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY); - messageSequenceNumbersByKey.put(keyValue, messageSequenceNumber); - } - - private class BackgroundMessageProducer - { - static final String SHUTDOWN = "SHUTDOWN"; - - private final String _threadName; - - private volatile Exception _exception; - - private Thread _thread; - private Map _messageSequenceNumbersByKey = new HashMap(); - private CountDownLatch _quarterOfMessagesSentLatch = new CountDownLatch(MSG_COUNT/4); - - public BackgroundMessageProducer(String threadName) - { - _threadName = threadName; - } - - public void waitUntilQuarterOfMessagesSentToEncourageConflation() throws InterruptedException - { - final long latchTimeout = 60000; - boolean success = _quarterOfMessagesSentLatch.await(latchTimeout, TimeUnit.MILLISECONDS); - assertTrue("Failed to be notified that 1/4 of the messages have been sent within " + latchTimeout + " ms.", success); - LOGGER.info("Quarter of messages sent"); - } - - public Exception getException() - { - return _exception; - } - - public Map getMessageSequenceNumbersByKey() - { - return Collections.unmodifiableMap(_messageSequenceNumbersByKey); - } - - public void startSendingMessages() - { - Runnable messageSender = new Runnable() - { - @Override - public void run() - { - try - { - LOGGER.info("Starting to send in background thread"); - Connection producerConnection = getConnection(); - Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - MessageProducer backgroundProducer = producerSession.createProducer(_queue); - for (int messageNumber = 0; messageNumber < MSG_COUNT; messageNumber++) - { - Message message = nextMessage(messageNumber, producerSession, 2); - backgroundProducer.send(message); - - putMessageInMap(message, _messageSequenceNumbersByKey); - _quarterOfMessagesSentLatch.countDown(); - } - - Message shutdownMessage = producerSession.createMessage(); - shutdownMessage.setBooleanProperty(SHUTDOWN, true); - backgroundProducer.send(shutdownMessage); - - LOGGER.info("Finished sending in background thread"); - } - catch (Exception e) - { - _exception = e; - throw new RuntimeException(e); - } - } - }; - - _thread = new Thread(messageSender); - _thread.setName(_threadName); - _thread.start(); - } - - public void join() throws InterruptedException - { - final int timeoutInMillis = 120000; - _thread.join(timeoutInMillis); - assertFalse("Expected producer thread to finish within " + timeoutInMillis + "ms", _thread.isAlive()); - } - } - - private void createConflationQueue(Session session) throws AMQException - { - final Map arguments = new HashMap(); - arguments.put("qpid.last_value_queue_key",KEY_PROPERTY); - ((AMQSession) session).createQueue(new AMQShortString(_queueName), false, true, false, arguments); - _queue = new AMQQueue("amq.direct", _queueName); - ((AMQSession) session).declareAndBind((AMQDestination)_queue); - } - - private Message nextMessage(int msg, Session producerSession) throws JMSException - { - return nextMessage(msg, producerSession, 10); - } - - private Message nextMessage(int msg, Session producerSession, int numberOfUniqueKeyValues) throws JMSException - { - Message send = producerSession.createTextMessage("Message: " + msg); - - send.setStringProperty(KEY_PROPERTY, String.valueOf(msg % numberOfUniqueKeyValues)); - send.setIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY, msg); - - return send; - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/MessageGroupQueueTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/MessageGroupQueueTest.java deleted file mode 100644 index cb8ced4ddb..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/MessageGroupQueueTest.java +++ /dev/null @@ -1,604 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.server.queue; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.jms.Connection; -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 org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.jms.ConnectionURL; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class MessageGroupQueueTest extends QpidBrokerTestCase -{ - protected final String QUEUE = "MessageGroupQueue"; - - private Connection producerConnection; - private MessageProducer producer; - private Session producerSession; - private Queue queue; - private Connection consumerConnection; - - - protected void setUp() throws Exception - { - super.setUp(); - - producerConnection = getConnection(); - producerSession = producerConnection.createSession(true, Session.AUTO_ACKNOWLEDGE); - - producerConnection.start(); - - consumerConnection = getConnection(); - - } - - protected void tearDown() throws Exception - { - producerConnection.close(); - consumerConnection.close(); - super.tearDown(); - } - - - public void testSimpleGroupAssignment() throws Exception - { - simpleGroupAssignment(false); - } - - public void testSharedGroupSimpleGroupAssignment() throws Exception - { - simpleGroupAssignment(true); - } - - - /** - * Pre populate the queue with messages with groups as follows - * - * ONE - * TWO - * ONE - * TWO - * - * Create two consumers with prefetch of 1, the first consumer should then be assigned group ONE, the second - * consumer assigned group TWO if they are started in sequence. - * - * Thus doing - * - * c1 <--- (ONE) - * c2 <--- (TWO) - * c2 ack ---> - * - * c2 should now be able to receive a second message from group TWO (skipping over the message from group ONE) - * - * i.e. - * - * c2 <--- (TWO) - * c2 ack ---> - * c1 <--- (ONE) - * c1 ack ---> - * - */ - private void simpleGroupAssignment(boolean sharedGroups) throws AMQException, JMSException - { - final Map arguments = new HashMap(); - arguments.put(QueueArgumentsConverter.QPID_GROUP_HEADER_KEY,"group"); - if(sharedGroups) - { - arguments.put(QueueArgumentsConverter.QPID_SHARED_MSG_GROUP,"1"); - } - ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments); - queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'"); - - ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); - producer = producerSession.createProducer(queue); - - String[] groups = { "ONE", "TWO"}; - - for (int msg = 0; msg < 4; msg++) - { - producer.send(createMessage(msg, groups[msg % groups.length])); - } - producerSession.commit(); - producer.close(); - producerSession.close(); - producerConnection.close(); - - Session cs1 = ((AMQConnection)consumerConnection).createSession(false, Session.CLIENT_ACKNOWLEDGE,1); - Session cs2 = ((AMQConnection)consumerConnection).createSession(false, Session.CLIENT_ACKNOWLEDGE,1); - - - MessageConsumer consumer1 = cs1.createConsumer(queue); - MessageConsumer consumer2 = cs2.createConsumer(queue); - - consumerConnection.start(); - Message cs1Received = consumer1.receive(1000); - assertNotNull("Consumer 1 should have received first message", cs1Received); - - Message cs2Received = consumer2.receive(1000); - - assertNotNull("Consumer 2 should have received first message", cs2Received); - - cs2Received.acknowledge(); - - Message cs2Received2 = consumer2.receive(1000); - - assertNotNull("Consumer 2 should have received second message", cs2Received2); - assertEquals("Differing groups", cs2Received2.getStringProperty("group"), - cs2Received.getStringProperty("group")); - - cs1Received.acknowledge(); - Message cs1Received2 = consumer1.receive(1000); - - assertNotNull("Consumer 1 should have received second message", cs1Received2); - assertEquals("Differing groups", cs1Received2.getStringProperty("group"), - cs1Received.getStringProperty("group")); - - cs1Received2.acknowledge(); - cs2Received2.acknowledge(); - - assertNull(consumer1.receive(1000)); - assertNull(consumer2.receive(1000)); - } - - - public void testConsumerCloseGroupAssignment() throws Exception - { - consumerCloseGroupAssignment(false); - } - - public void testSharedGroupConsumerCloseGroupAssignment() throws Exception - { - consumerCloseGroupAssignment(true); - } - - /** - * - * Tests that upon closing a consumer, groups previously assigned to that consumer are reassigned to a different - * consumer. - * - * Pre-populate the queue as ONE, ONE, TWO, ONE - * - * create in sequence two consumers - * - * receive first from c1 then c2 (thus ONE is assigned to c1, TWO to c2) - * - * Then close c1 before acking. - * - * If we now attempt to receive from c2, then the remaining messages in group ONE should be available (which - * requires c2 to go "backwards" in the queue). - * - **/ - private void consumerCloseGroupAssignment(boolean sharedGroups) throws AMQException, JMSException - { - final Map arguments = new HashMap(); - arguments.put(QueueArgumentsConverter.QPID_GROUP_HEADER_KEY,"group"); - if(sharedGroups) - { - arguments.put(QueueArgumentsConverter.QPID_SHARED_MSG_GROUP,"1"); - } - ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments); - queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'"); - - ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); - producer = producerSession.createProducer(queue); - - producer.send(createMessage(1, "ONE")); - producer.send(createMessage(2, "ONE")); - producer.send(createMessage(3, "TWO")); - producer.send(createMessage(4, "ONE")); - - producerSession.commit(); - producer.close(); - producerSession.close(); - producerConnection.close(); - - Session cs1 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1); - Session cs2 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1); - - MessageConsumer consumer1 = cs1.createConsumer(queue); - - consumerConnection.start(); - MessageConsumer consumer2 = cs2.createConsumer(queue); - - Message cs1Received = consumer1.receive(1000); - assertNotNull("Consumer 1 should have received first message", cs1Received); - assertEquals("incorrect message received", 1, cs1Received.getIntProperty("msg")); - - Message cs2Received = consumer2.receive(1000); - - assertNotNull("Consumer 2 should have received first message", cs2Received); - assertEquals("incorrect message received", 3, cs2Received.getIntProperty("msg")); - cs2.commit(); - - Message cs2Received2 = consumer2.receive(1000); - - assertNull("Consumer 2 should not yet have received a second message", cs2Received2); - - consumer1.close(); - - cs1.commit(); - Message cs2Received3 = consumer2.receive(1000); - - assertNotNull("Consumer 2 should have received second message", cs2Received3); - assertEquals("Unexpected group", "ONE", cs2Received3.getStringProperty("group")); - assertEquals("incorrect message received", 2, cs2Received3.getIntProperty("msg")); - - cs2.commit(); - - - Message cs2Received4 = consumer2.receive(1000); - - assertNotNull("Consumer 2 should have received third message", cs2Received4); - assertEquals("Unexpected group", "ONE", cs2Received4.getStringProperty("group")); - assertEquals("incorrect message received", 4, cs2Received4.getIntProperty("msg")); - cs2.commit(); - - assertNull(consumer2.receive(1000)); - } - - - - - public void testConsumerCloseWithRelease() throws Exception - { - consumerCloseWithRelease(false); - } - - public void testSharedGroupConsumerCloseWithRelease() throws Exception - { - consumerCloseWithRelease(true); - } - - - /** - * - * Tests that upon closing a consumer and its session, groups previously assigned to that consumer are reassigned - * toa different consumer, including messages which were previously delivered but have now been released. - * - * Pre-populate the queue as ONE, ONE, TWO, ONE - * - * create in sequence two consumers - * - * receive first from c1 then c2 (thus ONE is assigned to c1, TWO to c2) - * - * Then close c1 and its session without acking. - * - * If we now attempt to receive from c2, then the all messages in group ONE should be available (which - * requires c2 to go "backwards" in the queue). The first such message should be marked as redelivered - * - */ - private void consumerCloseWithRelease(boolean sharedGroups) throws AMQException, JMSException - { - final Map arguments = new HashMap(); - arguments.put(QueueArgumentsConverter.QPID_GROUP_HEADER_KEY,"group"); - if(sharedGroups) - { - arguments.put(QueueArgumentsConverter.QPID_SHARED_MSG_GROUP,"1"); - } - - ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments); - queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'"); - - ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); - producer = producerSession.createProducer(queue); - - producer.send(createMessage(1, "ONE")); - producer.send(createMessage(2, "ONE")); - producer.send(createMessage(3, "TWO")); - producer.send(createMessage(4, "ONE")); - - producerSession.commit(); - producer.close(); - producerSession.close(); - producerConnection.close(); - - Session cs1 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1); - Session cs2 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1); - - - MessageConsumer consumer1 = cs1.createConsumer(queue); - - consumerConnection.start(); - - MessageConsumer consumer2 = cs2.createConsumer(queue); - - Message cs1Received = consumer1.receive(1000); - assertNotNull("Consumer 1 should have received its first message", cs1Received); - assertEquals("incorrect message received", 1, cs1Received.getIntProperty("msg")); - - Message received = consumer2.receive(1000); - - assertNotNull("Consumer 2 should have received its first message", received); - assertEquals("incorrect message received", 3, received.getIntProperty("msg")); - - received = consumer2.receive(1000); - - assertNull("Consumer 2 should not yet have received second message", received); - - consumer1.close(); - cs1.close(); - cs2.commit(); - received = consumer2.receive(1000); - - assertNotNull("Consumer 2 should now have received second message", received); - assertEquals("Unexpected group", "ONE", received.getStringProperty("group")); - assertEquals("incorrect message received", 1, received.getIntProperty("msg")); - assertTrue("Expected second message to be marked as redelivered " + received.getIntProperty("msg"), - received.getJMSRedelivered()); - - cs2.commit(); - - - received = consumer2.receive(1000); - - assertNotNull("Consumer 2 should have received a third message", received); - assertEquals("Unexpected group", "ONE", received.getStringProperty("group")); - assertEquals("incorrect message received", 2, received.getIntProperty("msg")); - - cs2.commit(); - - received = consumer2.receive(1000); - - assertNotNull("Consumer 2 should have received a fourth message", received); - assertEquals("Unexpected group", "ONE", received.getStringProperty("group")); - assertEquals("incorrect message received", 4, received.getIntProperty("msg")); - - cs2.commit(); - - - assertNull(consumer2.receive(1000)); - } - - public void testGroupAssignmentSurvivesEmpty() throws JMSException, AMQException - { - groupAssignmentOnEmpty(false); - } - - public void testSharedGroupAssignmentDoesNotSurviveEmpty() throws JMSException, AMQException - { - groupAssignmentOnEmpty(true); - } - - private void groupAssignmentOnEmpty(boolean sharedGroups) throws AMQException, JMSException - { - final Map arguments = new HashMap(); - arguments.put(QueueArgumentsConverter.QPID_GROUP_HEADER_KEY,"group"); - if(sharedGroups) - { - arguments.put(QueueArgumentsConverter.QPID_SHARED_MSG_GROUP,"1"); - } - - ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments); - queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'"); - - ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); - producer = producerSession.createProducer(queue); - - producer.send(createMessage(1, "ONE")); - producer.send(createMessage(2, "TWO")); - producer.send(createMessage(3, "THREE")); - producer.send(createMessage(4, "ONE")); - - producerSession.commit(); - producer.close(); - producerSession.close(); - producerConnection.close(); - - Session cs1 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1); - Session cs2 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1); - - - MessageConsumer consumer1 = cs1.createConsumer(queue); - - consumerConnection.start(); - - MessageConsumer consumer2 = cs2.createConsumer(queue); - - Message received = consumer1.receive(1000); - assertNotNull("Consumer 1 should have received its first message", received); - assertEquals("incorrect message received", 1, received.getIntProperty("msg")); - - received = consumer2.receive(1000); - - assertNotNull("Consumer 2 should have received its first message", received); - assertEquals("incorrect message received", 2, received.getIntProperty("msg")); - - cs1.commit(); - - received = consumer1.receive(1000); - assertNotNull("Consumer 1 should have received its second message", received); - assertEquals("incorrect message received", 3, received.getIntProperty("msg")); - - // We expect different behaviours from "shared groups": here the assignment of a subscription to a group - // is terminated when there are no outstanding delivered but unacknowledged messages. In contrast, with a - // standard message grouping queue the assignment will be retained until the subscription is no longer - // registered - if(sharedGroups) - { - cs2.commit(); - received = consumer2.receive(1000); - - assertNotNull("Consumer 2 should have received its second message", received); - assertEquals("incorrect message received", 4, received.getIntProperty("msg")); - - cs2.commit(); - } - else - { - cs2.commit(); - received = consumer2.receive(1000); - - assertNull("Consumer 2 should not have received a second message", received); - - cs1.commit(); - - received = consumer1.receive(1000); - assertNotNull("Consumer 1 should have received its third message", received); - assertEquals("incorrect message received", 4, received.getIntProperty("msg")); - - } - - } - - private Message createMessage(int msg, String group) throws JMSException - { - Message send = producerSession.createTextMessage("Message: " + msg); - send.setIntProperty("msg", msg); - send.setStringProperty("group", group); - - return send; - } - - /** - * Tests that when a number of new messages for a given groupid are arriving while the delivery group - * state is also in the process of being emptied (due to acking a message while using prefetch=1), that only - * 1 of a number of existing consumers is ever receiving messages for the shared group at a time. - */ - public void testSingleSharedGroupWithMultipleConsumers() throws Exception - { - final Map arguments = new HashMap(); - arguments.put(QueueArgumentsConverter.QPID_GROUP_HEADER_KEY,"group"); - arguments.put(QueueArgumentsConverter.QPID_SHARED_MSG_GROUP,"1"); - - ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments); - queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'"); - - ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); - producer = producerSession.createProducer(queue); - - - consumerConnection.close(); - Map options = new HashMap(); - options.put(ConnectionURL.OPTIONS_MAXPREFETCH, "1"); - consumerConnection = getConnectionWithOptions(options); - - int numMessages = 100; - SharedGroupTestMessageListener groupingTestMessageListener = new SharedGroupTestMessageListener(numMessages); - - Session cs1 = ((AMQConnection)consumerConnection).createSession(false, Session.AUTO_ACKNOWLEDGE); - Session cs2 = ((AMQConnection)consumerConnection).createSession(false, Session.AUTO_ACKNOWLEDGE); - Session cs3 = ((AMQConnection)consumerConnection).createSession(false, Session.AUTO_ACKNOWLEDGE); - Session cs4 = ((AMQConnection)consumerConnection).createSession(false, Session.AUTO_ACKNOWLEDGE); - - MessageConsumer consumer1 = cs1.createConsumer(queue); - consumer1.setMessageListener(groupingTestMessageListener); - MessageConsumer consumer2 = cs2.createConsumer(queue); - consumer2.setMessageListener(groupingTestMessageListener); - MessageConsumer consumer3 = cs3.createConsumer(queue); - consumer3.setMessageListener(groupingTestMessageListener); - MessageConsumer consumer4 = cs4.createConsumer(queue); - consumer4.setMessageListener(groupingTestMessageListener); - consumerConnection.start(); - - for(int i = 1; i <= numMessages; i++) - { - producer.send(createMessage(i, "GROUP")); - } - producerSession.commit(); - producer.close(); - producerSession.close(); - producerConnection.close(); - - assertTrue("Mesages not all recieved in the allowed timeframe", groupingTestMessageListener.waitForLatch(30)); - assertEquals("Unexpected concurrent processing of messages for the group", 0, groupingTestMessageListener.getConcurrentProcessingCases()); - assertNull("Unexpecte throwable in message listeners", groupingTestMessageListener.getThrowable()); - } - - public static class SharedGroupTestMessageListener implements MessageListener - { - private final CountDownLatch _count; - private final AtomicInteger _activeListeners = new AtomicInteger(); - private final AtomicInteger _concurrentProcessingCases = new AtomicInteger(); - private Throwable _throwable; - - public SharedGroupTestMessageListener(int numMessages) - { - _count = new CountDownLatch(numMessages); - } - - public void onMessage(Message message) - { - try - { - int currentActiveListeners = _activeListeners.incrementAndGet(); - - if (currentActiveListeners > 1) - { - _concurrentProcessingCases.incrementAndGet(); - - System.err.println("Concurrent processing when handling message: " + message.getIntProperty("msg")); - } - - try - { - Thread.sleep(25); - } - catch (InterruptedException e) - { - Thread.currentThread().interrupt(); - } - - _activeListeners.decrementAndGet(); - } - catch (Throwable t) - { - _throwable = t; - t.printStackTrace(); - } - finally - { - _count.countDown(); - } - } - - public boolean waitForLatch(int seconds) throws Exception - { - return _count.await(seconds, TimeUnit.SECONDS); - } - - public int getConcurrentProcessingCases() - { - return _concurrentProcessingCases.get(); - } - - public Throwable getThrowable() - { - return _throwable; - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java deleted file mode 100644 index c6b2c9e95c..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java +++ /dev/null @@ -1,342 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.management.common.mbeans.ManagedBroker; -import org.apache.qpid.management.common.mbeans.ManagedQueue; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Session; -import javax.management.JMException; -import javax.management.MBeanException; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.UndeclaredThrowableException; - -/** - * This Test validates the Queue Model on the broker. - * Currently it has some basic queue creation / deletion tests. - * However, it should be expanded to include other tests that relate to the - * model. i.e. - * - * The Create and Delete tests should ensure that the requisite logging is - * performed. - * - * Additions to this suite would be to complete testing of creations, validating - * fields such as owner/exclusive, autodelete and priority are correctly set. - * - * Currently this test uses the JMX interface to validate that the queue has - * been declared as expected so these tests cannot run against a CPP broker. - * - * - * Tests should ensure that they clean up after themselves. - * e,g. Durable queue creation test should perform a queue delete. - */ -public class ModelTest extends QpidBrokerTestCase -{ - - private JMXTestUtils _jmxUtils; - private static final String VIRTUALHOST_NAME = "test"; - - @Override - public void setUp() throws Exception - { - getBrokerConfiguration().addJmxManagementConfiguration(); - - // Create a JMX Helper - _jmxUtils = new JMXTestUtils(this); - super.setUp(); - - // Open the JMX Connection - _jmxUtils.open(); - } - - @Override - public void tearDown() throws Exception - { - // Close the JMX Connection - _jmxUtils.close(); - super.tearDown(); - } - - /** - * Test that an exclusive transient queue can be created via AMQP. - * - * @throws Exception On unexpected error - */ - public void testExclusiveQueueCreationTransientViaAMQP() throws Exception - { - Connection connection = getConnection(); - - String queueName = getTestQueueName(); - boolean durable = false; - boolean autoDelete = false; - boolean exclusive = true; - - createViaAMQPandValidateViaJMX(connection, queueName, durable, - autoDelete, exclusive); - } - - - - /** - * Test that a transient queue can be created via AMQP. - * - * @throws Exception On unexpected error - */ - public void testQueueCreationTransientViaAMQP() throws Exception - { - Connection connection = getConnection(); - - String queueName = getTestQueueName(); - boolean durable = false; - boolean autoDelete = false; - boolean exclusive = true; - - createViaAMQPandValidateViaJMX(connection, queueName, durable, - autoDelete, exclusive); - } - - /** - * Test that a durable exclusive queue can be created via AMQP. - * - * @throws Exception On unexpected error - */ - - public void testExclusiveQueueCreationDurableViaAMQP() throws Exception - { - Connection connection = getConnection(); - - String queueName = getTestQueueName(); - boolean durable = true; - boolean autoDelete = false; - boolean exclusive = true; - - createViaAMQPandValidateViaJMX(connection, queueName, durable, - autoDelete, exclusive); - - // Clean up - ManagedBroker managedBroker = - _jmxUtils.getManagedBroker(VIRTUALHOST_NAME); - managedBroker.deleteQueue(queueName); - } - - /** - * Test that a durable queue can be created via AMQP. - * - * @throws Exception On unexpected error - */ - - public void testQueueCreationDurableViaAMQP() throws Exception - { - Connection connection = getConnection(); - - String queueName = getTestQueueName(); - boolean durable = true; - boolean autoDelete = false; - boolean exclusive = false; - - createViaAMQPandValidateViaJMX(connection, queueName, durable, - autoDelete, exclusive); - - // Clean up - ManagedBroker managedBroker = - _jmxUtils.getManagedBroker(VIRTUALHOST_NAME); - managedBroker.deleteQueue(queueName); - } - - - /** - * Test that a transient queue can be created via JMX. - * - * @throws IOException if there is a problem via the JMX connection - * @throws javax.management.JMException if there is a problem with the JMX command - */ - public void testCreationTransientViaJMX() throws IOException, JMException - { - String name = getName(); - String owner = null; - boolean durable = false; - - createViaJMXandValidateViaJMX(name, owner, durable); - } - - /** - * Test that a durable queue can be created via JMX. - * - * @throws IOException if there is a problem via the JMX connection - * @throws javax.management.JMException if there is a problem with the JMX command - */ - public void testCreationDurableViaJMX() throws IOException, JMException - { - String name = getName(); - String owner = null; - boolean durable = true; - - createViaJMXandValidateViaJMX(name, owner, durable); - - // Clean up - ManagedBroker managedBroker = - _jmxUtils.getManagedBroker(VIRTUALHOST_NAME); - managedBroker.deleteQueue(name); - } - - /** - * Test that a transient queue can be deleted via JMX. - * - * @throws IOException if there is a problem via the JMX connection - * @throws javax.management.JMException if there is a problem with the JMX command - */ - public void testDeletionTransientViaJMX() throws IOException, JMException - { - String name = getName(); - - _jmxUtils.createQueue(VIRTUALHOST_NAME, name, null, false); - - ManagedBroker managedBroker = _jmxUtils. - getManagedBroker(VIRTUALHOST_NAME); - - try - { - managedBroker.deleteQueue(name); - } - catch (UndeclaredThrowableException e) - { - fail(((MBeanException) ((InvocationTargetException) - e.getUndeclaredThrowable()).getTargetException()).getTargetException().getMessage()); - } - } - - /** - * Test that a durable queue can be created via JMX. - * - * @throws IOException if there is a problem via the JMX connection - * @throws javax.management.JMException if there is a problem with the JMX command - */ - public void testDeletionDurableViaJMX() throws IOException, JMException - { - String name = getName(); - - _jmxUtils.createQueue(VIRTUALHOST_NAME, name, null, true); - - ManagedBroker managedBroker = _jmxUtils. - getManagedBroker(VIRTUALHOST_NAME); - - try - { - managedBroker.deleteQueue(name); - } - catch (UndeclaredThrowableException e) - { - fail(((MBeanException) ((InvocationTargetException) - e.getUndeclaredThrowable()).getTargetException()).getTargetException().getMessage()); - } - } - - /* - * Helper Methods - */ - - /** - * Using the provided JMS Connection create a queue using the AMQP extension - * with the given properties and then validate it was created correctly via - * the JMX Connection - * - * @param connection Qpid JMS Connection - * @param queueName String the desired QueueName - * @param durable boolean if the queue should be durable - * @param autoDelete boolean if the queue is an autoDelete queue - * @param exclusive boolean if the queue is exclusive - * - * @throws AMQException if there is a problem with the createQueue call - * @throws JMException if there is a problem with the JMX validatation - * @throws IOException if there is a problem with the JMX connection - * @throws JMSException if there is a problem creating the JMS Session - */ - private void createViaAMQPandValidateViaJMX(Connection connection, - String queueName, - boolean durable, - boolean autoDelete, - boolean exclusive) - throws AMQException, JMException, IOException, JMSException - { - AMQSession session = (AMQSession) connection.createSession(false, - Session.AUTO_ACKNOWLEDGE); - - session.createQueue(new AMQShortString(queueName), - autoDelete, durable, exclusive); - - validateQueueViaJMX(queueName, (exclusive && durable &&!isBroker010()) ? connection.getClientID() : null, durable, autoDelete || (exclusive && !isBroker010() && !durable)); - } - - /** - * Use the JMX Helper to create a queue with the given properties and then - * validate it was created correctly via the JMX Connection - * - * @param queueName String the desired QueueName - * @param owner String the owner value that should be set - * @param durable boolean if the queue should be durable - * @param autoDelete boolean if the queue is an autoDelete queue - * - * @throws JMException if there is a problem with the JMX validatation - * @throws IOException if there is a problem with the JMX connection - */ - private void createViaJMXandValidateViaJMX(String queueName, String owner, - boolean durable) - throws JMException, IOException - { - _jmxUtils.createQueue(VIRTUALHOST_NAME, queueName, owner, durable); - - validateQueueViaJMX(queueName, owner, durable, false); - } - - /** - * Validate that a queue with the given properties exists on the broker - * - * @param queueName String the desired QueueName - * @param owner String the owner value that should be set - * @param durable boolean if the queue should be durable - * @param autoDelete boolean if the queue is an autoDelete queue - * - * @throws JMException if there is a problem with the JMX validatation - * @throws IOException if there is a problem with the JMX connection - */ - private void validateQueueViaJMX(String queueName, String owner, boolean durable, boolean autoDelete) - throws JMException, IOException - { - ManagedQueue managedQueue = _jmxUtils. - getManagedObject(ManagedQueue.class, - _jmxUtils.getQueueObjectName(VIRTUALHOST_NAME, - queueName)); - - assertEquals(queueName, managedQueue.getName()); - assertEquals(owner, managedQueue.getOwner()); - assertEquals(durable, managedQueue.isDurable()); - assertEquals(autoDelete, managedQueue.isAutoDelete()); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/MultipleTransactedBatchProducerTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/MultipleTransactedBatchProducerTest.java deleted file mode 100644 index cbf4e032db..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/MultipleTransactedBatchProducerTest.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.log4j.Logger; - -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageListener; -import javax.jms.Session; - -import java.util.Random; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -public class MultipleTransactedBatchProducerTest extends QpidBrokerTestCase -{ - private static final Logger _logger = Logger.getLogger(MultipleTransactedBatchProducerTest.class); - - private static final int MESSAGE_COUNT = 1000; - private static final int BATCH_SIZE = 50; - private static final int NUM_PRODUCERS = 2; - private static final int NUM_CONSUMERS = 3; - private static final Random RANDOM = new Random(); - - private CountDownLatch _receivedLatch; - private String _queueName; - - private volatile String _failMsg; - - public void setUp() throws Exception - { - //debug level logging often makes this test pass artificially, turn the level down to info. - setSystemProperty("amqj.server.logging.level", "INFO"); - _receivedLatch = new CountDownLatch(MESSAGE_COUNT * NUM_PRODUCERS); - - getBrokerConfiguration().addJmxManagementConfiguration(); - - super.setUp(); - _queueName = getTestQueueName(); - _failMsg = null; - } - - /** - * When there are multiple producers submitting batches of messages to a given - * queue using transacted sessions, it is highly probable that concurrent - * enqueue() activity will occur and attempt delivery of their message to the - * same subscription. In this scenario it is likely that one of the attempts - * will succeed and the other will result in use of the deliverAsync() method - * to start a queue Runner and ensure delivery of the message. - * - * A defect within the processQueue() method used by the Runner would mean that - * delivery of these messages may not occur, should the Runner stop before all - * messages have been processed. Such a defect was discovered and found to be - * most visible when Selectors are used such that one and only one subscription - * can/will accept any given message, but multiple subscriptions are present, - * and one of the earlier subscriptions receives more messages than the others. - * - * This test is to validate that the processQueue() method is able to correctly - * deliver all of the messages present for asynchronous delivery to subscriptions, - * by utilising multiple batch transacted producers to create the scenario and - * ensure all messages are received by a consumer. - */ - public void testMultipleBatchedProducersWithMultipleConsumersUsingSelectors() throws Exception - { - String selector1 = ("(\"" + _queueName +"\" % " + NUM_CONSUMERS + ") = 0"); - String selector2 = ("(\"" + _queueName +"\" % " + NUM_CONSUMERS + ") = 1"); - String selector3 = ("(\"" + _queueName +"\" % " + NUM_CONSUMERS + ") = 2"); - - //create consumers - Connection conn1 = getConnection(); - conn1.setExceptionListener(new ExceptionHandler("conn1")); - Session sess1 = conn1.createSession(true, Session.SESSION_TRANSACTED); - MessageConsumer cons1 = sess1.createConsumer(sess1.createQueue(_queueName), selector1); - cons1.setMessageListener(new Cons(sess1,"consumer1")); - - Connection conn2 = getConnection(); - conn2.setExceptionListener(new ExceptionHandler("conn2")); - Session sess2 = conn2.createSession(true, Session.SESSION_TRANSACTED); - MessageConsumer cons2 = sess2.createConsumer(sess2.createQueue(_queueName), selector2); - cons2.setMessageListener(new Cons(sess2,"consumer2")); - - Connection conn3 = getConnection(); - conn3.setExceptionListener(new ExceptionHandler("conn3")); - Session sess3 = conn3.createSession(true, Session.SESSION_TRANSACTED); - MessageConsumer cons3 = sess3.createConsumer(sess3.createQueue(_queueName), selector3); - cons3.setMessageListener(new Cons(sess3,"consumer3")); - - conn1.start(); - conn2.start(); - conn3.start(); - - //create producers - Connection connA = getConnection(); - connA.setExceptionListener(new ExceptionHandler("connA")); - Connection connB = getConnection(); - connB.setExceptionListener(new ExceptionHandler("connB")); - Thread producer1 = new Thread(new ProducerThread(connA, _queueName, "producer1")); - Thread producer2 = new Thread(new ProducerThread(connB, _queueName, "producer2")); - - producer1.start(); - Thread.sleep(10); - producer2.start(); - - //await delivery of the messages - int timeout = isBrokerStorePersistent() ? 300 : 75; - boolean result = _receivedLatch.await(timeout, TimeUnit.SECONDS); - - assertNull("Test failed because: " + String.valueOf(_failMsg), _failMsg); - assertTrue("Some of the messages were not all recieved in the given timeframe, remaining count was: "+_receivedLatch.getCount(), - result); - - } - - @Override - public Message createNextMessage(Session session, int msgCount) throws JMSException - { - Message message = super.createNextMessage(session,msgCount); - - //bias at least 50% of the messages to the first consumers selector because - //the issue presents itself primarily when an earlier subscription completes - //delivery after the later subscriptions - int val; - if (msgCount % 2 == 0) - { - val = 0; - } - else - { - val = RANDOM.nextInt(Integer.MAX_VALUE); - } - - message.setIntProperty(_queueName, val); - - return message; - } - - private class Cons implements MessageListener - { - private Session _sess; - private String _desc; - - public Cons(Session sess, String desc) - { - _sess = sess; - _desc = desc; - } - - public void onMessage(Message message) - { - _receivedLatch.countDown(); - int msgCount = 0; - int msgID = 0; - try - { - msgCount = message.getIntProperty(INDEX); - msgID = message.getIntProperty(_queueName); - } - catch (JMSException e) - { - _logger.error(_desc + " received exception: " + e.getMessage(), e); - failAsyncTest(e.getMessage()); - } - - _logger.info("Consumer received message:"+ msgCount + " with ID: " + msgID); - - try - { - _sess.commit(); - } - catch (JMSException e) - { - _logger.error(_desc + " received exception: " + e.getMessage(), e); - failAsyncTest(e.getMessage()); - } - } - } - - private class ProducerThread implements Runnable - { - private Connection _conn; - private String _dest; - private String _desc; - - public ProducerThread(Connection conn, String dest, String desc) - { - _conn = conn; - _dest = dest; - _desc = desc; - } - - public void run() - { - try - { - Session session = _conn.createSession(true, Session.SESSION_TRANSACTED); - sendMessage(session, session.createQueue(_dest), MESSAGE_COUNT, BATCH_SIZE); - } - catch (Exception e) - { - _logger.error(_desc + " received exception: " + e.getMessage(), e); - failAsyncTest(e.getMessage()); - } - } - } - - private class ExceptionHandler implements javax.jms.ExceptionListener - { - private String _desc; - - public ExceptionHandler(String description) - { - _desc = description; - } - - public void onException(JMSException e) - { - _logger.error(_desc + " received exception: " + e.getMessage(), e); - failAsyncTest(e.getMessage()); - } - } - - private void failAsyncTest(String msg) - { - _logger.error("Failing test because: " + msg); - _failMsg = msg; - } -} \ No newline at end of file diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/PriorityQueueTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/PriorityQueueTest.java deleted file mode 100644 index 7b2dd3239d..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/PriorityQueueTest.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.server.queue; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -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.naming.NamingException; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -public class PriorityQueueTest extends QpidBrokerTestCase -{ - private static final int TIMEOUT = 1500; - - protected final String QUEUE = "PriorityQueue"; - - private static final int MSG_COUNT = 50; - - private Connection producerConnection; - private MessageProducer producer; - private Session producerSession; - private Queue queue; - private Connection consumerConnection; - private Session consumerSession; - - private MessageConsumer consumer; - - protected void setUp() throws Exception - { - super.setUp(); - - producerConnection = getConnection(); - producerSession = producerConnection.createSession(true, Session.AUTO_ACKNOWLEDGE); - - producerConnection.start(); - - consumerConnection = getConnection(); - consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - } - - protected void tearDown() throws Exception - { - producerConnection.close(); - consumerConnection.close(); - super.tearDown(); - } - - public void testPriority() throws JMSException, NamingException, AMQException - { - final Map arguments = new HashMap(); - arguments.put("x-qpid-priorities",10); - ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments); - queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'"); - - ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); - producer = producerSession.createProducer(queue); - - for (int msg = 0; msg < MSG_COUNT; msg++) - { - producer.setPriority(msg % 10); - producer.send(nextMessage(msg, false, producerSession, producer)); - } - producerSession.commit(); - producer.close(); - producerSession.close(); - producerConnection.close(); - - consumer = consumerSession.createConsumer(queue); - consumerConnection.start(); - Message received; - int receivedCount = 0; - Message previous = null; - int messageCount = 0; - while((received = consumer.receive(1000))!=null) - { - messageCount++; - if(previous != null) - { - assertTrue("Messages arrived in unexpected order " + messageCount + " " + previous.getIntProperty("msg") + " " + received.getIntProperty("msg") + " " + previous.getJMSPriority() + " " + received.getJMSPriority(), (previous.getJMSPriority() > received.getJMSPriority()) || ((previous.getJMSPriority() == received.getJMSPriority()) && previous.getIntProperty("msg") < received.getIntProperty("msg")) ); - } - - previous = received; - receivedCount++; - } - - assertEquals("Incorrect number of message received", 50, receivedCount); - } - - public void testOddOrdering() throws AMQException, JMSException - { - final Map arguments = new HashMap(); - arguments.put("x-qpid-priorities",3); - ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments); - queue = producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'"); - - ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); - producer = producerSession.createProducer(queue); - - // In order ABC - producer.setPriority(9); - producer.send(nextMessage(1, false, producerSession, producer)); - producer.setPriority(4); - producer.send(nextMessage(2, false, producerSession, producer)); - producer.setPriority(1); - producer.send(nextMessage(3, false, producerSession, producer)); - - // Out of order BAC - producer.setPriority(4); - producer.send(nextMessage(4, false, producerSession, producer)); - producer.setPriority(9); - producer.send(nextMessage(5, false, producerSession, producer)); - producer.setPriority(1); - producer.send(nextMessage(6, false, producerSession, producer)); - - // Out of order BCA - producer.setPriority(4); - producer.send(nextMessage(7, false, producerSession, producer)); - producer.setPriority(1); - producer.send(nextMessage(8, false, producerSession, producer)); - producer.setPriority(9); - producer.send(nextMessage(9, false, producerSession, producer)); - - // Reverse order CBA - producer.setPriority(1); - producer.send(nextMessage(10, false, producerSession, producer)); - producer.setPriority(4); - producer.send(nextMessage(11, false, producerSession, producer)); - producer.setPriority(9); - producer.send(nextMessage(12, false, producerSession, producer)); - producerSession.commit(); - - consumer = consumerSession.createConsumer(queue); - consumerConnection.start(); - - Message msg = consumer.receive(TIMEOUT); - assertEquals(1, msg.getIntProperty("msg")); - msg = consumer.receive(TIMEOUT); - assertEquals(5, msg.getIntProperty("msg")); - msg = consumer.receive(TIMEOUT); - assertEquals(9, msg.getIntProperty("msg")); - msg = consumer.receive(TIMEOUT); - assertEquals(12, msg.getIntProperty("msg")); - - msg = consumer.receive(TIMEOUT); - assertEquals(2, msg.getIntProperty("msg")); - msg = consumer.receive(TIMEOUT); - assertEquals(4, msg.getIntProperty("msg")); - msg = consumer.receive(TIMEOUT); - assertEquals(7, msg.getIntProperty("msg")); - msg = consumer.receive(TIMEOUT); - assertEquals(11, msg.getIntProperty("msg")); - - msg = consumer.receive(TIMEOUT); - assertEquals(3, msg.getIntProperty("msg")); - msg = consumer.receive(TIMEOUT); - assertEquals(6, msg.getIntProperty("msg")); - msg = consumer.receive(TIMEOUT); - assertEquals(8, msg.getIntProperty("msg")); - msg = consumer.receive(TIMEOUT); - assertEquals(10, msg.getIntProperty("msg")); - } - - private Message nextMessage(int msg, boolean first, Session producerSession, MessageProducer producer) throws JMSException - { - Message send = producerSession.createTextMessage("Message: " + msg); - send.setIntProperty("msg", msg); - - return send; - } - - /** - * Test that after sending an initial message with priority 0, it is able to be repeatedly reflected back to the queue using - * default priority and then consumed again, with separate transacted sessions with prefetch 1 for producer and consumer. - * - * Highlighted defect with PriorityQueues resolved in QPID-3927. - */ - public void testMessageReflectionWithPriorityIncreaseOnTransactedSessionsWithPrefetch1() throws Exception - { - setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, "1"); - Connection conn = getConnection(); - conn.start(); - assertEquals("Prefetch not reset", 1, ((AMQConnection) conn).getMaxPrefetch()); - - final Session producerSess = conn.createSession(true, Session.SESSION_TRANSACTED); - final Session consumerSess = conn.createSession(true, Session.SESSION_TRANSACTED); - - //declare a priority queue with 10 priorities - final Map arguments = new HashMap(); - arguments.put("x-qpid-priorities",10); - ((AMQSession) producerSess).createQueue(new AMQShortString(getTestQueueName()), false, true, false, arguments); - - Queue queue = producerSess.createQueue(getTestQueueName()); - - //create the consumer, producer, add message listener - CountDownLatch latch = new CountDownLatch(5); - MessageConsumer cons = producerSess.createConsumer(queue); - MessageProducer producer = producerSess.createProducer(queue); - - ReflectingMessageListener listener = new ReflectingMessageListener(producerSess,producer,consumerSess,latch); - cons.setMessageListener(listener); - - //Send low priority 0 message to kick start the asynchronous reflection process - producer.setPriority(0); - producer.send(nextMessage(1, true, producerSess, producer)); - producerSess.commit(); - - //wait for the reflection process to complete - assertTrue("Test process failed to complete in allowed time", latch.await(10, TimeUnit.SECONDS)); - assertNull("Unexpected throwable encountered", listener.getThrown()); - } - - private static class ReflectingMessageListener implements MessageListener - { - private static final Logger _logger = Logger.getLogger(PriorityQueueTest.ReflectingMessageListener.class); - - private Session _prodSess; - private Session _consSess; - private CountDownLatch _latch; - private MessageProducer _prod; - private long _origCount; - private Throwable _lastThrown; - - public ReflectingMessageListener(final Session prodSess, final MessageProducer prod, - final Session consSess, final CountDownLatch latch) - { - _latch = latch; - _origCount = _latch.getCount(); - _prodSess = prodSess; - _consSess = consSess; - _prod = prod; - } - - @Override - public void onMessage(final Message message) - { - try - { - _latch.countDown(); - long msgNum = _origCount - _latch.getCount(); - _logger.info("Received message " + msgNum + " with ID: " + message.getIntProperty("msg")); - - if(_latch.getCount() > 0) - { - //reflect the message, updating its ID and using default priority - message.clearProperties(); - message.setIntProperty("msg", (int) msgNum + 1); - _prod.setPriority(Message.DEFAULT_PRIORITY); - _prod.send(message); - _prodSess.commit(); - } - - //commit the consumer session to consume the message - _consSess.commit(); - } - catch(Throwable t) - { - _logger.error(t.getMessage(), t); - _lastThrown = t; - } - } - - public Throwable getThrown() - { - return _lastThrown; - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java deleted file mode 100644 index 427508954d..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java +++ /dev/null @@ -1,494 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.server.queue; - -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.jms.BytesMessage; -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.Session; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.management.common.mbeans.ManagedQueue; -import org.apache.qpid.server.logging.AbstractTestLogging; -import org.apache.qpid.test.utils.JMXTestUtils; - -public class ProducerFlowControlTest extends AbstractTestLogging -{ - private static final Logger _logger = Logger.getLogger(ProducerFlowControlTest.class); - - private static final int TIMEOUT = 10000; - - private Connection producerConnection; - private Connection consumerConnection; - private Session producerSession; - private Session consumerSession; - private MessageProducer producer; - private MessageConsumer consumer; - private Queue queue; - - private final AtomicInteger _sentMessages = new AtomicInteger(0); - - private JMXTestUtils _jmxUtils; - private boolean _jmxUtilConnected; - - public void setUp() throws Exception - { - getBrokerConfiguration().addJmxManagementConfiguration(); - - _jmxUtils = new JMXTestUtils(this); - _jmxUtilConnected=false; - super.setUp(); - - _monitor.markDiscardPoint(); - - producerConnection = getConnection(); - producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - producerConnection.start(); - - consumerConnection = getConnection(); - consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - } - - public void tearDown() throws Exception - { - try - { - if(_jmxUtilConnected) - { - try - { - _jmxUtils.close(); - } - catch (IOException e) - { - _logger.error("Error closing jmxUtils", e); - } - } - producerConnection.close(); - consumerConnection.close(); - } - finally - { - super.tearDown(); - } - } - - public void testCapacityExceededCausesBlock() throws Exception - { - String queueName = getTestQueueName(); - - createAndBindQueueWithFlowControlEnabled(producerSession, queueName, 1000, 800); - producer = producerSession.createProducer(queue); - - // try to send 5 messages (should block after 4) - sendMessagesAsync(producer, producerSession, 5, 50L); - - Thread.sleep(5000); - - assertEquals("Incorrect number of message sent before blocking", 4, _sentMessages.get()); - - consumer = consumerSession.createConsumer(queue); - consumerConnection.start(); - - - consumer.receive(); - - Thread.sleep(1000); - - assertEquals("Message incorrectly sent after one message received", 4, _sentMessages.get()); - - - consumer.receive(); - - Thread.sleep(1000); - - assertEquals("Message not sent after two messages received", 5, _sentMessages.get()); - - } - - - public void testBrokerLogMessages() throws Exception - { - String queueName = getTestQueueName(); - - createAndBindQueueWithFlowControlEnabled(producerSession, queueName, 1000, 800); - producer = producerSession.createProducer(queue); - - // try to send 5 messages (should block after 4) - sendMessagesAsync(producer, producerSession, 5, 50L); - - List results = waitAndFindMatches("QUE-1003", 7000); - - assertEquals("Did not find correct number of QUE-1003 queue overfull messages", 1, results.size()); - - consumer = consumerSession.createConsumer(queue); - consumerConnection.start(); - - - while(consumer.receive(1000) != null) {}; - - results = waitAndFindMatches("QUE-1004"); - - assertEquals("Did not find correct number of UNDERFULL queue underfull messages", 1, results.size()); - } - - - public void testClientLogMessages() throws Exception - { - String queueName = getTestQueueName(); - - setTestClientSystemProperty("qpid.flow_control_wait_failure","3000"); - setTestClientSystemProperty("qpid.flow_control_wait_notify_period","1000"); - - Session session = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - createAndBindQueueWithFlowControlEnabled(session, queueName, 1000, 800); - producer = session.createProducer(queue); - - // try to send 5 messages (should block after 4) - MessageSender sender = sendMessagesAsync(producer, session, 5, 50L); - - List results = waitAndFindMatches("Message send delayed by", TIMEOUT); - assertTrue("No delay messages logged by client",results.size()!=0); - - List failedMessages = waitAndFindMatches("Message send failed due to timeout waiting on broker enforced" - + " flow control", TIMEOUT); - assertEquals("Incorrect number of send failure messages logged by client (got " + results.size() + " delay " - + "messages)",1,failedMessages.size()); - } - - - public void testFlowControlOnCapacityResumeEqual() throws Exception - { - String queueName = getTestQueueName(); - - createAndBindQueueWithFlowControlEnabled(producerSession, queueName, 1000, 1000); - producer = producerSession.createProducer(queue); - - - // try to send 5 messages (should block after 4) - sendMessagesAsync(producer, producerSession, 5, 50L); - - Thread.sleep(5000); - - assertEquals("Incorrect number of message sent before blocking", 4, _sentMessages.get()); - - consumer = consumerSession.createConsumer(queue); - consumerConnection.start(); - - consumer.receive(); - - Thread.sleep(1000); - - assertEquals("Message incorrectly sent after one message received", 5, _sentMessages.get()); - - - } - - - public void testFlowControlSoak() throws Exception - { - String queueName = getTestQueueName(); - - - final int numProducers = 10; - final int numMessages = 100; - - createAndBindQueueWithFlowControlEnabled(producerSession, queueName, 6000, 3000); - - consumerConnection.start(); - - Connection[] producers = new Connection[numProducers]; - for(int i = 0 ; i < numProducers; i ++) - { - - producers[i] = getConnection(); - producers[i].start(); - Session session = producers[i].createSession(false, Session.AUTO_ACKNOWLEDGE); - - MessageProducer myproducer = session.createProducer(queue); - MessageSender sender = sendMessagesAsync(myproducer, session, numMessages, 50L); - } - - consumer = consumerSession.createConsumer(queue); - consumerConnection.start(); - - for(int j = 0; j < numProducers * numMessages; j++) - { - - Message msg = consumer.receive(5000); - Thread.sleep(50L); - assertNotNull("Message not received("+j+"), sent: "+_sentMessages.get(), msg); - - } - - - - Message msg = consumer.receive(500); - assertNull("extra message received", msg); - - - for(int i = 0; i < numProducers; i++) - { - producers[i].close(); - } - - } - - public void testSendTimeout() throws Exception - { - String queueName = getTestQueueName(); - final String expectedMsg = isBroker010() ? "Exception when sending message:timed out waiting for message credit" - : "Unable to send message for 3 seconds due to broker enforced flow control"; - - setTestClientSystemProperty("qpid.flow_control_wait_failure","3000"); - Session session = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - createAndBindQueueWithFlowControlEnabled(producerSession, queueName, 1000, 800); - producer = session.createProducer(queue); - - // try to send 5 messages (should block after 4) - MessageSender sender = sendMessagesAsync(producer, session, 5, 100L); - - Exception e = sender.awaitSenderException(10000); - - assertNotNull("No timeout exception on sending", e); - - - assertEquals("Unexpected exception reason", expectedMsg, e.getMessage()); - - } - - public void testFlowControlAttributeModificationViaJMX() throws Exception - { - _jmxUtils.open(); - _jmxUtilConnected = true; - - String queueName = getTestQueueName(); - - createAndBindQueueWithFlowControlEnabled(producerSession, queueName, 0, 0); - producer = producerSession.createProducer(queue); - - Thread.sleep(1000); - - //Create a JMX MBean proxy for the queue - ManagedQueue queueMBean = _jmxUtils.getManagedObject(ManagedQueue.class, _jmxUtils.getQueueObjectName("test", queueName)); - assertNotNull(queueMBean); - - //check current attribute values are 0 as expected - assertTrue("Capacity was not the expected value", queueMBean.getCapacity() == 0L); - assertTrue("FlowResumeCapacity was not the expected value", queueMBean.getFlowResumeCapacity() == 0L); - - //set new values that will cause flow control to be active, and the queue to become overfull after 1 message is sent - queueMBean.setCapacity(250L); - queueMBean.setFlowResumeCapacity(250L); - assertTrue("Capacity was not the expected value", queueMBean.getCapacity() == 250L); - assertTrue("FlowResumeCapacity was not the expected value", queueMBean.getFlowResumeCapacity() == 250L); - assertFalse("Queue should not be overfull", queueMBean.isFlowOverfull()); - - // try to send 2 messages (should block after 1) - - sendMessagesAsync(producer, producerSession, 2, 50L); - - Thread.sleep(2000); - - //check only 1 message was sent, and queue is overfull - assertEquals("Incorrect number of message sent before blocking", 1, _sentMessages.get()); - assertTrue("Queue should be overfull", queueMBean.isFlowOverfull()); - - //raise the attribute values, causing the queue to become underfull and allow the second message to be sent. - queueMBean.setCapacity(300L); - queueMBean.setFlowResumeCapacity(300L); - - Thread.sleep(2000); - - //check second message was sent, and caused the queue to become overfull again - assertEquals("Second message was not sent after lifting FlowResumeCapacity", 2, _sentMessages.get()); - assertTrue("Queue should be overfull", queueMBean.isFlowOverfull()); - - //raise capacity above queue depth, check queue remains overfull as FlowResumeCapacity still exceeded - queueMBean.setCapacity(700L); - assertTrue("Queue should be overfull", queueMBean.isFlowOverfull()); - - //receive a message, check queue becomes underfull - - consumer = consumerSession.createConsumer(queue); - consumerConnection.start(); - - consumer.receive(); - - //perform a synchronous op on the connection - ((AMQSession) consumerSession).sync(); - - assertFalse("Queue should not be overfull", queueMBean.isFlowOverfull()); - - consumer.receive(); - } - - public void testQueueDeleteWithBlockedFlow() throws Exception - { - String queueName = getTestQueueName(); - createAndBindQueueWithFlowControlEnabled(producerSession, queueName, 1000, 800, true, false); - - producer = producerSession.createProducer(queue); - - // try to send 5 messages (should block after 4) - sendMessagesAsync(producer, producerSession, 5, 50L); - - Thread.sleep(5000); - - assertEquals("Incorrect number of message sent before blocking", 4, _sentMessages.get()); - - // close blocked producer session and connection - producerConnection.close(); - - // delete queue with a consumer session - ((AMQSession) consumerSession).sendQueueDelete(new AMQShortString(queueName)); - - consumer = consumerSession.createConsumer(queue); - consumerConnection.start(); - - Message message = consumer.receive(1000l); - assertNull("Unexpected message", message); - } - - private void createAndBindQueueWithFlowControlEnabled(Session session, String queueName, int capacity, int resumeCapacity) throws Exception - { - createAndBindQueueWithFlowControlEnabled(session, queueName, capacity, resumeCapacity, false, true); - } - - private void createAndBindQueueWithFlowControlEnabled(Session session, String queueName, int capacity, int resumeCapacity, boolean durable, boolean autoDelete) throws Exception - { - final Map arguments = new HashMap(); - arguments.put("x-qpid-capacity",capacity); - arguments.put("x-qpid-flow-resume-capacity",resumeCapacity); - ((AMQSession) session).createQueue(new AMQShortString(queueName), autoDelete, durable, false, arguments); - queue = session.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='" + durable + "'&autodelete='" + autoDelete + "'"); - ((AMQSession) session).declareAndBind((AMQDestination)queue); - } - - private MessageSender sendMessagesAsync(final MessageProducer producer, - final Session producerSession, - final int numMessages, - long sleepPeriod) - { - MessageSender sender = new MessageSender(producer, producerSession, numMessages,sleepPeriod); - new Thread(sender).start(); - return sender; - } - - private void sendMessages(MessageProducer producer, Session producerSession, int numMessages, long sleepPeriod) - throws JMSException - { - - for (int msg = 0; msg < numMessages; msg++) - { - producer.send(nextMessage(msg, producerSession)); - _sentMessages.incrementAndGet(); - - - try - { - ((AMQSession)producerSession).sync(); - } - catch (AMQException e) - { - _logger.error("Error performing sync", e); - throw new RuntimeException(e); - } - - try - { - Thread.sleep(sleepPeriod); - } - catch (InterruptedException e) - { - throw new RuntimeException(e); - } - } - } - - private static final byte[] BYTE_300 = new byte[300]; - - private Message nextMessage(int msg, Session producerSession) throws JMSException - { - BytesMessage send = producerSession.createBytesMessage(); - send.writeBytes(BYTE_300); - send.setIntProperty("msg", msg); - - return send; - } - - private class MessageSender implements Runnable - { - private final MessageProducer _senderProducer; - private final Session _senderSession; - private final int _numMessages; - private volatile JMSException _exception; - private CountDownLatch _exceptionThrownLatch = new CountDownLatch(1); - private long _sleepPeriod; - - public MessageSender(MessageProducer producer, Session producerSession, int numMessages, long sleepPeriod) - { - _senderProducer = producer; - _senderSession = producerSession; - _numMessages = numMessages; - _sleepPeriod = sleepPeriod; - } - - public void run() - { - try - { - sendMessages(_senderProducer, _senderSession, _numMessages, _sleepPeriod); - } - catch (JMSException e) - { - _exception = e; - _exceptionThrownLatch.countDown(); - } - } - - public Exception awaitSenderException(long timeout) throws InterruptedException - { - _exceptionThrownLatch.await(timeout, TimeUnit.MILLISECONDS); - return _exception; - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/QueueBindTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/QueueBindTest.java deleted file mode 100644 index 64ba0156e6..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/QueueBindTest.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.Session; - -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.common.AMQPFilterTypes; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.url.AMQBindingURL; - -public class QueueBindTest extends QpidBrokerTestCase -{ - private Connection _connection; - private AMQSession _session; - - protected void setUp() throws Exception - { - super.setUp(); - - _connection = getConnection(); - _session = (AMQSession) _connection.createSession(true, Session.SESSION_TRANSACTED); - } - - public void testQueueCannotBeReboundOnNonTopicExchange() throws Exception - { - runTestForNonTopicExhange(new AMQQueue(new AMQBindingURL("direct://amq.direct//" + getTestQueueName()))); - runTestForNonTopicExhange(new AMQQueue(new AMQBindingURL("fanout://amq.fanout//" + getTestQueueName()) + "?routingkey='" - + getTestQueueName() + "'")); - } - - public void testQueueCanBeReboundOnTopicExchange() throws Exception - { - AMQQueue destination = new AMQQueue(new AMQBindingURL("topic://amq.topic//" + getTestQueueName() + "?routingkey='" - + getTestQueueName() + "'")); - setTestClientSystemProperty("qpid.default_mandatory", "false"); - runTestForTopicExchange(destination); - - } - - private void runTestForTopicExchange(AMQDestination destination) throws AMQException, JMSException, Exception - { - // binding queue with empty arguments - _session.declareAndBind(destination, FieldTable.convertToFieldTable(Collections. emptyMap())); - - // try to re-bind queue with a selector - Map bindArguments = new HashMap(); - bindArguments.put(AMQPFilterTypes.JMS_SELECTOR.getValue().toString(), INDEX + "=0"); - _session.bindQueue(destination.getAMQQueueName(), destination.getRoutingKey(), - FieldTable.convertToFieldTable(bindArguments), destination.getExchangeName(), destination); - - _connection.start(); - - // repeat send/receive twice to make sure that selector is working - for (int i = 0; i < 2; i++) - { - int numberOfMesssages = 2; - sendMessage(_session, destination, numberOfMesssages); - - MessageConsumer consumer = _session.createConsumer(destination); - Message m = consumer.receive(1000); - assertNotNull("Message not received", m); - assertEquals("Unexpected index", 0, m.getIntProperty(INDEX)); - _session.commit(); - - m = consumer.receive(1000); - assertNull("Message received", m); - - consumer.close(); - } - } - - private void runTestForNonTopicExhange(AMQQueue destination) throws AMQException, Exception, JMSException - { - // binding queue with empty arguments - _session.declareAndBind(destination, FieldTable.convertToFieldTable(Collections. emptyMap())); - - // try to re-bind queue with a selector - Map bindArguments = new HashMap(); - bindArguments.put(AMQPFilterTypes.JMS_SELECTOR.getValue().toString(), INDEX + "=0"); - _session.bindQueue(destination.getAMQQueueName(), destination.getRoutingKey(), - FieldTable.convertToFieldTable(bindArguments), destination.getExchangeName(), destination); - - // send and receive to prove that selector is not used - int numberOfMesssages = 2; - sendMessage(_session, destination, numberOfMesssages); - - MessageConsumer consumer = _session.createConsumer(destination); - _connection.start(); - - for (int i = 0; i < numberOfMesssages; i++) - { - Message m = consumer.receive(1000l); - assertNotNull("Message [" + i + "] not received with exchange " + destination.getExchangeName(), m); - assertEquals("Unexpected index", i, m.getIntProperty(INDEX)); - _session.commit(); - } - consumer.close(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java deleted file mode 100644 index dd57c1e3f7..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.Session; - -/** - * Test Case to ensure that messages are correctly returned. - * This includes checking: - * - The message is returned. - * - The broker doesn't leak memory. - * - The broker's state is correct after test. - */ -public class QueueDepthWithSelectorTest extends QpidBrokerTestCase -{ - protected final String VHOST = "test"; - protected final String QUEUE = this.getClass().getName(); - - protected Connection _clientConnection; - protected Connection _producerConnection; - private Session _clientSession; - protected Session _producerSession; - protected MessageProducer _producer; - private MessageConsumer _consumer; - - protected static int MSG_COUNT = 50; - - protected Message[] _messages = new Message[MSG_COUNT]; - - protected Queue _queue; - - @Override - public void setUp() throws Exception - { - super.setUp(); - - _messages = new Message[MSG_COUNT]; - _queue = getTestQueue(); - - //Create Producer - _producerConnection = getConnection(); - _producerConnection.start(); - _producerSession = _producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - _producer = _producerSession.createProducer(_queue); - - // Create consumer - _clientConnection = getConnection(); - _clientConnection.start(); - _clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - _consumer = _clientSession.createConsumer(_queue, "key = 23"); - } - - public void test() throws Exception - { - //Send messages - _logger.info("Starting to send messages"); - for (int msg = 0; msg < MSG_COUNT; msg++) - { - _producer.send(nextMessage(msg)); - } - _logger.info("Closing connection"); - //Close the connection.. .giving the broker time to clean up its state. - _producerConnection.close(); - - //Verify we get all the messages. - _logger.info("Verifying messages"); - verifyAllMessagesRecevied(50); - verifyBrokerState(0); - - //Close the connection.. .giving the broker time to clean up its state. - _clientConnection.close(); - - //Verify Broker state - _logger.info("Verifying broker state"); - verifyBrokerState(0); - } - - protected void verifyBrokerState(int expectedDepth) - { - try - { - Connection connection = getConnection(); - AMQSession session = (AMQSession)connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - long queueDepth = session.getQueueDepth((AMQDestination) _queue); - assertEquals("Session reports Queue depth not as expected", expectedDepth, queueDepth); - - connection.close(); - } - catch (AMQException e) - { - fail(e.getMessage()); - } - catch (Exception e) - { - fail(e.getMessage()); - } - } - - protected void verifyAllMessagesRecevied(int expectedDepth) throws Exception - { - boolean[] msgIdRecevied = new boolean[MSG_COUNT]; - - for (int i = 0; i < expectedDepth; i++) - { - _messages[i] = _consumer.receive(1000); - assertNotNull("should have received a message but didn't", _messages[i]); - } - - //Check received messages - int msgId = 0; - for (Message msg : _messages) - { - assertNotNull("Message should not be null", msg); - assertEquals("msgId was wrong", msgId, msg.getIntProperty("ID")); - assertFalse("Already received msg id " + msgId, msgIdRecevied[msgId]); - msgIdRecevied[msgId] = true; - msgId++; - } - - //Check all received - for (msgId = 0; msgId < expectedDepth; msgId++) - { - assertTrue("Message " + msgId + " not received.", msgIdRecevied[msgId]); - } - - //do a synchronous op to ensure the acks are processed - //on the broker before proceeding - ((AMQSession)_clientSession).sync(); - } - - /** - * Get the next message putting the given count into the intProperties as ID. - * - * @param msgNo the message count to store as ID. - * @throws JMSException - */ - protected Message nextMessage(int msgNo) throws JMSException - { - Message send = _producerSession.createTextMessage("MessageReturnTest"); - send.setIntProperty("ID", msgNo); - send.setIntProperty("key", 23); - return send; - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/QueueMessageDurabilityTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/QueueMessageDurabilityTest.java deleted file mode 100644 index fe86e9d41f..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/QueueMessageDurabilityTest.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import java.util.HashMap; -import java.util.Map; - -import javax.jms.Connection; -import javax.jms.DeliveryMode; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.TextMessage; - -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.store.MessageDurability; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class QueueMessageDurabilityTest extends QpidBrokerTestCase -{ - - private static final String QPID_MESSAGE_DURABILITY = "qpid.message_durability"; - private static final String DURABLE_ALWAYS_PERSIST_NAME = "DURABLE_QUEUE_ALWAYS_PERSIST"; - private static final String DURABLE_NEVER_PERSIST_NAME = "DURABLE_QUEUE_NEVER_PERSIST"; - private static final String DURABLE_DEFAULT_PERSIST_NAME = "DURABLE_QUEUE_DEFAULT_PERSIST"; - private static final String NONDURABLE_ALWAYS_PERSIST_NAME = "NONDURABLE_QUEUE_ALWAYS_PERSIST"; - - @Override - public void setUp() throws Exception - { - super.setUp(); - Connection conn = getConnection(); - Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - AMQSession amqSession = (AMQSession) session; - - Map arguments = new HashMap<>(); - arguments.put(QPID_MESSAGE_DURABILITY, MessageDurability.ALWAYS.name()); - amqSession.createQueue(new AMQShortString(DURABLE_ALWAYS_PERSIST_NAME), false, true, false, arguments); - - arguments = new HashMap<>(); - arguments.put(QPID_MESSAGE_DURABILITY, MessageDurability.NEVER.name()); - amqSession.createQueue(new AMQShortString(DURABLE_NEVER_PERSIST_NAME), false, true, false, arguments); - - arguments = new HashMap<>(); - arguments.put(QPID_MESSAGE_DURABILITY, MessageDurability.DEFAULT.name()); - amqSession.createQueue(new AMQShortString(DURABLE_DEFAULT_PERSIST_NAME), false, true, false, arguments); - - arguments = new HashMap<>(); - arguments.put(QPID_MESSAGE_DURABILITY,MessageDurability.ALWAYS.name()); - amqSession.createQueue(new AMQShortString(NONDURABLE_ALWAYS_PERSIST_NAME), false, false, false, arguments); - - amqSession.bindQueue(AMQShortString.valueOf(DURABLE_ALWAYS_PERSIST_NAME), - AMQShortString.valueOf("Y.*.*.*"), - null, - AMQShortString.valueOf(ExchangeDefaults.TOPIC_EXCHANGE_NAME), - null); - - amqSession.bindQueue(AMQShortString.valueOf(DURABLE_NEVER_PERSIST_NAME), - AMQShortString.valueOf("*.Y.*.*"), - null, - AMQShortString.valueOf(ExchangeDefaults.TOPIC_EXCHANGE_NAME), - null); - - amqSession.bindQueue(AMQShortString.valueOf(DURABLE_DEFAULT_PERSIST_NAME), - AMQShortString.valueOf("*.*.Y.*"), - null, - AMQShortString.valueOf(ExchangeDefaults.TOPIC_EXCHANGE_NAME), - null); - - amqSession.bindQueue(AMQShortString.valueOf(NONDURABLE_ALWAYS_PERSIST_NAME), - AMQShortString.valueOf("*.*.*.Y"), - null, - AMQShortString.valueOf(ExchangeDefaults.TOPIC_EXCHANGE_NAME), - null); - } - - public void testSendPersistentMessageToAll() throws Exception - { - Connection conn = getConnection(); - Session session = conn.createSession(true, Session.SESSION_TRANSACTED); - MessageProducer producer = session.createProducer(null); - conn.start(); - producer.send(session.createTopic("Y.Y.Y.Y"), session.createTextMessage("test")); - session.commit(); - - AMQSession amqSession = (AMQSession) session; - assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_ALWAYS_PERSIST_NAME))); - assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_NEVER_PERSIST_NAME))); - assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_DEFAULT_PERSIST_NAME))); - assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(NONDURABLE_ALWAYS_PERSIST_NAME))); - - restartBroker(); - - conn = getConnection(); - session = conn.createSession(true, Session.SESSION_TRANSACTED); - amqSession = (AMQSession) session; - assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_ALWAYS_PERSIST_NAME))); - assertEquals(0,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_NEVER_PERSIST_NAME))); - assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_DEFAULT_PERSIST_NAME))); - - assertFalse(amqSession.isQueueBound((AMQDestination) session.createQueue(NONDURABLE_ALWAYS_PERSIST_NAME))); - - } - - - public void testSendNonPersistentMessageToAll() throws Exception - { - Connection conn = getConnection(); - Session session = conn.createSession(true, Session.SESSION_TRANSACTED); - MessageProducer producer = session.createProducer(null); - producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); - conn.start(); - producer.send(session.createTopic("Y.Y.Y.Y"), session.createTextMessage("test")); - session.commit(); - - AMQSession amqSession = (AMQSession) session; - assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_ALWAYS_PERSIST_NAME))); - assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_NEVER_PERSIST_NAME))); - assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_DEFAULT_PERSIST_NAME))); - assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(NONDURABLE_ALWAYS_PERSIST_NAME))); - - restartBroker(); - - conn = getConnection(); - session = conn.createSession(true, Session.SESSION_TRANSACTED); - amqSession = (AMQSession) session; - assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_ALWAYS_PERSIST_NAME))); - assertEquals(0,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_NEVER_PERSIST_NAME))); - assertEquals(0,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_DEFAULT_PERSIST_NAME))); - - assertFalse(amqSession.isQueueBound((AMQDestination)session.createQueue(NONDURABLE_ALWAYS_PERSIST_NAME))); - - } - - public void testNonPersistentContentRetained() throws Exception - { - Connection conn = getConnection(); - Session session = conn.createSession(true, Session.SESSION_TRANSACTED); - MessageProducer producer = session.createProducer(null); - producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); - conn.start(); - producer.send(session.createTopic("N.N.Y.Y"), session.createTextMessage("test1")); - producer.send(session.createTopic("Y.N.Y.Y"), session.createTextMessage("test2")); - session.commit(); - MessageConsumer consumer = session.createConsumer(session.createQueue(DURABLE_ALWAYS_PERSIST_NAME)); - Message msg = consumer.receive(1000l); - assertNotNull(msg); - assertTrue(msg instanceof TextMessage); - assertEquals("test2", ((TextMessage) msg).getText()); - session.rollback(); - restartBroker(); - conn = getConnection(); - conn.start(); - session = conn.createSession(true, Session.SESSION_TRANSACTED); - AMQSession amqSession = (AMQSession) session; - assertEquals(1, amqSession.getQueueDepth((AMQDestination) session.createQueue(DURABLE_ALWAYS_PERSIST_NAME))); - assertEquals(0,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_NEVER_PERSIST_NAME))); - assertEquals(0,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_DEFAULT_PERSIST_NAME))); - consumer = session.createConsumer(session.createQueue(DURABLE_ALWAYS_PERSIST_NAME)); - msg = consumer.receive(1000l); - assertNotNull(msg); - assertTrue(msg instanceof TextMessage); - assertEquals("test2", ((TextMessage)msg).getText()); - session.commit(); - } - - public void testPersistentContentRetainedOnTransientQueue() throws Exception - { - setTestClientSystemProperty(ClientProperties.QPID_DECLARE_QUEUES_PROP_NAME, "false"); - Connection conn = getConnection(); - Session session = conn.createSession(true, Session.SESSION_TRANSACTED); - MessageProducer producer = session.createProducer(null); - producer.setDeliveryMode(DeliveryMode.PERSISTENT); - conn.start(); - producer.send(session.createTopic("N.N.Y.Y"), session.createTextMessage("test1")); - session.commit(); - MessageConsumer consumer = session.createConsumer(session.createQueue(DURABLE_DEFAULT_PERSIST_NAME)); - Message msg = consumer.receive(1000l); - assertNotNull(msg); - assertTrue(msg instanceof TextMessage); - assertEquals("test1", ((TextMessage)msg).getText()); - session.commit(); - System.gc(); - consumer = session.createConsumer(session.createQueue(NONDURABLE_ALWAYS_PERSIST_NAME)); - msg = consumer.receive(1000l); - assertNotNull(msg); - assertTrue(msg instanceof TextMessage); - assertEquals("test1", ((TextMessage)msg).getText()); - session.commit(); - } - - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/SortedQueueTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/SortedQueueTest.java deleted file mode 100644 index 340ae4a1ae..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/SortedQueueTest.java +++ /dev/null @@ -1,538 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.queue; - -import org.apache.log4j.Logger; - -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.Session; -import javax.jms.TextMessage; -import javax.naming.NamingException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.concurrent.atomic.AtomicInteger; - -public class SortedQueueTest extends QpidBrokerTestCase -{ - private static final Logger LOGGER = Logger.getLogger(SortedQueueTest.class); - public static final String TEST_SORT_KEY = "testSortKey"; - private static final String[] VALUES = SortedQueueEntryListTest.keys.clone(); - private static final String[] VALUES_SORTED = SortedQueueEntryListTest.keys.clone(); - private final String[] SUBSET_KEYS = { "000", "100", "200", "300", "400", "500", "600", "700", "800", "900" }; - - private Connection _producerConnection; - private Session _producerSession; - private Connection _consumerConnection; - private long _receiveInterval; - - protected void setUp() throws Exception - { - super.setUp(); - setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, "1"); - // Sort value array to generated "expected" order of messages. - Arrays.sort(VALUES_SORTED); - _producerConnection = getConnection(); - _consumerConnection = getConnection(); - _producerSession = _producerConnection.createSession(true, Session.SESSION_TRANSACTED); - _receiveInterval = isBrokerStorePersistent() ? 3000l : 1500l; - } - - protected void tearDown() throws Exception - { - _producerSession.close(); - _producerConnection.close(); - _consumerConnection.close(); - super.tearDown(); - } - - public void testSortOrder() throws JMSException, NamingException, AMQException - { - final Queue queue = createQueue(); - final MessageProducer producer = _producerSession.createProducer(queue); - - for(String value : VALUES) - { - final Message msg = _producerSession.createTextMessage("Message Text:" + value); - msg.setStringProperty(TEST_SORT_KEY, value); - producer.send(msg); - } - - _producerSession.commit(); - producer.close(); - - final Session consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - final MessageConsumer consumer = consumerSession.createConsumer(queue); - _consumerConnection.start(); - TextMessage received; - int messageCount = 0; - while((received = (TextMessage) consumer.receive(_receiveInterval)) != null) - { - assertEquals("Received message with unexpected sorted key value", VALUES_SORTED[messageCount], - received.getStringProperty(TEST_SORT_KEY)); - assertEquals("Received message with unexpected message value", - "Message Text:" + VALUES_SORTED[messageCount], received.getText()); - messageCount++; - } - - assertEquals("Incorrect number of messages received", VALUES.length, messageCount); - } - - public void testAutoAckSortedQueue() throws JMSException, NamingException, AMQException - { - runThroughSortedQueueForSessionMode(Session.AUTO_ACKNOWLEDGE); - } - - public void testTransactedSortedQueue() throws JMSException, NamingException, AMQException - { - runThroughSortedQueueForSessionMode(Session.SESSION_TRANSACTED); - } - - public void testClientAckSortedQueue() throws JMSException, NamingException, AMQException - { - runThroughSortedQueueForSessionMode(Session.CLIENT_ACKNOWLEDGE); - } - - private void runThroughSortedQueueForSessionMode(final int sessionMode) throws JMSException, NamingException, - AMQException - { - final Queue queue = createQueue(); - final MessageProducer producer = _producerSession.createProducer(queue); - - final TestConsumerThread consumerThread = new TestConsumerThread(sessionMode, queue); - consumerThread.start(); - - for(String value : VALUES) - { - final Message msg = _producerSession.createMessage(); - msg.setStringProperty(TEST_SORT_KEY, value); - producer.send(msg); - _producerSession.commit(); - } - - try - { - consumerThread.join(getConsumerThreadJoinInterval()); - } - catch(InterruptedException e) - { - fail("Test failed waiting for consumer to complete"); - } - - assertTrue("Consumer timed out", consumerThread.isStopped()); - assertEquals("Incorrect number of messages received", VALUES.length, consumerThread.getConsumed()); - - producer.close(); - } - - public void testSortedQueueWithAscendingSortedKeys() throws JMSException, NamingException, AMQException - { - final Queue queue = createQueue(); - final MessageProducer producer = _producerSession.createProducer(queue); - - final TestConsumerThread consumerThread = new TestConsumerThread(Session.AUTO_ACKNOWLEDGE, queue); - consumerThread.start(); - - for(int i = 0; i < 200; i++) - { - final String ascendingKey = AscendingSortedKeys.getNextKey(); - final Message msg = _producerSession.createTextMessage("Message Text:" + ascendingKey); - msg.setStringProperty(TEST_SORT_KEY, ascendingKey); - producer.send(msg); - _producerSession.commit(); - } - - try - { - consumerThread.join(getConsumerThreadJoinInterval()); - } - catch(InterruptedException e) - { - fail("Test failed waiting for consumer to complete"); - } - - assertTrue("Consumer timed out", consumerThread.isStopped()); - assertEquals("Incorrect number of messages received", 200, consumerThread.getConsumed()); - - producer.close(); - } - - private long getConsumerThreadJoinInterval() - { - return isBrokerStorePersistent() ? 50000L: 5000L; - } - - public void testSortOrderWithNonUniqueKeys() throws JMSException, NamingException, AMQException - { - final Queue queue = createQueue(); - final MessageProducer producer = _producerSession.createProducer(queue); - - int count = 0; - while(count < 200) - { - final Message msg = _producerSession.createTextMessage("Message Text:" + count++); - msg.setStringProperty(TEST_SORT_KEY, "samesortkeyvalue"); - producer.send(msg); - } - - _producerSession.commit(); - producer.close(); - - final Session consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - final MessageConsumer consumer = consumerSession.createConsumer(queue); - _consumerConnection.start(); - TextMessage received = null; - int messageCount = 0; - - while((received = (TextMessage) consumer.receive(_receiveInterval)) != null) - { - assertEquals("Received message with unexpected sorted key value", "samesortkeyvalue", - received.getStringProperty(TEST_SORT_KEY)); - assertEquals("Received message with unexpected message value", "Message Text:" + messageCount, - received.getText()); - messageCount++; - } - - assertEquals("Incorrect number of messages received", 200, messageCount); - } - - public void testSortOrderWithUniqueKeySubset() throws JMSException, NamingException, AMQException - { - final Queue queue = createQueue(); - final MessageProducer producer = _producerSession.createProducer(queue); - - int count = 0; - while(count < 100) - { - int keyValueIndex = count % 10; - final Message msg = _producerSession.createTextMessage("Message Text:" + count); - msg.setStringProperty(TEST_SORT_KEY, SUBSET_KEYS[keyValueIndex]); - producer.send(msg); - count++; - } - - _producerSession.commit(); - producer.close(); - - final Session consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - final MessageConsumer consumer = consumerSession.createConsumer(queue); - _consumerConnection.start(); - TextMessage received; - int messageCount = 0; - - while((received = (TextMessage) consumer.receive(_receiveInterval)) != null) - { - assertEquals("Received message with unexpected sorted key value", SUBSET_KEYS[messageCount / 10], - received.getStringProperty(TEST_SORT_KEY)); - messageCount++; - } - - assertEquals("Incorrect number of messages received", 100, messageCount); - } - - public void testGetNextWithAck() throws JMSException, NamingException, AMQException - { - Queue _queue = createQueue(); - MessageProducer producer = _producerSession.createProducer(_queue); - Message received = null; - - //Send 3 out of order - sendAndCommitMessage(producer,"2"); - sendAndCommitMessage(producer,"3"); - sendAndCommitMessage(producer,"1"); - - final Session consumerSession = _consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); - final MessageConsumer consumer = consumerSession.createConsumer(_queue); - _consumerConnection.start(); - - //Receive 3 in sorted order - received = assertReceiveAndValidateMessage(consumer, "1"); - received.acknowledge(); - received = assertReceiveAndValidateMessage(consumer, "2"); - received.acknowledge(); - received = assertReceiveAndValidateMessage(consumer, "3"); - received.acknowledge(); - - //Send 1 - sendAndCommitMessage(producer,"4"); - - //Receive 1 and recover - received = assertReceiveAndValidateMessage(consumer, "4"); - consumerSession.recover(); - - //Receive same 1 - received = assertReceiveAndValidateMessage(consumer, "4"); - received.acknowledge(); - - //Send 3 out of order - sendAndCommitMessage(producer,"7"); - sendAndCommitMessage(producer,"6"); - sendAndCommitMessage(producer,"5"); - - //Receive 1 of 3 (possibly out of order due to pre-fetch) - final Message messageBeforeRollback = assertReceiveMessage(consumer); - consumerSession.recover(); - - if (isBroker010()) - { - //Receive 3 in sorted order (not as per JMS recover) - received = assertReceiveAndValidateMessage(consumer, "5"); - received.acknowledge(); - received = assertReceiveAndValidateMessage(consumer, "6"); - received.acknowledge(); - received = assertReceiveAndValidateMessage(consumer, "7"); - received.acknowledge(); - } - else - { - //First message will be the one rolled-back (as per JMS spec). - final String messageKeyDeliveredBeforeRollback = messageBeforeRollback.getStringProperty(TEST_SORT_KEY); - received = assertReceiveAndValidateMessage(consumer, messageKeyDeliveredBeforeRollback); - received.acknowledge(); - - //Remaining two messages will be sorted - final SortedSet keys = new TreeSet(Arrays.asList("5", "6", "7")); - keys.remove(messageKeyDeliveredBeforeRollback); - - received = assertReceiveAndValidateMessage(consumer, keys.first()); - received.acknowledge(); - received = assertReceiveAndValidateMessage(consumer, keys.last()); - received.acknowledge(); - } - } - - private Queue createQueue() throws AMQException, JMSException - { - final Map arguments = new HashMap(); - arguments.put(QueueArgumentsConverter.QPID_QUEUE_SORT_KEY, TEST_SORT_KEY); - ((AMQSession) _producerSession).createQueue(new AMQShortString(getTestQueueName()), false, true, false, arguments); - final Queue queue = new AMQQueue("amq.direct", getTestQueueName()); - ((AMQSession) _producerSession).declareAndBind((AMQDestination) queue); - return queue; - } - - private Message getSortableTestMesssage(final String key) throws JMSException - { - final Message msg = _producerSession.createTextMessage("Message Text: Key Value" + key); - msg.setStringProperty(TEST_SORT_KEY, key); - return msg; - } - - private void sendAndCommitMessage(final MessageProducer producer, final String keyValue) throws JMSException - { - producer.send(getSortableTestMesssage(keyValue)); - _producerSession.commit(); - } - - private Message assertReceiveAndValidateMessage(final MessageConsumer consumer, final String expectedKey) throws JMSException - { - final Message received = assertReceiveMessage(consumer); - assertEquals("Received message with unexpected sorted key value", expectedKey, - received.getStringProperty(TEST_SORT_KEY)); - return received; - } - - private Message assertReceiveMessage(final MessageConsumer consumer) - throws JMSException - { - final Message received = (TextMessage) consumer.receive(_receiveInterval); - assertNotNull("Received message is unexpectedly null", received); - return received; - } - - private class TestConsumerThread extends Thread - { - private final AtomicInteger _consumed = new AtomicInteger(0); - private volatile boolean _stopped = false; - private int _count = 0; - private int _sessionType = Session.AUTO_ACKNOWLEDGE; - private Queue _queue; - - public TestConsumerThread(final int sessionType, final Queue queue) - { - _sessionType = sessionType; - _queue = queue; - } - - public void run() - { - try - { - Connection conn = null; - try - { - conn = getConnection(); - } - catch(Exception e) - { - throw new RuntimeException("Could not get connection"); - } - - final Session session = conn.createSession((_sessionType == Session.SESSION_TRANSACTED ? true : false), - _sessionType); - final MessageConsumer consumer = session.createConsumer(_queue); - - conn.start(); - - Message msg; - while((msg = consumer.receive(_receiveInterval)) != null) - { - if(_sessionType == Session.SESSION_TRANSACTED) - { - if (_count%10 == 0) - { - LOGGER.debug("transacted session rollback"); - session.rollback(); - } - else - { - LOGGER.debug("transacted session commit"); - session.commit(); - _consumed.incrementAndGet(); - } - } - else if(_sessionType == Session.CLIENT_ACKNOWLEDGE) - { - if (_count%10 == 0) - { - LOGGER.debug("client ack session recover"); - session.recover(); - } - else - { - LOGGER.debug("client ack session acknowledge"); - msg.acknowledge(); - _consumed.incrementAndGet(); - } - } - else - { - LOGGER.debug("auto ack session"); - _consumed.incrementAndGet(); - } - - _count++; - LOGGER.debug("Message consumed with key: " + msg.getStringProperty(TEST_SORT_KEY)); - LOGGER.debug("Message consumed with consumed index: " + _consumed.get()); - } - - _stopped = true; - session.close(); - conn.close(); - } - catch(JMSException e) - { - LOGGER.error("Exception in listener", e); - } - } - - public boolean isStopped() - { - return _stopped; - } - - public int getConsumed() - { - return _consumed.get(); - } - } - - private static class AscendingSortedKeys - { - public static final String[] KEYS = { "Ul4a1", "WaWsv", "2Yz7E", "ix74r", "okgRi", "HlUbF", "LewvM", "lweGy", - "TXQ0Z", "0Kyfs", "s7Mxk", "dmoS7", "8RCUA", "W3VFH", "aez9y", "uQIcz", "0h1b1", "cmXIX", - "4dEz6", "zHF1q", "D6rBy", "5drc6", "0BmCy", "BCxeC", "t59lR", "aL6AJ", "OHaBz", "WmadA", - "B3qem", "CxVEf", "AIYUu", "uJScX", "uoStw", "ogLgc", "AgJHQ", "hUTw7", "Rxrsm", "9GXkX", - "7hyVv", "y94nw", "Twano", "TCgPp", "pFrrl", "POUYS", "L7cGc", "0ao3l", "CNHmv", "MaJQs", - "OUqFM", "jeskS", "FPfSE", "v1Hln", "14FLR", "KZamH", "G1RhS", "FVMxo", "rKDLJ", "nnP8o", - "nFqik", "zmLYD", "1j5L8", "e6e4z", "WDVWJ", "aDGtS", "fcwDa", "nlaBy", "JJs5m", "vLsmS", - "No0Qb", "JXljW", "Waim6", "MezSW", "l83Ud", "SjskQ", "uPX7G", "5nmWv", "ZhwG1", "uTacx", - "t98iW", "JkzUn", "fmIK1", "i7WMQ", "bgJAz", "n1pmO", "jS1aj", "4W0Tl", "Yf2Ec", "sqVrf", - "MojnP", "qQxHP", "pWiOs", "yToGW", "kB5nP", "BpYhV", "Cfgr3", "zbIYY", "VLTy6", "he9IA", - "lm0pD", "WreyP", "8hJdt", "QnJ1S", "n8pJ9", "iqv4k", "OUYuF", "8cVD3", "sx5Gl", "cQOnv", - "wiHrZ", "oGu6x", "7fsYM", "gf8rI", "7fKYU", "pT8wu", "lCMxy", "prNT6", "5Drn0", "guMb8", - "OxWIH", "uZPqg", "SbRYy", "In3NS", "uvf7A", "FLsph", "pmeCd", "BbwgA", "ru4UG", "YOfrY", - "W7cTs", "K4GS8", "AOgEe", "618Di", "dpe1v", "3otm6", "oVQp6", "5Mg9r", "Y1mC0", "VIlwP", - "aFFss", "Mkgy8", "pv0i7", "S77LH", "XyPZN", "QYxC0", "vkCHH", "MGlTF", "24ARF", "v2eC3", - "ZUnqt", "HfyNQ", "FjHXR", "45cIH", "1LB1L", "zqH0W", "fLNg8", "oQ87r", "Cp3mZ", "Zv7z0", - "O3iyQ", "EOE1o", "5ZaEz", "tlILt", "MmsIo", "lXFOB", "gtCA5", "yEfy9", "7X3uy", "d7vjM", - "XflUq", "Fhtgl", "NOHsz", "GWqqX", "xciqp", "BFkb8", "P6bcg", "lViBv", "2TRI7", "2hEEU", - "9XyT9", "29QAz", "U3yw5", "FxX9q", "C2Irc", "8U2nU", "m4bxU", "5iGN5", "mX2GE", "cShY2", - "JRJQB", "yvOMI", "4QMc9", "NAFuw", "RmDcr", "faHir", "2ZHdk", "zY1GY", "a00b5", "ZuDtD", - "JIqXi", "K20wK", "gdQsS", "5Namm", "lkMUA", "IBe8k", "FcWrW", "FFDui", "tuDyS", "ZJTXH", - "AkKTk", "zQt6Q", "FNYIM", "RpBQm", "RsQUq", "Mm8si", "gjUTu", "zz4ZU", "jiVBP", "ReKEW", - "5VZjS", "YjB9t", "zFgtB", "8TxD7", "euZA5", "MK07Y", "CK5W7", "16lHc", "6q6L9", "Z4I1v", - "UlU3M", "SWfou", "0PktI", "55rfB", "jfREu", "580YD", "Uvlv4", "KASQ8", "AmdQd", "piJSk", - "hE1Ql", "LDk6f", "NcICA", "IKxdL", "iwzGk", "uN6r3", "lsQGo", "QClRL", "iKqhr", "FGzgp", - "RkQke", "b29RJ", "CIShG", "9eoRc", "F6PT2", "LbRTH", "M3zXL", "GXdoH", "IjTwP", "RBhp0", - "yluBx", "mz8gx", "MmKGJ", "Q6Lix", "uupzk", "RACuj", "d85a9", "qaofN", "kZANm", "jtn0X", - "lpF6W", "suY4x", "rz7Ut", "wDajX", "1v5hH", "Yw2oU", "ksJby", "WMiS3", "lj07Q", "EdBKc", - "6AFT0", "0YAGH", "ThjNn", "JKWYR", "9iGoT", "UmaEv", "3weIF", "CdyBV", "pAhR1", "djsrv", - "xReec", "8FmFH", "Dz1R3", "Ta8f6", "DG4sT", "VjCZq", "jSjS3", "Pb1pa", "VNCPd", "Kr8ys", - "AXpwE", "ZzJHW", "Nxx9V", "jzUqR", "dhSuH", "DQimp", "07n1c", "HP433", "RzaZA", "cL0aE", - "Ss0Zu", "FnPFB", "7lUXZ", "9rlg9", "lH1kt", "ni2v1", "48cHL", "soy9t", "WPmlx", "2Nslm", - "hSSvQ", "9y4lw", "ulk41", "ECMvU", "DLhzM", "GrDg7", "x3LDe", "QChxs", "xXTI4", "Gv3Fq", - "rhl0J", "QssNC", "brhlQ", "s93Ml", "tl72W", "pvgjS", "Qworu", "DcpWB", "X6Pin", "J2mQi", - "BGaQY", "CqqaD", "NhXdu", "dQ586", "Yh1hF", "HRxd8", "PYBf4", "64s8N", "tvdkD", "azIWp", - "tAOsr", "v8yFN", "h1zcH", "SmGzv", "bZLvS", "fFDrJ", "Oz8yZ", "0Wr5y", "fcJOy", "7ku1p", - "QbxXc", "VerEA", "QWxoT", "hYBCK", "o8Uyd", "FwEJz", "hi5X7", "uAWyp", "I7p2a", "M6qcG", - "gIYvE", "HzZT8", "iB08l", "StlDJ", "tjQxs", "k85Ae", "taOXK", "s4786", "2DREs", "atef2", - "Vprf2", "VBjhz", "EoToP", "blLA9", "qUJMd", "ydG8U", "8xEKz", "uLtKs", "GSQwj", "S2Dfu", - "ciuWz", "i3pyd", "7Ow5C", "IRh48", "vOqCE", "Q6hMC", "yofH3", "KsjRK", "5IhmG", "fqypy", - "0MR5X", "Chuy3" }; - - private static int _i = 0; - private static int _j = 0; - - static - { - Arrays.sort(KEYS); - } - - public static String getNextKey() - { - if(_j == KEYS.length) - { - _j = 0; - _i++; - if(_i == KEYS.length) - { - _i = 0; - } - } - return new StringBuffer().append(KEYS[_i]).append("-").append(KEYS[_j++]).toString(); - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/TimeToLiveTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/TimeToLiveTest.java deleted file mode 100644 index e606df3f7d..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/TimeToLiveTest.java +++ /dev/null @@ -1,397 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.queue; - -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.ReentrantLock; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.Session; -import javax.jms.TopicSubscriber; -import javax.naming.NamingException; - -import org.apache.log4j.Logger; -import org.junit.Assert; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class TimeToLiveTest extends QpidBrokerTestCase -{ - private static final Logger _logger = Logger.getLogger(TimeToLiveTest.class); - - protected final String QUEUE = "TimeToLiveQueue"; - - private final long TIME_TO_LIVE = 100L; - - private static final int MSG_COUNT = 50; - private static final long SERVER_TTL_TIMEOUT = 60000L; - - public void testPassiveTTLWithPrefetch() throws Exception - { - doTestPassiveTTL(true); - } - - public void testPassiveTTL() throws Exception - { - doTestPassiveTTL(false); - - } - - private void doTestPassiveTTL(boolean prefetchMessages) throws JMSException, NamingException - { - //Create Client 1 - Connection clientConnection = getConnection(); - - Session clientSession = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Queue queue = clientSession.createQueue(QUEUE); - - // Create then close the consumer so the queue is actually created - // Closing it then reopening it ensures that the consumer shouldn't get messages - // which should have expired and allows a shorter sleep period. See QPID-1418 - - MessageConsumer consumer = clientSession.createConsumer(queue); - consumer.close(); - - //Create Producer - Connection producerConnection = getConnection(); - - producerConnection.start(); - - // Move to a Transacted session to ensure that all messages have been delivered to broker before - // we start waiting for TTL - Session producerSession = producerConnection.createSession(true, Session.SESSION_TRANSACTED); - - MessageProducer producer = producerSession.createProducer(queue); - - consumer = clientSession.createConsumer(queue); - if(prefetchMessages) - { - clientConnection.start(); - } - - //Set TTL - int msg = 0; - producer.send(nextMessage(String.valueOf(msg), true, producerSession, producer)); - - producer.setTimeToLive(TIME_TO_LIVE); - - for (; msg < MSG_COUNT - 2; msg++) - { - producer.send(nextMessage(String.valueOf(msg), false, producerSession, producer)); - } - - //Reset TTL - producer.setTimeToLive(0L); - producer.send(nextMessage(String.valueOf(msg), false, producerSession, producer)); - - producerSession.commit(); - - - // Ensure we sleep the required amount of time. - ReentrantLock waitLock = new ReentrantLock(); - Condition wait = waitLock.newCondition(); - final long MILLIS = 1000000L; - - long waitTime = TIME_TO_LIVE * MILLIS; - while (waitTime > 0) - { - try - { - waitLock.lock(); - - waitTime = wait.awaitNanos(waitTime); - } - catch (InterruptedException e) - { - //Stop if we are interrupted - fail(e.getMessage()); - } - finally - { - waitLock.unlock(); - } - - } - - if(prefetchMessages) - { - clientConnection.close(); - clientConnection = getConnection(); - - clientSession = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - queue = clientSession.createQueue(QUEUE); - consumer = clientSession.createConsumer(queue); - } - - clientConnection.start(); - - //Receive Message 0 - // Set 5s receive time for messages we expect to receive. - Message receivedFirst = consumer.receive(5000); - Message receivedSecond = consumer.receive(5000); - Message receivedThird = consumer.receive(1000); - - // Log the messages to help diagnosis incase of failure - _logger.info("First:"+receivedFirst); - _logger.info("Second:"+receivedSecond); - _logger.info("Third:"+receivedThird); - - // Only first and last messages sent should survive expiry - Assert.assertNull("More messages received", receivedThird); - - Assert.assertNotNull("First message not received", receivedFirst); - Assert.assertTrue("First message doesn't have first set.", receivedFirst.getBooleanProperty("first")); - Assert.assertEquals("First message has incorrect TTL.", 0L, receivedFirst.getLongProperty("TTL")); - - Assert.assertNotNull("Final message not received", receivedSecond); - Assert.assertFalse("Final message has first set.", receivedSecond.getBooleanProperty("first")); - Assert.assertEquals("Final message has incorrect TTL.", 0L, receivedSecond.getLongProperty("TTL")); - - clientConnection.close(); - - producerConnection.close(); - } - - private Message nextMessage(String msg, boolean first, Session producerSession, MessageProducer producer) throws JMSException - { - Message send = producerSession.createTextMessage("Message " + msg); - send.setBooleanProperty("first", first); - send.setStringProperty("testprop", "TimeToLiveTest"); - send.setLongProperty("TTL", producer.getTimeToLive()); - return send; - } - - - /** - * Tests the expired messages get actively deleted even on queues which have no consumers - * @throws Exception - */ - public void testActiveTTL() throws Exception - { - Connection producerConnection = getConnection(); - AMQSession producerSession = (AMQSession) producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Queue queue = producerSession.createTemporaryQueue(); - producerSession.declareAndBind((AMQDestination) queue); - MessageProducer producer = producerSession.createProducer(queue); - producer.setTimeToLive(1000L); - - // send Messages - for(int i = 0; i < MSG_COUNT; i++) - { - producer.send(producerSession.createTextMessage("Message: "+i)); - } - long failureTime = System.currentTimeMillis() + 2 * SERVER_TTL_TIMEOUT; - - // check Queue depth for up to TIMEOUT seconds after the Queue Depth hasn't changed for 100ms. - long messageCount = MSG_COUNT; - long lastPass; - - do - { - lastPass = messageCount; - Thread.sleep(100); - messageCount = producerSession.getQueueDepth((AMQDestination) queue); - - // If we have received messages in the last loop then extend the timeout time. - // if we get messages stuck that are not expiring then the failureTime will occur - // failing the test. This will help with the scenario when the broker does not - // have enough CPU cycles to process the TTLs. - if (lastPass != messageCount) - { - failureTime = System.currentTimeMillis() + 2 * SERVER_TTL_TIMEOUT; - } - } - while(messageCount > 0L && System.currentTimeMillis() < failureTime); - - assertEquals("Messages not automatically expired: ", 0L, messageCount); - - producer.close(); - producerSession.close(); - producerConnection.close(); - } - - public void testPassiveTTLwithDurableSubscription() throws Exception - { - //Create Client 1 - Connection clientConnection = getConnection(); - - Session clientSession = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - // Create and close the durable subscriber - AMQTopic topic = new AMQTopic((AMQConnection) clientConnection, getTestQueueName()); - TopicSubscriber durableSubscriber = clientSession.createDurableSubscriber(topic, getTestQueueName(),"testprop='TimeToLiveTest'", false); - durableSubscriber.close(); - - //Create Producer - Connection producerConnection = getConnection(); - - producerConnection.start(); - - // Move to a Transacted session to ensure that all messages have been delivered to broker before - // we start waiting for TTL - Session producerSession = producerConnection.createSession(true, Session.SESSION_TRANSACTED); - - MessageProducer producer = producerSession.createProducer(topic); - - //Set TTL - int msg = 0; - producer.send(nextMessage(String.valueOf(msg), true, producerSession, producer)); - - producer.setTimeToLive(TIME_TO_LIVE); - - for (; msg < MSG_COUNT - 2; msg++) - { - producer.send(nextMessage(String.valueOf(msg), false, producerSession, producer)); - } - - //Reset TTL - producer.setTimeToLive(0L); - producer.send(nextMessage(String.valueOf(msg), false, producerSession, producer)); - - producerSession.commit(); - - //resubscribe - durableSubscriber = clientSession.createDurableSubscriber(topic, getTestQueueName(),"testprop='TimeToLiveTest'", false); - - // Ensure we sleep the required amount of time. - ReentrantLock waitLock = new ReentrantLock(); - Condition wait = waitLock.newCondition(); - final long MILLIS = 1000000L; - - long waitTime = TIME_TO_LIVE * MILLIS; - while (waitTime > 0) - { - try - { - waitLock.lock(); - - waitTime = wait.awaitNanos(waitTime); - } - catch (InterruptedException e) - { - //Stop if we are interrupted - fail(e.getMessage()); - } - finally - { - waitLock.unlock(); - } - - } - - clientConnection.start(); - - //Receive Message 0 - // Set 5s receive time for messages we expect to receive. - Message receivedFirst = durableSubscriber.receive(5000); - Message receivedSecond = durableSubscriber.receive(5000); - Message receivedThird = durableSubscriber.receive(1000); - - // Log the messages to help diagnosis incase of failure - _logger.info("First:"+receivedFirst); - _logger.info("Second:"+receivedSecond); - _logger.info("Third:"+receivedThird); - - // Only first and last messages sent should survive expiry - Assert.assertNull("More messages received", receivedThird); - - Assert.assertNotNull("First message not received", receivedFirst); - Assert.assertTrue("First message doesn't have first set.", receivedFirst.getBooleanProperty("first")); - Assert.assertEquals("First message has incorrect TTL.", 0L, receivedFirst.getLongProperty("TTL")); - - Assert.assertNotNull("Final message not received", receivedSecond); - Assert.assertFalse("Final message has first set.", receivedSecond.getBooleanProperty("first")); - Assert.assertEquals("Final message has incorrect TTL.", 0L, receivedSecond.getLongProperty("TTL")); - - clientSession.unsubscribe(getTestQueueName()); - clientConnection.close(); - - producerConnection.close(); - } - - public void testActiveTTLwithDurableSubscription() throws Exception - { - //Create Client 1 - Connection clientConnection = getConnection(); - Session clientSession = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - // Create and close the durable subscriber - AMQTopic topic = new AMQTopic((AMQConnection) clientConnection, getTestQueueName()); - TopicSubscriber durableSubscriber = clientSession.createDurableSubscriber(topic, "MyDurableTTLSubscription","testprop='TimeToLiveTest'", false); - durableSubscriber.close(); - - //Create Producer - Connection producerConnection = getConnection(); - AMQSession producerSession = (AMQSession) producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageProducer producer = producerSession.createProducer(topic); - producer.setTimeToLive(1000L); - - // send Messages - for(int i = 0; i < MSG_COUNT; i++) - { - producer.send(producerSession.createTextMessage("Message: "+i)); - } - long failureTime = System.currentTimeMillis() + 2 * SERVER_TTL_TIMEOUT; - - // check Queue depth for up to TIMEOUT seconds after the Queue Depth hasn't changed for 100ms. - long messageCount = MSG_COUNT; - long lastPass; - AMQQueue subcriptionQueue = new AMQQueue("amq.topic","clientid" + ":" + "MyDurableTTLSubscription"); - do - { - lastPass = messageCount; - Thread.sleep(100); - messageCount = producerSession.getQueueDepth((AMQDestination) subcriptionQueue); - - // If we have received messages in the last loop then extend the timeout time. - // if we get messages stuck that are not expiring then the failureTime will occur - // failing the test. This will help with the scenario when the broker does not - // have enough CPU cycles to process the TTLs. - if (lastPass != messageCount) - { - failureTime = System.currentTimeMillis() + 2 * SERVER_TTL_TIMEOUT; - } - } - while(messageCount > 0L && System.currentTimeMillis() < failureTime); - - assertEquals("Messages not automatically expired: ", 0L, messageCount); - - producer.close(); - producerSession.close(); - producerConnection.close(); - - clientSession.unsubscribe("MyDurableTTLSubscription"); - clientSession.close(); - clientConnection.close(); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java deleted file mode 100644 index 789ad420d8..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.security.acl; - -import org.apache.commons.lang.StringUtils; -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQConnectionURL; -import org.apache.qpid.jms.ConnectionListener; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.url.URLSyntaxException; - -import javax.jms.Connection; -import javax.jms.ExceptionListener; -import javax.jms.JMSException; -import javax.naming.NamingException; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -/** - * Abstract test case for ACLs. - * - * This base class contains convenience methods to manage ACL files and implements a mechanism that allows each - * test method to run its own setup code before the broker starts. - * - * @see ExternalACLTest - * @see ExternalACLJMXTest - * @see ExhaustiveACLTest - */ -public abstract class AbstractACLTestCase extends QpidBrokerTestCase implements ConnectionListener -{ - /** Used to synchronise {@link #tearDown()} when exceptions are thrown */ - protected CountDownLatch _exceptionReceived; - - @Override - public void setUp() throws Exception - { - getBrokerConfiguration().addGroupFileConfiguration(System.getProperty(QPID_HOME) + "/etc/groups-systests"); - - // run test specific setup - String testSetup = StringUtils.replace(getName(), "test", "setUp"); - try - { - Method setup = getClass().getDeclaredMethod(testSetup); - setup.invoke(this); - } - catch (NoSuchMethodException e) - { - // Ignore - } - catch (InvocationTargetException e) - { - throw (Exception) e.getTargetException(); - } - - super.setUp(); - } - - @Override - public void tearDown() throws Exception - { - try - { - super.tearDown(); - } - catch (JMSException e) - { - //we're throwing this away as it can happen in this test as the state manager remembers exceptions - //that we provoked with authentication failures, where the test passes - we can ignore on con close - } - } - - public void writeACLFile(final String...rules) throws IOException - { - writeACLFileUtil(this, rules); - } - - public static void writeACLFileUtil(QpidBrokerTestCase testcase, String...rules) throws IOException - { - File aclFile = File.createTempFile(testcase.getClass().getSimpleName(), testcase.getName()); - aclFile.deleteOnExit(); - - testcase.getBrokerConfiguration().addAclFileConfiguration(aclFile.getAbsolutePath()); - - PrintWriter out = new PrintWriter(new FileWriter(aclFile)); - out.println(String.format("# %s", testcase.getName())); - for (String line : rules) - { - out.println(line); - } - out.close(); - } - - /** - * Creates a connection to the broker, and sets a connection listener to prevent failover and an exception listener - * with a {@link CountDownLatch} to synchronise in the {@link #check403Exception(Throwable)} method and allow the - * {@link #tearDown()} method to complete properly. - */ - public Connection getConnection(String vhost, String username, String password) throws NamingException, JMSException, URLSyntaxException - { - AMQConnection connection = (AMQConnection) getConnection(createConnectionURL(vhost, username, password)); - - //Prevent Failover - connection.setConnectionListener(this); - - //QPID-2081: use a latch to sync on exception causing connection close, to work - //around the connection close race during tearDown() causing sporadic failures - _exceptionReceived = new CountDownLatch(1); - - connection.setExceptionListener(new ExceptionListener() - { - public void onException(JMSException e) - { - _exceptionReceived.countDown(); - } - }); - - return (Connection) connection; - } - - // Connection Listener Interface - Used here to block failover - - public void bytesSent(long count) - { - } - - public void bytesReceived(long count) - { - } - - public boolean preFailover(boolean redirect) - { - //Prevent failover. - return false; - } - - public boolean preResubscribe() - { - return false; - } - - public void failoverComplete() - { - } - - /** - * Convenience method to build an {@link AMQConnectionURL} with the right parameters. - */ - public AMQConnectionURL createConnectionURL(String vhost, String username, String password) throws URLSyntaxException - { - String url = "amqp://" + username + ":" + password + "@clientid/" + vhost + "?brokerlist='" + getBroker() + "?retries='0''"; - return new AMQConnectionURL(url); - } - - /** - * Convenience method to validate a JMS exception with a linked {@link AMQConstant#ACCESS_REFUSED} 403 error code exception. - */ - public void check403Exception(Throwable t) throws Exception - { - assertNotNull("There was no linked exception", t); - assertTrue("Wrong linked exception type : " + t.getClass(), t instanceof AMQException); - assertEquals("Incorrect error code received", 403, ((AMQException) t).getErrorCode().getCode()); - - //use the latch to ensure the control thread waits long enough for the exception thread - //to have done enough to mark the connection closed before teardown commences - assertTrue("Timed out waiting for conneciton to report close", _exceptionReceived.await(2, TimeUnit.SECONDS)); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExhaustiveACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExhaustiveACLTest.java deleted file mode 100644 index 505b3035d3..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExhaustiveACLTest.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.security.acl; - -import javax.jms.Connection; -import javax.jms.MessageConsumer; -import javax.jms.Queue; -import javax.jms.Session; - -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.protocol.AMQConstant; - -/** - * ACL version 2/3 file testing to verify that ACL entries control queue creation with specific properties. - * - * Tests have their own ACL files that setup specific permissions, and then try to create queues with every possible combination - * of properties to show that rule matching works correctly. For example, a rule that specified {@code autodelete="true"} for - * queues with {@code name="temp.true.*"} as well should not affect queues that have names that do not match, or queues that - * are not autodelete, or both. Also checks that ACL entries only affect the specified users and virtual hosts. - */ -public class ExhaustiveACLTest extends AbstractACLTestCase -{ - - /** - * Creates a queue. - * - * Connects to the broker as a particular user and create the named queue on a virtual host, with the provided - * parameters. Uses a new {@link Connection} and {@link Session} and closes them afterwards. - */ - private void createQueue(String vhost, String user, String name, boolean autoDelete, boolean durable) throws Exception - { - Connection conn = getConnection(vhost, user, "guest"); - Session sess = conn.createSession(true, Session.SESSION_TRANSACTED); - conn.start(); - ((AMQSession) sess).createQueue(new AMQShortString(name), autoDelete, durable, false); - sess.commit(); - conn.close(); - } - - /** - * Calls {@link #createQueue(String, String, String, boolean, boolean)} with the provided parameters and checks that - * no exceptions were thrown. - */ - private void createQueueSuccess(String vhost, String user, String name, boolean autoDelete, boolean durable) throws Exception - { - try - { - createQueue(vhost, user, name, autoDelete, durable); - } - catch (AMQException e) - { - fail(String.format("Create queue should have worked for \"%s\" for user %s@%s, autoDelete=%s, durable=%s", - name, user, vhost, Boolean.toString(autoDelete), Boolean.toString(durable))); - } - } - - /** - * Calls {@link #createQueue(String, String, String, boolean, boolean)} with the provided parameters and checks that - * the exception thrown was an {@link AMQConstant#ACCESS_REFUSED} or 403 error code. - */ - private void createQueueFailure(String vhost, String user, String name, boolean autoDelete, boolean durable) throws Exception - { - try - { - createQueue(vhost, user, name, autoDelete, durable); - fail(String.format("Create queue should have failed for \"%s\" for user %s@%s, autoDelete=%s, durable=%s", - name, user, vhost, Boolean.toString(autoDelete), Boolean.toString(durable))); - } - catch (AMQException e) - { - assertEquals("Should be an ACCESS_REFUSED error", 403, e.getErrorCode().getCode()); - } - } - - public void setUpAuthoriseCreateQueueAutodelete() throws Exception - { - writeACLFile("acl allow client access virtualhost", - "acl allow server access virtualhost", - "acl allow client create queue name=\"temp.true.*\" autodelete=true", - "acl allow client create queue name=\"temp.false.*\" autodelete=false", - "acl deny client create queue", - "acl allow client delete queue", - "acl deny all create queue" - ); - } - - /** - * Test creation of temporary queues, with the autodelete property set to true. - */ - public void testAuthoriseCreateQueueAutodelete() throws Exception - { - createQueueSuccess("test", "client", "temp.true.00", true, false); - createQueueSuccess("test", "client", "temp.true.01", true, false); - createQueueSuccess("test", "client", "temp.true.02", true, true); - createQueueSuccess("test", "client", "temp.false.03", false, false); - createQueueSuccess("test", "client", "temp.false.04", false, false); - createQueueSuccess("test", "client", "temp.false.05", false, true); - createQueueFailure("test", "client", "temp.true.06", false, false); - createQueueFailure("test", "client", "temp.false.07", true, false); - createQueueFailure("test", "server", "temp.true.08", true, false); - createQueueFailure("test", "client", "temp.other.09", false, false); - } - - - public void setUpAuthoriseQueueAutodeleteDeleteByOther() throws Exception - { - writeACLFile("acl allow client access virtualhost", - "acl allow server access virtualhost", - "acl allow client create queue name=\"temp.true.*\" autodelete=true", - "acl allow server consume queue name=\"temp.true.*\"", - "acl allow server bind exchange", - "acl deny client create queue", - "acl allow client delete queue", - "acl deny all create queue" - ); - } - /** - * Test creation of temporary queues, with the autodelete property and then autodeleted. - */ - public void testAuthoriseQueueAutodeleteDeleteByOther() throws Exception - { - // stop the consumer trying to redeclare the queue - setTestSystemProperty(ClientProperties.QPID_DECLARE_QUEUES_PROP_NAME, "false"); - - // create a temp queue as use client - createQueueSuccess("test", "client", "temp.true.00", true, false); - - // consume from temp queue as user server - Connection conn = getConnection("test", "server", "guest"); - Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - conn.start(); - Queue queue = sess.createQueue("temp.true.00"); - MessageConsumer cons = sess.createConsumer(queue); - cons.close(); - sess.close(); - - sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - conn.start(); - - // test if the queue is bound to the default exchange - assertFalse(((AMQSession)sess).isQueueBound("","temp.true.00","temp.true.00",null)); - sess.close(); - - conn.close(); - - - } - - public void setUpAuthoriseCreateQueue() throws Exception - { - writeACLFile("acl allow client access virtualhost", - "acl allow server access virtualhost", - "acl allow client create queue name=\"create.*\"" - ); - } - - /** - * Tests creation of named queues. - * - * If a named queue is specified - */ - public void testAuthoriseCreateQueue() throws Exception - { - createQueueSuccess("test", "client", "create.00", true, true); - createQueueSuccess("test", "client", "create.01", true, false); - createQueueSuccess("test", "client", "create.02", false, true); - createQueueSuccess("test", "client", "create.03", true, false); - createQueueFailure("test", "server", "create.04", true, true); - createQueueFailure("test", "server", "create.05", true, false); - createQueueFailure("test", "server", "create.06", false, true); - createQueueFailure("test", "server", "create.07", true, false); - } - - public void setUpAuthoriseCreateQueueBoth() throws Exception - { - writeACLFile("acl allow all access virtualhost", - "acl allow client create queue name=\"create.*\"", - "acl allow all create queue temporary=true" - ); - } - - /** - * Tests creation of named queues. - * - * If a named queue is specified - */ - public void testAuthoriseCreateQueueBoth() throws Exception - { - createQueueSuccess("test", "client", "create.00", true, false); - createQueueSuccess("test", "client", "create.01", false, false); - createQueueFailure("test", "server", "create.02", false, false); - createQueueFailure("test", "guest", "create.03", false, false); - createQueueSuccess("test", "client", "tmp.00", true, false); - createQueueSuccess("test", "server", "tmp.01", true, false); - createQueueSuccess("test", "guest", "tmp.02", true, false); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java deleted file mode 100644 index 165fbed00c..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.security.acl; - -import org.apache.qpid.management.common.mbeans.ServerInformation; -import org.apache.qpid.server.security.access.ObjectType; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -import java.lang.management.ManagementFactory; -import java.lang.management.RuntimeMXBean; - -/** - * Tests that access to the JMX interface is governed only by {@link ObjectType#METHOD}/{@link ObjectType#ALL} - * rules and AMQP rights have no effect. - * - * Ensures that objects outside the Qpid domain are not governed by the ACL model. - */ -public class ExternalACLJMXTest extends AbstractACLTestCase -{ - - private JMXTestUtils _jmx; - - private static final String TEST_QUEUE_OWNER = "admin"; - private static final String TEST_VHOST = "test"; - private static final String TEST2_VHOST = "test2"; - - @Override - public void setUp() throws Exception - { - //remove the normal 'test' vhost, we will configure the vhosts below - getBrokerConfiguration(0).removeObjectConfiguration(org.apache.qpid.server.model.VirtualHostNode.class, TestBrokerConfiguration.ENTRY_NAME_VIRTUAL_HOST); - - createTestVirtualHostNode(0, TEST_VHOST); - createTestVirtualHostNode(0, TEST2_VHOST); - - getBrokerConfiguration().addJmxManagementConfiguration(); - - _jmx = new JMXTestUtils(this); - super.setUp(); - _jmx.open(); - } - - @Override - public void tearDown() throws Exception - { - _jmx.close(); - super.tearDown(); - } - - public void setUpDenyAllIsCatchAllRule() throws Exception - { - writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", - "#No more rules, default catch all (deny all) should apply"); - } - - public void testDenyAllIsCatchAllRule() throws Exception - { - //try a broker-level method - ServerInformation info = _jmx.getServerInformation(); - try - { - info.resetStatistics(); - fail("Exception not thrown"); - } - catch (SecurityException e) - { - assertEquals("Cause message incorrect", "Permission denied: UPDATE resetStatistics", e.getMessage()); - } - - //try a vhost-level method - try - { - _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true); - fail("Exception not thrown"); - } - catch (Exception e) - { - assertEquals("Cause message incorrect", "Permission denied: UPDATE createNewQueue", e.getMessage()); - } - - // Ensure that calls to MBeans outside the Qpid domain are not impeded. - final RuntimeMXBean runtimeBean = _jmx.getManagedObject(RuntimeMXBean.class, ManagementFactory.RUNTIME_MXBEAN_NAME); - runtimeBean.getName(); - // PASS - } - - /** - * Ensure an ALLOW ALL ALL rule allows access to both getters/setters. - */ - public void setUpAllowAll() throws Exception - { - writeACLFile("ACL ALLOW ALL ALL"); - } - - public void testAllowAll() throws Exception - { - ServerInformation info = _jmx.getServerInformation(); - info.getBuildVersion(); // getter - requires ACCESS - info.resetStatistics(); // setter - requires UPDATE - // PASS - } - - public void setUpVhostWithName() throws Exception - { - writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", - "ACL ALLOW admin UPDATE METHOD component='VirtualHost.VirtualHostManager' name='createNewQueue' virtualhost_name='"+ TEST_VHOST + "'", - "ACL DENY admin UPDATE METHOD component='VirtualHost.VirtualHostManager' name='createNewQueue' virtualhost_name='"+ TEST2_VHOST + "'"); - } - - public void testVhostWithName() throws Exception - { - _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true); - - try - { - _jmx.createQueue(TEST2_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true); - fail("Exception not thrown"); - } - catch (SecurityException e) - { - assertEquals("Cause message incorrect", "Permission denied: UPDATE createNewQueue", e.getMessage()); - } - } - - - /** - * admin user is allowed all update methods on the component at broker level. - */ - public void setUpUpdateComponentOnlyAllow() throws Exception - { - writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", - "ACL ALLOW admin UPDATE METHOD component='VirtualHost.VirtualHostManager'"); - } - - public void testUpdateComponentOnlyAllow() throws Exception - { - _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true); - // PASS - _jmx.deleteQueue(TEST_VHOST, getTestQueueName()); - // PASS - } - - - /** - * admin user is allowed all update methods on all components at broker level. - */ - public void setUpUpdateMethodOnlyAllow() throws Exception - { - writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", - "ACL ALLOW admin UPDATE METHOD"); - } - - public void testUpdateMethodOnlyAllow() throws Exception - { - _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true); - //PASS - _jmx.deleteQueue(TEST_VHOST, getTestQueueName()); - // PASS - } - - - /** - * admin user has JMX right, AMQP right is irrelevant. - */ - public void setUpCreateQueueSuccess() throws Exception - { - writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", - "ACL ALLOW admin UPDATE METHOD component='VirtualHost.VirtualHostManager' name='createNewQueue'"); - } - - public void testCreateQueueSuccess() throws Exception - { - _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true); - } - - - /** - * admin user has JMX right, verifies lack of AMQP rights is irrelevant. - */ - public void setUpCreateQueueSuccessNoAMQPRights() throws Exception - { - writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", - "ACL ALLOW admin UPDATE METHOD component='VirtualHost.VirtualHostManager' name='createNewQueue'", - "ACL DENY admin CREATE QUEUE"); - } - - public void testCreateQueueSuccessNoAMQPRights() throws Exception - { - _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true); - } - - - /** - * admin user does not have JMX right, AMQP right is irrelevant. - */ - public void setUpCreateQueueDenied() throws Exception - { - writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", - "ACL DENY admin UPDATE METHOD component='VirtualHost.VirtualHostManager' name='createNewQueue'"); - } - - public void testCreateQueueDenied() throws Exception - { - try - { - _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true); - fail("Exception not thrown"); - } - catch (SecurityException e) - { - assertEquals("Cause message incorrect", "Permission denied: UPDATE createNewQueue", e.getMessage()); - } - } - - - /** - * admin user does not have JMX right - */ - public void setUpServerInformationUpdateDenied() throws Exception - { - writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", - "ACL DENY admin UPDATE METHOD component='ServerInformation' name='resetStatistics'"); - } - - public void testServerInformationUpdateDenied() throws Exception - { - ServerInformation info = _jmx.getServerInformation(); - try - { - info.resetStatistics(); - fail("Exception not thrown"); - } - catch (SecurityException e) - { - assertEquals("Cause message incorrect", "Permission denied: UPDATE resetStatistics", e.getMessage()); - } - } - - - /** - * admin user has JMX right to check management API major version (but not minor version) - */ - public void setUpServerInformationAccessGranted() throws Exception - { - writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", - "ACL ALLOW-LOG admin ACCESS METHOD component='ServerInformation' name='getManagementApiMajorVersion'"); - } - - public void testServerInformationAccessGranted() throws Exception - { - ServerInformation info = _jmx.getServerInformation(); - info.getManagementApiMajorVersion(); - - try - { - info.getManagementApiMinorVersion(); - fail("Exception not thrown"); - } - catch (SecurityException e) - { - assertEquals("Cause message incorrect", "Permission denied: ACCESS getManagementApiMinorVersion", e.getMessage()); - } - } - - - /** - * admin user has JMX right to use the update method - */ - public void setUpServerInformationUpdateMethodPermission() throws Exception - { - writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", - "ACL ALLOW admin UPDATE METHOD component='ServerInformation' name='resetStatistics'"); - } - - public void testServerInformationUpdateMethodPermission() throws Exception - { - ServerInformation info = _jmx.getServerInformation(); - info.resetStatistics(); - // PASS - } - - - /** - * admin user has JMX right to use all types of method on ServerInformation - */ - public void setUpServerInformationAllMethodPermissions() throws Exception - { - writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", - "ACL ALLOW admin ALL METHOD component='ServerInformation'"); - } - - public void testServerInformationAllMethodPermissions() throws Exception - { - //try an update method - ServerInformation info = _jmx.getServerInformation(); - info.resetStatistics(); - // PASS - //try an access method - info.getManagementApiMinorVersion(); - // PASS - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLTest.java deleted file mode 100644 index 0e8f3cb7d8..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLTest.java +++ /dev/null @@ -1,487 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.security.acl; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.Session; -import javax.jms.TextMessage; -import javax.jms.Topic; -import javax.jms.TopicSubscriber; -import javax.naming.NamingException; - -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.url.URLSyntaxException; - -/** - * Tests the V2 ACLs. The tests perform basic AMQP operations like creating queues or exchanges and publishing and consuming messages, using - * JMS to contact the broker. - */ -public class ExternalACLTest extends AbstractACLTestCase -{ - - public void setUpAccessAuthorizedSuccess() throws Exception - { - writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST"); - } - - public void testAccessAuthorizedSuccess() throws Exception - { - Connection conn = getConnection("test", "client", "guest"); - conn.close(); - } - - public void setUpAccessNoRightsFailure() throws Exception - { - writeACLFile("ACL DENY-LOG client ACCESS VIRTUALHOST"); - } - - public void testAccessNoRightsFailure() throws Exception - { - try - { - getConnection("test", "client", "guest"); - fail("Connection was created."); - } - catch (JMSException e) - { - assertAccessDeniedException(e); - } - } - - private void assertAccessDeniedException(JMSException e) - { - assertEquals("Unexpected exception message", "Error creating connection: Permission denied: test", e.getMessage()); - - // JMSException -> linkedException -> cause = AMQException (403 or 320) - Exception linkedException = e.getLinkedException(); - assertNotNull("There was no linked exception", linkedException); - Throwable cause = linkedException.getCause(); - assertNotNull("Cause was null", cause); - assertTrue("Wrong linked exception type", cause instanceof AMQException); - AMQConstant errorCode = isBroker010() ? AMQConstant.CONNECTION_FORCED : AMQConstant.ACCESS_REFUSED; - assertEquals("Incorrect error code received", errorCode, ((AMQException) cause).getErrorCode()); - } - - public void setUpAccessVirtualHostWithName() throws Exception - { - writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST name='test'", "ACL DENY-LOG guest ACCESS VIRTUALHOST name='test'", - "ACL ALLOW-LOG server ACCESS VIRTUALHOST name='*'"); - } - - public void testAccessVirtualHostWithName() throws Exception - { - Connection conn = getConnection("test", "client", "guest"); - conn.close(); - - try - { - getConnection("test", "guest", "guest"); - fail("Access should be denied"); - } - catch (JMSException e) - { - assertAccessDeniedException(e); - } - - Connection conn2 = getConnection("test", "server", "guest"); - conn2.close(); - } - - public void setUpClientCreateVirtualHostQueue() throws Exception - { - writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", - "ACL ALLOW-LOG client CREATE QUEUE virtualhost_name='test'", - "ACL ALLOW-LOG client CONSUME QUEUE", - "ACL ALLOW-LOG client BIND EXCHANGE", - "ACL ALLOW-LOG guest ACCESS VIRTUALHOST", - "ACL DENY-LOG guest CREATE QUEUE virtualhost_name='test'"); - } - - public void testClientCreateVirtualHostQueue() throws NamingException, JMSException, AMQException, Exception - { - Connection conn = getConnection("test", "client", "guest"); - Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - Destination dest = sess.createQueue(getTestQueueName()); - sess.createConsumer(dest); - conn.close(); - - try - { - conn = getConnection("test", "guest", "guest"); - sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - sess.createConsumer(dest); - - fail("Queue creation for user 'guest' is denied"); - } - catch (JMSException e) - { - check403Exception(e.getLinkedException()); - } - } - - - public void setUpClientDeleteQueueSuccess() throws Exception - { - writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", - "ACL ALLOW-LOG client CREATE QUEUE durable=\"true\"", - "ACL ALLOW-LOG client CONSUME QUEUE name=\"clientid:kipper\"" , - "ACL ALLOW-LOG client BIND EXCHANGE name=\"amq.topic\" durable=true routingKey=kipper", - "ACL ALLOW-LOG client DELETE QUEUE durable=\"true\"", - "ACL ALLOW-LOG client UNBIND EXCHANGE name=\"amq.topic\" durable=true routingKey=kipper"); - } - - public void testClientDeleteQueueSuccess() throws Exception - { - Connection conn = getConnection("test", "client", "guest"); - Session sess = conn.createSession(true, Session.SESSION_TRANSACTED); - conn.start(); - - // create kipper - Topic kipper = sess.createTopic("kipper"); - TopicSubscriber subscriber = sess.createDurableSubscriber(kipper, "kipper"); - - subscriber.close(); - sess.unsubscribe("kipper"); - - //Do something to show connection is active. - sess.rollback(); - conn.close(); - } - - - public void setUpClientDeleteQueueFailure() throws Exception - { - writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", - "ACL ALLOW-LOG client CREATE QUEUE durable=\"true\"", - "ACL ALLOW-LOG client CONSUME QUEUE name=\"clientid:kipper\"" , - "ACL ALLOW-LOG client BIND EXCHANGE name=\"amq.topic\" durable=true routingKey=kipper", - "ACL DENY-LOG client DELETE QUEUE durable=\"true\"", - "ACL DENY-LOG client UNBIND EXCHANGE name=\"amq.topic\" durable=true routingKey=kipper"); - } - - public void testClientDeleteQueueFailure() throws Exception - { - Connection conn = getConnection("test", "client", "guest"); - Session sess = conn.createSession(true, Session.SESSION_TRANSACTED); - conn.start(); - - // create kipper - Topic kipper = sess.createTopic("kipper"); - TopicSubscriber subscriber = sess.createDurableSubscriber(kipper, "kipper"); - - subscriber.close(); - try - { - sess.unsubscribe("kipper"); - - //Do something to show connection is active. - sess.rollback(); - - fail("Exception was not thrown"); - } - catch (JMSException e) - { - // JMSException -> linedException = AMQException.403 - check403Exception(e.getLinkedException()); - } - } - - - public void testClientConsumeFromTempQueueSuccess() throws Exception - { - Connection conn = getConnection("test", "client", "guest"); - - Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - - conn.start(); - - sess.createConsumer(sess.createTemporaryQueue()); - } - - public void setUpClientConsumeFromNamedQueueValid() throws Exception - { - writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", - "ACL ALLOW-LOG client CREATE QUEUE name=\"example.RequestQueue\"", - "ACL ALLOW-LOG client CONSUME QUEUE name=\"example.RequestQueue\"" , - "ACL ALLOW-LOG client BIND EXCHANGE name=\"amq.direct\" routingKey=\"example.RequestQueue\""); - } - - - public void testClientConsumeFromNamedQueueValid() throws Exception - { - Connection conn = getConnection("test", "client", "guest"); - - Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - - conn.start(); - - sess.createConsumer(sess.createQueue("example.RequestQueue")); - } - - public void setUpClientConsumeFromNamedQueueFailure() throws Exception - { - writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", - "ACL ALLOW-LOG client CREATE QUEUE", - "ACL ALLOW-LOG client BIND EXCHANGE" , - "ACL DENY-LOG client CONSUME QUEUE name=\"IllegalQueue\""); - } - - public void testClientConsumeFromNamedQueueFailure() throws NamingException, Exception - { - Connection conn = getConnection("test", "client", "guest"); - Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - conn.start(); - Destination dest = sess.createQueue("IllegalQueue"); - - try - { - sess.createConsumer(dest); - - fail("Test failed as consumer was created."); - } - catch (JMSException e) - { - check403Exception(e.getLinkedException()); - } - } - - public void setUpClientCreateTemporaryQueueSuccess() throws Exception - { - writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", - "ACL ALLOW-LOG client CREATE QUEUE temporary=\"true\"", - "ACL ALLOW-LOG client BIND EXCHANGE name=\"amq.direct\" temporary=true" , - "ACL ALLOW-LOG client DELETE QUEUE temporary=\"true\"", - "ACL ALLOW-LOG client UNBIND EXCHANGE name=\"amq.direct\" temporary=true"); - } - - public void testClientCreateTemporaryQueueSuccess() throws JMSException, URLSyntaxException, Exception - { - Connection conn = getConnection("test", "client", "guest"); - Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - conn.start(); - - sess.createTemporaryQueue(); - conn.close(); - } - - public void setUpClientCreateTemporaryQueueFailed() throws Exception - { - writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", - "ACL DENY-LOG client CREATE QUEUE temporary=\"true\""); - } - - public void testClientCreateTemporaryQueueFailed() throws NamingException, Exception - { - Connection conn = getConnection("test", "client", "guest"); - Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - conn.start(); - - try - { - - session.createTemporaryQueue(); - - fail("Test failed as creation succeded."); - } - catch (JMSException e) - { - check403Exception(e.getLinkedException()); - } - } - - public void setUpClientCreateNamedQueueFailure() throws Exception - { - writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", - "ACL ALLOW-LOG client CREATE QUEUE name=\"ValidQueue\""); - } - - public void testClientCreateNamedQueueFailure() throws NamingException, JMSException, AMQException, Exception - { - Connection conn = getConnection("test", "client", "guest"); - Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - conn.start(); - Destination dest = sess.createQueue("IllegalQueue"); - - try - { - //Create a Named Queue as side effect - sess.createConsumer(dest); - fail("Test failed as Queue creation succeded."); - } - catch (JMSException e) - { - check403Exception(e.getLinkedException()); - } - } - - public void setUpClientPublishUsingTransactionSuccess() throws Exception - { - writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", - "ACL ALLOW-LOG client CREATE QUEUE", - "ACL ALLOW-LOG client BIND EXCHANGE" , - "ACL ALLOW-LOG client PUBLISH EXCHANGE name=\"amq.direct\" routingKey=\"example.RequestQueue\""); - } - - public void testClientPublishUsingTransactionSuccess() throws Exception - { - Connection conn = getConnection("test", "client", "guest"); - - Session sess = conn.createSession(true, Session.SESSION_TRANSACTED); - - conn.start(); - - Queue queue = sess.createQueue("example.RequestQueue"); - - ((AMQSession)sess).declareAndBind((AMQDestination)queue); - - MessageProducer sender = sess.createProducer(queue); - - sender.send(sess.createTextMessage("test")); - - //Send the message using a transaction as this will allow us to retrieve any errors that occur on the broker. - sess.commit(); - - conn.close(); - } - - public void setUpRequestResponseSuccess() throws Exception - { - // The group "messaging-users", referenced in the ACL below, is currently defined - // in broker/etc/groups-systests. - // We tolerate a dependency from this test to that file because its - // contents are expected to change rarely. - - writeACLFile("ACL ALLOW-LOG messaging-users ACCESS VIRTUALHOST", "# Server side", - "ACL ALLOW-LOG server CREATE QUEUE name=\"example.RequestQueue\"", - "ACL ALLOW-LOG server BIND EXCHANGE" , - "ACL ALLOW-LOG server PUBLISH EXCHANGE name=\"amq.direct\" routingKey=\"TempQueue*\"", - "ACL ALLOW-LOG server CONSUME QUEUE name=\"example.RequestQueue\"", - "# Client side", - "ACL ALLOW-LOG client PUBLISH EXCHANGE name=\"amq.direct\" routingKey=\"example.RequestQueue\"", - "ACL ALLOW-LOG client CONSUME QUEUE temporary=true", - "ACL ALLOW-LOG client BIND EXCHANGE name=\"amq.direct\" temporary=true", - "ACL ALLOW-LOG client UNBIND EXCHANGE name=\"amq.direct\" temporary=true", - "ACL ALLOW-LOG client CREATE QUEUE temporary=true", - "ACL ALLOW-LOG client DELETE QUEUE temporary=true"); - } - - - public void testRequestResponseSuccess() throws Exception - { - //Set up the Server - Connection serverConnection = getConnection("test", "server", "guest"); - Session serverSession = serverConnection.createSession(true, Session.SESSION_TRANSACTED); - Queue requestQueue = serverSession.createQueue("example.RequestQueue"); - MessageConsumer server = serverSession.createConsumer(requestQueue); - serverConnection.start(); - - //Set up the consumer - Connection clientConnection = getConnection("test", "client", "guest"); - Session clientSession = clientConnection.createSession(true, Session.SESSION_TRANSACTED); - Queue responseQueue = clientSession.createTemporaryQueue(); - MessageConsumer clientResponse = clientSession.createConsumer(responseQueue); - clientConnection.start(); - - // Client - Message request = clientSession.createTextMessage("Request"); - request.setJMSReplyTo(responseQueue); - - clientSession.createProducer(requestQueue).send(request); - clientSession.commit(); - - // Server - Message msg = server.receive(2000); - assertNotNull("Server should have received client's request", msg); - assertNotNull("Received msg should have Reply-To", msg.getJMSReplyTo()); - - MessageProducer sender = serverSession.createProducer(msg.getJMSReplyTo()); - sender.send(serverSession.createTextMessage("Response")); - serverSession.commit(); - - // Client - Message clientResponseMsg = clientResponse.receive(2000); - clientSession.commit(); - assertNotNull("Client did not receive response message,", clientResponseMsg); - assertEquals("Incorrect message received", "Response", ((TextMessage) clientResponseMsg).getText()); - } - - public void setUpClientDeleteQueueSuccessWithOnlyAllPermissions() throws Exception - { - writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", - "ACL ALLOW-LOG client ALL QUEUE", - "ACL ALLOW-LOG client ALL EXCHANGE"); - } - - public void testClientDeleteQueueSuccessWithOnlyAllPermissions() throws Exception - { - Connection conn = getConnection("test", "client", "guest"); - Session sess = conn.createSession(true, Session.SESSION_TRANSACTED); - conn.start(); - - // create kipper - String topicName = "kipper"; - Topic topic = sess.createTopic(topicName); - TopicSubscriber subscriber = sess.createDurableSubscriber(topic, topicName); - - subscriber.close(); - sess.unsubscribe(topicName); - - //Do something to show connection is active. - sess.rollback(); - conn.close(); - } - - public void setUpFirewallAllow() throws Exception - { - writeACLFile("ACL ALLOW client ACCESS VIRTUALHOST from_network=\"127.0.0.1\""); - } - - public void testFirewallAllow() throws Exception - { - getConnection("test", "client", "guest"); - // test pass because we successfully connected - } - - public void setUpFirewallDeny() throws Exception - { - writeACLFile("ACL DENY client ACCESS VIRTUALHOST from_network=\"127.0.0.1\""); - } - - public void testFirewallDeny() throws Exception - { - try - { - getConnection("test", "client", "guest"); - fail("We expected the connection to fail"); - } - catch(JMSException e) - { - // pass - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java deleted file mode 100644 index 0d0c1257a2..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.auth.manager; - -import static org.apache.qpid.test.utils.TestSSLConstants.BROKER_PEERSTORE; -import static org.apache.qpid.test.utils.TestSSLConstants.BROKER_PEERSTORE_PASSWORD; -import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE; -import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE_PASSWORD; -import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE; -import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD; -import static org.apache.qpid.test.utils.TestSSLConstants.UNTRUSTED_KEYSTORE; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.jms.Connection; -import javax.jms.JMSException; - -import org.apache.qpid.client.AMQConnectionURL; -import org.apache.qpid.management.common.mbeans.ManagedConnection; -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.Transport; -import org.apache.qpid.server.model.TrustStore; -import org.apache.qpid.server.security.FileTrustStore; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class ExternalAuthenticationTest extends QpidBrokerTestCase -{ - @Override - protected void setUp() throws Exception - { - // not calling super.setUp() to avoid broker start-up - setSystemProperty("javax.net.debug", "ssl"); - } - - /** - * Tests that when EXTERNAL authentication is used on the SSL port, clients presenting certificates are able to connect. - * Also, checks that default authentication manager PrincipalDatabaseAuthenticationManager is used on non SSL port. - */ - public void testExternalAuthenticationManagerOnSSLPort() throws Exception - { - setCommonBrokerSSLProperties(true); - super.setUp(); - - setClientKeystoreProperties(); - setClientTrustoreProperties(); - - try - { - getExternalSSLConnection(false); - } - catch (JMSException e) - { - fail("Should be able to create a connection to the SSL port: " + e.getMessage()); - } - - try - { - getConnection(); - } - catch (JMSException e) - { - fail("Should be able to create a connection with credentials to the standard port: " + e.getMessage()); - } - - } - - /** - * Tests that when EXTERNAL authentication manager is set on the non-SSL port, clients with valid username and password - * but not using ssl are unable to connect to the non-SSL port. - */ - public void testExternalAuthenticationManagerOnNonSslPort() throws Exception - { - setCommonBrokerSSLProperties(true); - getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT, Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_EXTERNAL_PROVIDER); - super.setUp(); - - setClientKeystoreProperties(); - setClientTrustoreProperties(); - - try - { - getConnection(); - fail("Connection should not succeed"); - } - catch (JMSException e) - { - // pass - } - } - - /** - * Tests that when EXTERNAL authentication manager is used, clients without certificates are unable to connect to the SSL port - * even with valid username and password. - */ - public void testExternalAuthenticationManagerWithoutClientKeyStore() throws Exception - { - setCommonBrokerSSLProperties(false); - super.setUp(); - - setClientTrustoreProperties(); - - try - { - getExternalSSLConnection(true); - fail("Connection should not succeed"); - } - catch (JMSException e) - { - // pass - } - } - - /** - * Tests that when using the EXTERNAL authentication provider and needing client auth, clients with - * untrusted certificates are unable to connect to the SSL port. - */ - public void testExternalAuthenticationDeniesUntrustedClientCert() throws Exception - { - setCommonBrokerSSLProperties(true); - super.setUp(); - - setUntrustedClientKeystoreProperties(); - setClientTrustoreProperties(); - - try - { - getExternalSSLConnection(false); - fail("Connection should not succeed"); - } - catch (JMSException e) - { - // pass - } - } - - /** - * Tests that when using the EXTERNAL auth provider and a 'peersOnly' truststore, clients using certs directly in - * in the store will be able to connect and clients using certs signed by the same CA but not in the store will not. - */ - public void testExternalAuthenticationWithPeersOnlyTrustStore() throws Exception - { - externalAuthenticationWithPeersOnlyTrustStoreTestImpl(false); - } - - /** - * Tests that when using the EXTERNAL auth provider, with both the regular trust store and a 'peersOnly' truststore, clients - * using certs signed by the CA in the trust store are allowed even if they are not present in the 'peersOnly' store. - */ - public void testExternalAuthenticationWithRegularAndPeersOnlyTrustStores() throws Exception - { - externalAuthenticationWithPeersOnlyTrustStoreTestImpl(true); - } - - private void externalAuthenticationWithPeersOnlyTrustStoreTestImpl(boolean useTrustAndPeerStore) throws Exception - { - String peerStoreName = "myPeerStore"; - - List storeNames = null; - if(useTrustAndPeerStore) - { - //Use the regular trust store AND the 'peersOnly' store. The regular trust store trusts the CA that - //signed both the app1 and app2 certs. The peersOnly store contains only app1 and so does not trust app2 - storeNames = Arrays.asList(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE, peerStoreName); - } - else - { - //use only the 'peersOnly' store, which contains only app1 and so does not trust app2 - storeNames = Arrays.asList(peerStoreName); - } - - //set the brokers SSL config, inc which SSL stores to use - setCommonBrokerSSLProperties(true, storeNames); - - //add the peersOnly store to the config - Map sslTrustStoreAttributes = new HashMap(); - sslTrustStoreAttributes.put(TrustStore.NAME, peerStoreName); - sslTrustStoreAttributes.put(FileTrustStore.PATH, BROKER_PEERSTORE); - sslTrustStoreAttributes.put(FileTrustStore.PASSWORD, BROKER_PEERSTORE_PASSWORD); - sslTrustStoreAttributes.put(FileTrustStore.PEERS_ONLY, true); - getBrokerConfiguration().addObjectConfiguration(TrustStore.class, sslTrustStoreAttributes); - - super.setUp(); - - setClientKeystoreProperties(); - setClientTrustoreProperties(); - - try - { - //use the app1 cert, which IS in the peerstore (and has CA in the trustStore) - getExternalSSLConnection(false, "&ssl_cert_alias='app1'"); - } - catch (JMSException e) - { - fail("Client's validation against the broker's multi store manager unexpectedly failed, when configured store was expected to allow."); - } - - try - { - //use the app2 cert, which is NOT in the peerstore (but is signed by the same CA as app1) - getExternalSSLConnection(false, "&ssl_cert_alias='app2'"); - if(!useTrustAndPeerStore) - { - fail("Client's validation against the broker's multi store manager unexpectedly passed, when configured store was expected to deny."); - } - } - catch (JMSException e) - { - if(useTrustAndPeerStore) - { - fail("Client's validation against the broker's multi store manager unexpectedly failed, when configured store was expected to allow."); - } - else - { - //expected, the CA in trust store should allow both app1 and app2 - } - } - } - - /** - * Tests the creation of usernames when EXTERNAL authentication is used. - * The username should be created as CN@DC1.DC2...DCn by default. - */ - public void testExternalAuthenticationManagerUsernameAsCN() throws Exception - { - JMXTestUtils jmxUtils = new JMXTestUtils(this); - - setCommonBrokerSSLProperties(true); - getBrokerConfiguration().addJmxManagementConfiguration(); - - super.setUp(); - - setClientKeystoreProperties(); - setClientTrustoreProperties(); - - try - { - getExternalSSLConnection(false, "&ssl_cert_alias='app2'"); - } - catch (JMSException e) - { - fail("Should be able to create a connection to the SSL port: " + e.getMessage()); - } - - // Getting the used username using JMX - jmxUtils.open(); - List connections = jmxUtils.getManagedConnections("test"); - assertNotNull("Connections are null", connections); - assertEquals("Unexpected number of connections", 1, connections.size()); - assertEquals("Wrong authorized ID", "app2@acme.org", connections.get(0).getAuthorizedId()); - } - - /** - * Tests the creation of usernames when EXTERNAL authentication is used. - * The username should be created as full DN when the useFullDN option is used. - */ - public void testExternalAuthenticationManagerUsernameAsDN() throws Exception - { - JMXTestUtils jmxUtils = new JMXTestUtils(this); - - setCommonBrokerSSLProperties(true); - getBrokerConfiguration().setObjectAttribute(AuthenticationProvider.class, TestBrokerConfiguration.ENTRY_NAME_EXTERNAL_PROVIDER, ExternalAuthenticationManager.ATTRIBUTE_USE_FULL_DN, "true"); - getBrokerConfiguration().addJmxManagementConfiguration(); - - super.setUp(); - - setClientKeystoreProperties(); - setClientTrustoreProperties(); - - try - { - getExternalSSLConnection(false, "&ssl_cert_alias='app2'"); - } - catch (JMSException e) - { - fail("Should be able to create a connection to the SSL port: " + e.getMessage()); - } - - // Getting the used username using JMX - jmxUtils.open(); - List connections = jmxUtils.getManagedConnections("test"); - assertNotNull("Connections are null", connections); - assertEquals("Unexpected number of connections", 1, connections.size()); - assertEquals("Wrong authorized ID", "CN=app2@acme.org,OU=art,O=acme,L=Toronto,ST=ON,C=CA", connections.get(0).getAuthorizedId()); - } - - private Connection getExternalSSLConnection(boolean includeUserNameAndPassword) throws Exception - { - return getExternalSSLConnection(includeUserNameAndPassword, ""); - } - - private Connection getExternalSSLConnection(boolean includeUserNameAndPassword, String optionString) throws Exception - { - String url = "amqp://%s@test/?brokerlist='tcp://localhost:%s?ssl='true'&sasl_mechs='EXTERNAL'%s'"; - if (includeUserNameAndPassword) - { - url = String.format(url, "guest:guest", String.valueOf(QpidBrokerTestCase.DEFAULT_SSL_PORT), optionString); - } - else - { - url = String.format(url, ":", String.valueOf(QpidBrokerTestCase.DEFAULT_SSL_PORT), optionString); - } - return getConnection(new AMQConnectionURL(url)); - } - - private void setCommonBrokerSSLProperties(boolean needClientAuth) - { - setCommonBrokerSSLProperties(needClientAuth, Collections.singleton(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE)); - } - - private void setCommonBrokerSSLProperties(boolean needClientAuth, Collection trustStoreNames) - { - TestBrokerConfiguration config = getBrokerConfiguration(); - - Map sslPortAttributes = new HashMap(); - sslPortAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); - sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT); - sslPortAttributes.put(Port.NEED_CLIENT_AUTH, String.valueOf(needClientAuth)); - sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT); - sslPortAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); - sslPortAttributes.put(Port.TRUST_STORES, trustStoreNames); - config.addObjectConfiguration(Port.class, sslPortAttributes); - - Map externalAuthProviderAttributes = new HashMap(); - externalAuthProviderAttributes.put(AuthenticationProvider.NAME, TestBrokerConfiguration.ENTRY_NAME_EXTERNAL_PROVIDER); - externalAuthProviderAttributes.put(AuthenticationProvider.TYPE, ExternalAuthenticationManager.PROVIDER_TYPE); - config.addObjectConfiguration(AuthenticationProvider.class, externalAuthProviderAttributes); - - config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT, Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_EXTERNAL_PROVIDER); - } - - private void setUntrustedClientKeystoreProperties() - { - setSystemProperty("javax.net.ssl.keyStore", UNTRUSTED_KEYSTORE); - setSystemProperty("javax.net.ssl.keyStorePassword", KEYSTORE_PASSWORD); - } - - private void setClientKeystoreProperties() - { - setSystemProperty("javax.net.ssl.keyStore", KEYSTORE); - setSystemProperty("javax.net.ssl.keyStorePassword", KEYSTORE_PASSWORD); - } - - private void setClientTrustoreProperties() - { - setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); - setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java deleted file mode 100644 index 1c32a3f671..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.server.security.auth.manager; - -import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE; -import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE_PASSWORD; -import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE; -import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import javax.jms.Connection; -import javax.jms.JMSException; - -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.Transport; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class MultipleAuthenticationManagersTest extends QpidBrokerTestCase -{ - @Override - protected void setUp() throws Exception - { - TestBrokerConfiguration config = getBrokerConfiguration(); - - Map externalAuthProviderAttributes = new HashMap(); - externalAuthProviderAttributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); - externalAuthProviderAttributes.put(AuthenticationProvider.NAME, TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER); - config.addObjectConfiguration(AuthenticationProvider.class, externalAuthProviderAttributes); - - Map sslPortAttributes = new HashMap(); - sslPortAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); - sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT); - sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT); - sslPortAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); - sslPortAttributes.put(Port.TRUST_STORES, Collections.singleton(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE)); - sslPortAttributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER); - config.addObjectConfiguration(Port.class, sslPortAttributes); - - // set the ssl system properties - setSystemProperty("javax.net.ssl.keyStore", KEYSTORE); - setSystemProperty("javax.net.ssl.keyStorePassword", KEYSTORE_PASSWORD); - setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); - setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); - setSystemProperty("javax.net.debug", "ssl"); - super.setUp(); - } - - private Connection getAnonymousSSLConnection() throws Exception - { - String url = "amqp://:@test/?brokerlist='tcp://localhost:%s?ssl='true''"; - - url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT); - - return new AMQConnection(url); - - } - - private Connection getAnonymousConnection() throws Exception - { - String url = "amqp://:@test/?brokerlist='tcp://localhost:%s'"; - - url = String.format(url,QpidBrokerTestCase.DEFAULT_PORT); - - return new AMQConnection(url); - - } - - - public void testMultipleAuthenticationManagers() throws Exception - { - try - { - Connection conn = getConnection(); - assertNotNull("Connection unexpectedly null", conn); - } - catch(JMSException e) - { - fail("Should be able to create a connection with credentials to the standard port. " + e.getMessage()); - } - - try - { - Connection conn = getAnonymousSSLConnection(); - assertNotNull("Connection unexpectedly null", conn); - } - catch(JMSException e) - { - fail("Should be able to create a anonymous connection to the SSL port. " + e.getMessage()); - } - - try - { - Connection conn = getAnonymousConnection(); - fail("Should not be able to create anonymous connection to the standard port"); - } - catch(AMQException e) - { - // pass - } - - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/stats/StatisticsReportingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/stats/StatisticsReportingTest.java deleted file mode 100644 index 04b8385e69..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/stats/StatisticsReportingTest.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.stats; - -import java.util.List; -import java.util.Map; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.TextMessage; - -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.VirtualHost; -import org.apache.qpid.server.model.VirtualHostNode; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.util.LogMonitor; - -/** - * Test generation of message/data statistics reporting and the ability - * to control from the configuration file. - */ -public class StatisticsReportingTest extends QpidBrokerTestCase -{ - private static final String VHOST_NAME1 = "vhost1"; - private static final String VHOST_NAME2 = "vhost2"; - private static final String VHOST_NAME3 = "vhost3"; - private static long STATISTICS_REPORTING_PERIOD_IN_SECONDS = 10l; - - protected LogMonitor _monitor; - protected static final String USER = "admin"; - - protected Connection _conToVhost1, _conToVhost2, _conToVhost3; - protected String _queueName = "statistics"; - protected Destination _queue; - protected String _brokerUrl; - private long _startTestTime; - - @Override - public void setUp() throws Exception - { - createTestVirtualHostNode(0, VHOST_NAME1); - createTestVirtualHostNode(0, VHOST_NAME2); - createTestVirtualHostNode(0, VHOST_NAME3); - - if (getName().equals("testEnabledStatisticsReporting")) - { - TestBrokerConfiguration config = getBrokerConfiguration(); - config.removeObjectConfiguration(VirtualHostNode.class, TestBrokerConfiguration.ENTRY_NAME_VIRTUAL_HOST); - config.setBrokerAttribute(Broker.STATISTICS_REPORTING_PERIOD, STATISTICS_REPORTING_PERIOD_IN_SECONDS); - } - - _monitor = new LogMonitor(_outputFile); - _startTestTime = System.currentTimeMillis(); - - super.setUp(); - - _brokerUrl = getBroker().toString(); - _conToVhost1 = new AMQConnection(_brokerUrl, USER, USER, "clientid", VHOST_NAME1); - _conToVhost2 = new AMQConnection(_brokerUrl, USER, USER, "clientid", VHOST_NAME2); - _conToVhost3 = new AMQConnection(_brokerUrl, USER, USER, "clientid", VHOST_NAME3); - - _conToVhost1.start(); - _conToVhost2.start(); - _conToVhost3.start(); - } - - @Override - public void tearDown() throws Exception - { - _conToVhost1.close(); - _conToVhost2.close(); - _conToVhost3.close(); - - super.tearDown(); - } - - /** - * Test enabling reporting. - */ - public void testEnabledStatisticsReporting() throws Exception - { - sendUsing(_conToVhost1, 10, 100); - sendUsing(_conToVhost2, 20, 100); - sendUsing(_conToVhost3, 15, 100); - - Thread.sleep(STATISTICS_REPORTING_PERIOD_IN_SECONDS * 1000); - - Map> brokerStatsData = _monitor.findMatches("BRK-1008", "BRK-1009", "VHT-1003", "VHT-1004"); - long endTestTime = System.currentTimeMillis(); - - int maxNumberOfReports = (int)((endTestTime - _startTestTime)/STATISTICS_REPORTING_PERIOD_IN_SECONDS); - - int brk1008LinesNumber = brokerStatsData.get("BRK-1008").size(); - int brk1009LinesNumber = brokerStatsData.get("BRK-1009").size(); - int vht1003LinesNumber = brokerStatsData.get("VHT-1003").size(); - int vht1004LinesNumber = brokerStatsData.get("VHT-1004").size(); - - assertTrue("Incorrect number of broker data stats log messages:" + brk1008LinesNumber, 2 <= brk1008LinesNumber - && brk1008LinesNumber <= maxNumberOfReports * 2); - assertTrue("Incorrect number of broker message stats log messages:" + brk1009LinesNumber, 2 <= brk1009LinesNumber - && brk1009LinesNumber <= maxNumberOfReports * 2); - assertTrue("Incorrect number of virtualhost data stats log messages:" + vht1003LinesNumber, 6 <= vht1003LinesNumber - && vht1003LinesNumber <= maxNumberOfReports * 6); - assertTrue("Incorrect number of virtualhost message stats log messages: " + vht1004LinesNumber, 6 <= vht1004LinesNumber - && vht1004LinesNumber <= maxNumberOfReports * 6); - } - - /** - * Test not enabling reporting. - */ - public void testNotEnabledStatisticsReporting() throws Exception - { - sendUsing(_conToVhost1, 10, 100); - sendUsing(_conToVhost2, 20, 100); - sendUsing(_conToVhost3, 15, 100); - - Thread.sleep(10 * 1000); // 15s - - List brokerStatsData = _monitor.findMatches("BRK-1008"); - List brokerStatsMessages = _monitor.findMatches("BRK-1009"); - List vhostStatsData = _monitor.findMatches("VHT-1003"); - List vhostStatsMessages = _monitor.findMatches("VHT-1004"); - - assertEquals("Incorrect number of broker data stats log messages", 0, brokerStatsData.size()); - assertEquals("Incorrect number of broker message stats log messages", 0, brokerStatsMessages.size()); - assertEquals("Incorrect number of virtualhost data stats log messages", 0, vhostStatsData.size()); - assertEquals("Incorrect number of virtualhost message stats log messages", 0, vhostStatsMessages.size()); - } - - private void sendUsing(Connection con, int number, int size) throws Exception - { - Session session = con.createSession(true, Session.SESSION_TRANSACTED); - createQueue(session); - MessageProducer producer = session.createProducer(_queue); - String content = new String(new byte[size]); - TextMessage msg = session.createTextMessage(content); - for (int i = 0; i < number; i++) - { - producer.send(msg); - } - session.commit(); - session.close(); - } - - private void createQueue(Session session) throws AMQException, JMSException - { - _queue = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, _queueName); - if (!((AMQSession) session).isQueueBound((AMQDestination) _queue)) - { - ((AMQSession) session).createQueue(new AMQShortString(_queueName), false, true, false, null); - ((AMQSession) session).declareAndBind((AMQDestination) new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, _queueName)); - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/store/PersistentStoreTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/store/PersistentStoreTest.java deleted file mode 100644 index c2ea420e4b..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/store/PersistentStoreTest.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.server.store; - -import java.util.ArrayList; -import java.util.List; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; - -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class PersistentStoreTest extends QpidBrokerTestCase -{ - private static final int NUM_MESSAGES = 100; - private Connection _con; - private Session _session; - private Destination _destination; - - public void setUp() throws Exception - { - super.setUp(); - _con = getConnection(); - } - - public void testCommittedMessagesSurviveBrokerNormalShutdown() throws Exception - { - sendAndCommitMessages(); - stopBroker(); - startBroker(); - confirmBrokerStillHasCommittedMessages(); - } - - public void testCommittedMessagesSurviveBrokerAbnormalShutdown() throws Exception - { - if (isInternalBroker()) - { - return; - } - - sendAndCommitMessages(); - killBroker(); - startBroker(); - confirmBrokerStillHasCommittedMessages(); - } - - public void testCommittedMessagesSurviveBrokerNormalShutdownMidTransaction() throws Exception - { - sendAndCommitMessages(); - sendMoreMessagesWithoutCommitting(); - stopBroker(); - startBroker(); - confirmBrokerStillHasCommittedMessages(); - } - - public void testCommittedMessagesSurviveBrokerAbnormalShutdownMidTransaction() throws Exception - { - if (isInternalBroker()) - { - return; - } - sendAndCommitMessages(); - sendMoreMessagesWithoutCommitting(); - killBroker(); - startBroker(); - confirmBrokerStillHasCommittedMessages(); - } - - private void sendAndCommitMessages() throws Exception - { - _session = _con.createSession(true, Session.SESSION_TRANSACTED); - _destination = _session.createQueue(getTestQueueName()); - // Create queue by consumer side-effect - _session.createConsumer(_destination).close(); - - sendMessage(_session, _destination, NUM_MESSAGES); - _session.commit(); - } - - private void sendMoreMessagesWithoutCommitting() throws Exception - { - sendMessage(_session, _destination, 5); - // sync to ensure that messages have reached the broker - ((AMQSession) _session).sync(); - } - - private void confirmBrokerStillHasCommittedMessages() throws Exception - { - Connection con = getConnection(); - Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - con.start(); - Destination destination = session.createQueue(getTestQueueName()); - MessageConsumer consumer = session.createConsumer(destination); - for (int i = 1; i <= NUM_MESSAGES; i++) - { - Message msg = consumer.receive(RECEIVE_TIMEOUT); - assertNotNull("Message " + i + " not received", msg); - assertEquals("Did not receive the expected message", i, msg.getIntProperty(INDEX)); - } - - Message msg = consumer.receive(100); - if(msg != null) - { - fail("No more messages should be received, but received additional message with index: " + msg.getIntProperty(INDEX)); - } - } - - /** - * This test requires that we can send messages without committing. - * QTC always commits the messages sent via sendMessages. - * - * @param session the session to use for sending - * @param destination where to send them to - * @param count no. of messages to send - * - * @return the sent messages - * - * @throws Exception - */ - @Override - public List sendMessage(Session session, Destination destination, - int count) throws Exception - { - List messages = new ArrayList(count); - - MessageProducer producer = session.createProducer(destination); - - for (int i = 1;i <= (count); i++) - { - Message next = createNextMessage(session, i); - - producer.send(next); - - messages.add(next); - } - - return messages; - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/store/SplitStoreTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/store/SplitStoreTest.java deleted file mode 100644 index 7916f39488..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/store/SplitStoreTest.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.server.store; - -import java.io.File; -import java.util.Collections; -import java.util.Map; - -import javax.jms.Connection; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.Queue; -import javax.jms.Session; - -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.server.model.VirtualHostNode; -import org.apache.qpid.server.virtualhostnode.AbstractVirtualHostNode; -import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNode; -import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNodeImpl; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.test.utils.TestFileUtils; -import org.apache.qpid.util.FileUtils; - -public class SplitStoreTest extends QpidBrokerTestCase -{ - private String _messageStorePath; - private String _configStorePath; - - @Override - protected void setUp() throws Exception - { - super.setUp(); - - String virtualHostWorkDir = System.getProperty("QPID_WORK") + File.separator + TestBrokerConfiguration.ENTRY_NAME_VIRTUAL_HOST + File.separator; - _messageStorePath = virtualHostWorkDir + "messageStore"; - _configStorePath = virtualHostWorkDir + "configStore"; - } - - @Override - protected void tearDown() throws Exception - { - try - { - super.tearDown(); - } - finally - { - TestFileUtils.delete(new File(_messageStorePath), true); - } - } - - @Override - public void startBroker() throws Exception - { - // Overridden to prevent QBTC starting the Broker. - } - - public void testJsonConfigurationStoreWithPersistentMessageStore() throws Exception - { - doTest(JsonVirtualHostNodeImpl.VIRTUAL_HOST_NODE_TYPE, getTestProfileVirtualHostNodeType()); - } - - public void testSeparateConfigurationAndMessageStoresOfTheSameType() throws Exception - { - doTest(getTestProfileVirtualHostNodeType(), getTestProfileVirtualHostNodeType()); - } - - private void configureAndStartBroker(String virtualHostNodeType, String virtualHostType) throws Exception - { - final String blueprint = String.format( - "{ \"type\" : \"%s\", \"storePath\" : \"%s\" }", virtualHostType, _messageStorePath); - final Map contextMap = Collections.singletonMap(AbstractVirtualHostNode.VIRTUALHOST_BLUEPRINT_CONTEXT_VAR, - blueprint); - - TestBrokerConfiguration config = getBrokerConfiguration(); - config.setObjectAttribute(VirtualHostNode.class, TestBrokerConfiguration.ENTRY_NAME_VIRTUAL_HOST, VirtualHostNode.TYPE, virtualHostNodeType); - config.setObjectAttribute(VirtualHostNode.class, TestBrokerConfiguration.ENTRY_NAME_VIRTUAL_HOST, VirtualHostNode.CONTEXT, contextMap); - config.setObjectAttribute(VirtualHostNode.class, TestBrokerConfiguration.ENTRY_NAME_VIRTUAL_HOST, JsonVirtualHostNode.STORE_PATH, _configStorePath); - - super.startBroker(); - } - - private void doTest(String nodeType, String path) throws Exception - { - configureAndStartBroker(nodeType, path); - - Connection connection = getConnection(); - Session session = connection.createSession(true, Session.SESSION_TRANSACTED); - Queue queue = session.createQueue(getTestQueueName()); - session.createConsumer(queue).close(); // Create durable queue by side effect - sendMessage(session, queue, 2); - connection.close(); - - restartBroker(); - - setTestSystemProperty(ClientProperties.QPID_DECLARE_QUEUES_PROP_NAME, "false"); - connection = getConnection(); - connection.start(); - session = connection.createSession(true, Session.SESSION_TRANSACTED); - MessageConsumer consumer = session.createConsumer(queue); - Message message = consumer.receive(1000); - session.commit(); - - assertNotNull("Message was not received after first restart", message); - assertEquals("Unexpected message received after first restart", 0, message.getIntProperty(INDEX)); - - stopBroker(); - File messageStoreFile = new File(_messageStorePath); - FileUtils.delete(messageStoreFile, true); - assertFalse("Store folder was not deleted", messageStoreFile.exists()); - super.startBroker(); - - connection = getConnection(); - connection.start(); - session = connection.createSession(true, Session.SESSION_TRANSACTED); - consumer = session.createConsumer(queue); - message = consumer.receive(500); - - assertNull("Message was received after store removal", message); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/store/VirtualHostMessageStoreTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/store/VirtualHostMessageStoreTest.java deleted file mode 100644 index dfc507d88a..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/store/VirtualHostMessageStoreTest.java +++ /dev/null @@ -1,875 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.store; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.io.File; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import javax.security.auth.Subject; - -import org.codehaus.jackson.map.ObjectMapper; - -import org.apache.qpid.common.AMQPFilterTypes; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.framing.amqp_8_0.BasicConsumeBodyImpl; -import org.apache.qpid.server.configuration.updater.TaskExecutor; -import org.apache.qpid.server.configuration.updater.TaskExecutorImpl; -import org.apache.qpid.server.connection.SessionPrincipal; -import org.apache.qpid.server.exchange.ExchangeImpl; -import org.apache.qpid.server.message.InstanceProperties; -import org.apache.qpid.server.message.MessageSource; -import org.apache.qpid.server.model.Binding; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.ConfiguredObject; -import org.apache.qpid.server.model.ConfiguredObjectFactory; -import org.apache.qpid.server.model.ExclusivityPolicy; -import org.apache.qpid.server.model.LifetimePolicy; -import org.apache.qpid.server.model.Queue; -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.model.UUIDGenerator; -import org.apache.qpid.server.model.VirtualHost; -import org.apache.qpid.server.model.VirtualHostNode; -import org.apache.qpid.server.protocol.AMQConnectionModel; -import org.apache.qpid.server.protocol.AMQSessionModel; -import org.apache.qpid.server.protocol.v0_8.AMQMessage; -import org.apache.qpid.server.protocol.v0_8.MessageMetaData; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.LastValueQueue; -import org.apache.qpid.server.queue.LastValueQueueImpl; -import org.apache.qpid.server.queue.PriorityQueue; -import org.apache.qpid.server.queue.PriorityQueueImpl; -import org.apache.qpid.server.queue.StandardQueueImpl; -import org.apache.qpid.server.txn.AutoCommitTransaction; -import org.apache.qpid.server.txn.ServerTransaction; -import org.apache.qpid.server.util.BrokerTestHelper; -import org.apache.qpid.server.virtualhost.TestMemoryVirtualHost; -import org.apache.qpid.server.virtualhost.VirtualHostImpl; -import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNode; -import org.apache.qpid.test.utils.QpidTestCase; -import org.apache.qpid.util.FileUtils; - -/** - * - * Virtualhost/store integration test. Tests for correct behaviour of the message store - * when exercised via the higher level functions of the store. - * - * For persistent stores, it validates that Exchanges, Queues, Bindings and - * Messages are persisted and recovered correctly. - */ -public class VirtualHostMessageStoreTest extends QpidTestCase -{ - - public static final int DEFAULT_PRIORTY_LEVEL = 5; - public static final String SELECTOR_VALUE = "Test = 'MST'"; - public static final String LVQ_KEY = "MST-LVQ-KEY"; - - private String nonDurableExchangeName = "MST-NonDurableDirectExchange"; - private String directExchangeName = "MST-DirectExchange"; - private String topicExchangeName = "MST-TopicExchange"; - - private String durablePriorityTopicQueueName = "MST-PriorityTopicQueue-Durable"; - private String durableTopicQueueName = "MST-TopicQueue-Durable"; - private String priorityTopicQueueName = "MST-PriorityTopicQueue"; - private String topicQueueName = "MST-TopicQueue"; - - private String durableExclusiveQueueName = "MST-Queue-Durable-Exclusive"; - private String durablePriorityQueueName = "MST-PriorityQueue-Durable"; - private String durableLastValueQueueName = "MST-LastValueQueue-Durable"; - private String durableQueueName = "MST-Queue-Durable"; - private String priorityQueueName = "MST-PriorityQueue"; - private String queueName = "MST-Queue"; - - private String directRouting = "MST-direct"; - private String topicRouting = "MST-topic"; - - private String queueOwner = "MST"; - - private VirtualHostImpl _virtualHost; - private String _storePath; - private VirtualHostNode _node; - private TaskExecutor _taskExecutor; - - public void setUp() throws Exception - { - super.setUp(); - - String nodeName = "node" + getName(); - String hostName = "host" + getName(); - _storePath = System.getProperty("QPID_WORK", TMP_FOLDER + File.separator + getTestName()) + File.separator + nodeName; - cleanup(new File(_storePath)); - - Broker broker = BrokerTestHelper.createBrokerMock(); - _taskExecutor = new TaskExecutorImpl(); - _taskExecutor.start(); - when(broker.getTaskExecutor()).thenReturn(_taskExecutor); - - ConfiguredObjectFactory factory = broker.getObjectFactory(); - Map nodeAttributes = new HashMap<>(); - nodeAttributes.put(ConfiguredObject.TYPE, getTestProfileVirtualHostNodeType()); - nodeAttributes.put(JsonVirtualHostNode.STORE_PATH, _storePath); - nodeAttributes.put(VirtualHostNode.NAME, nodeName); - - _node = factory.create(VirtualHostNode.class, nodeAttributes, broker); - _node.start(); - - final Map virtualHostAttributes = new HashMap<>(); - virtualHostAttributes.put(VirtualHost.NAME, hostName); - virtualHostAttributes.put(VirtualHost.NAME, hostName); - String bluePrint = getTestProfileVirtualHostNodeBlueprint(); - if (bluePrint == null) - { - bluePrint = "{type=\"" + TestMemoryVirtualHost.VIRTUAL_HOST_TYPE + "\"}"; - } - ObjectMapper objectMapper = new ObjectMapper(); - Map attrs = objectMapper.readValue(bluePrint, Map.class); - virtualHostAttributes.putAll(attrs); - _node.createChild(VirtualHost.class, virtualHostAttributes, _node); - - _virtualHost = (VirtualHostImpl)_node.getVirtualHost(); - - } - - @Override - public void tearDown() throws Exception - { - try - { - if (_virtualHost != null) - { - VirtualHostNode node = _virtualHost.getParent(VirtualHostNode.class); - node.close(); - } - } - finally - { - _taskExecutor.stopImmediately(); - super.tearDown(); - } - } - - protected void reloadVirtualHost() - { - assertEquals("Virtual host node is not active", State.ACTIVE, _virtualHost.getState()); - _node.stop(); - State currentState = _node.getState(); - assertEquals("Virtual host node is not stopped", State.STOPPED, currentState); - - _node.start(); - currentState = _node.getState(); - assertEquals("Virtual host node is not active", State.ACTIVE, currentState); - _virtualHost = (VirtualHostImpl) _node.getVirtualHost(); - } - - public void testQueueExchangeAndBindingCreation() throws Exception - { - assertEquals("Should not be any existing queues", 0, _virtualHost.getQueues().size()); - - createAllQueues(); - createAllTopicQueues(); - - //Register Non-Durable DirectExchange - ExchangeImpl nonDurableExchange = createExchange(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, nonDurableExchangeName, false); - bindAllQueuesToExchange(nonDurableExchange, directRouting); - - //Register DirectExchange - ExchangeImpl directExchange = createExchange(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, directExchangeName, true); - bindAllQueuesToExchange(directExchange, directRouting); - - //Register TopicExchange - ExchangeImpl topicExchange = createExchange(ExchangeDefaults.TOPIC_EXCHANGE_CLASS, topicExchangeName, true); - bindAllTopicQueuesToExchange(topicExchange, topicRouting); - - //Send Message To NonDurable direct Exchange = persistent - sendMessageOnExchange(nonDurableExchange, directRouting, true); - // and non-persistent - sendMessageOnExchange(nonDurableExchange, directRouting, false); - - //Send Message To direct Exchange = persistent - sendMessageOnExchange(directExchange, directRouting, true); - // and non-persistent - sendMessageOnExchange(directExchange, directRouting, false); - - //Send Message To topic Exchange = persistent - sendMessageOnExchange(topicExchange, topicRouting, true); - // and non-persistent - sendMessageOnExchange(topicExchange, topicRouting, false); - - //Ensure all the Queues have four messages (one transient, one persistent) x 2 exchange routings - validateMessageOnQueues(4, true); - //Ensure all the topics have two messages (one transient, one persistent) - validateMessageOnTopics(2, true); - - assertEquals("Not all queues correctly registered", - 10, _virtualHost.getQueues().size()); - } - - public void testMessagePersistence() throws Exception - { - testQueueExchangeAndBindingCreation(); - - reloadVirtualHost(); - - //Validate durable queues and subscriptions still have the persistent messages - validateMessageOnQueues(2, false); - validateMessageOnTopics(1, false); - } - - /** - * Tests message removal by running the testMessagePersistence() method above before - * clearing the queues, reloading the virtual host, and ensuring that the persistent - * messages were removed from the queues. - */ - public void testMessageRemoval() throws Exception - { - testMessagePersistence(); - - assertEquals("Incorrect number of queues registered after recovery", - 6, _virtualHost.getQueues().size()); - - //clear the queue - _virtualHost.getQueue(durableQueueName).clearQueue(); - - //check the messages are gone - validateMessageOnQueue(durableQueueName, 0); - - //reload and verify messages arent restored - reloadVirtualHost(); - - validateMessageOnQueue(durableQueueName, 0); - } - - /** - * Tests queue persistence by creating a selection of queues with differing properties, both - * durable and non durable, and ensuring that following the recovery process the correct queues - * are present and any property manipulations (eg queue exclusivity) are correctly recovered. - */ - public void testQueuePersistence() throws Exception - { - assertEquals("Should not be any existing queues", - 0, _virtualHost.getQueues().size()); - - //create durable and non durable queues/topics - createAllQueues(); - createAllTopicQueues(); - - //reload the virtual host, prompting recovery of the queues/topics - reloadVirtualHost(); - - assertEquals("Incorrect number of queues registered after recovery", - 6, _virtualHost.getQueues().size()); - - //Validate the non-Durable Queues were not recovered. - assertNull("Non-Durable queue still registered:" + priorityQueueName, - _virtualHost.getQueue(priorityQueueName)); - assertNull("Non-Durable queue still registered:" + queueName, - _virtualHost.getQueue(queueName)); - assertNull("Non-Durable queue still registered:" + priorityTopicQueueName, - _virtualHost.getQueue(priorityTopicQueueName)); - assertNull("Non-Durable queue still registered:" + topicQueueName, - _virtualHost.getQueue(topicQueueName)); - - //Validate normally expected properties of Queues/Topics - validateDurableQueueProperties(); - - //Update the durable exclusive queue's exclusivity - setQueueExclusivity(false); - validateQueueExclusivityProperty(false); - } - - /** - * Tests queue removal by creating a durable queue, verifying it recovers, and - * then removing it from the store, and ensuring that following the second reload - * process it is not recovered. - */ - public void testDurableQueueRemoval() throws Exception - { - //Register Durable Queue - createQueue(durableQueueName, false, true, false, false); - - assertEquals("Incorrect number of queues registered before recovery", - 1, _virtualHost.getQueues().size()); - - reloadVirtualHost(); - - assertEquals("Incorrect number of queues registered after first recovery", - 1, _virtualHost.getQueues().size()); - - //test that removing the queue means it is not recovered next time - - final AMQQueue queue = _virtualHost.getQueue(durableQueueName); - _virtualHost.getDurableConfigurationStore().remove(queue.asObjectRecord()); - - reloadVirtualHost(); - - assertEquals("Incorrect number of queues registered after second recovery", - 0, _virtualHost.getQueues().size()); - assertNull("Durable queue was not removed:" + durableQueueName, - _virtualHost.getQueue(durableQueueName)); - } - - /** - * Tests exchange persistence by creating a selection of exchanges, both durable - * and non durable, and ensuring that following the recovery process the correct - * durable exchanges are still present. - */ - public void testExchangePersistence() throws Exception - { - int origExchangeCount = _virtualHost.getExchanges().size(); - - Map> oldExchanges = createExchanges(); - - assertEquals("Incorrect number of exchanges registered before recovery", - origExchangeCount + 3, _virtualHost.getExchanges().size()); - - reloadVirtualHost(); - - //verify the exchanges present after recovery - validateExchanges(origExchangeCount, oldExchanges); - } - - /** - * Tests exchange removal by creating a durable exchange, verifying it recovers, and - * then removing it from the store, and ensuring that following the second reload - * process it is not recovered. - */ - public void testDurableExchangeRemoval() throws Exception - { - int origExchangeCount = _virtualHost.getExchanges().size(); - - createExchange(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, directExchangeName, true); - - assertEquals("Incorrect number of exchanges registered before recovery", - origExchangeCount + 1, _virtualHost.getExchanges().size()); - - reloadVirtualHost(); - - assertEquals("Incorrect number of exchanges registered after first recovery", - origExchangeCount + 1, _virtualHost.getExchanges().size()); - - //test that removing the exchange means it is not recovered next time - - final ExchangeImpl exchange = _virtualHost.getExchange(directExchangeName); - _virtualHost.getDurableConfigurationStore().remove(exchange.asObjectRecord()); - - reloadVirtualHost(); - - assertEquals("Incorrect number of exchanges registered after second recovery", - origExchangeCount, _virtualHost.getExchanges().size()); - assertNull("Durable exchange was not removed:" + directExchangeName, - _virtualHost.getExchange(directExchangeName)); - } - - /** - * Tests binding persistence by creating a selection of queues and exchanges, both durable - * and non durable, then adding bindings with and without selectors before reloading the - * virtual host and verifying that following the recovery process the correct durable - * bindings (those for durable queues to durable exchanges) are still present. - */ - public void testBindingPersistence() throws Exception - { - int origExchangeCount = _virtualHost.getExchanges().size(); - - createAllQueues(); - createAllTopicQueues(); - - Map> exchanges = createExchanges(); - - ExchangeImpl nonDurableExchange = exchanges.get(nonDurableExchangeName); - ExchangeImpl directExchange = exchanges.get(directExchangeName); - ExchangeImpl topicExchange = exchanges.get(topicExchangeName); - - bindAllQueuesToExchange(nonDurableExchange, directRouting); - bindAllQueuesToExchange(directExchange, directRouting); - bindAllTopicQueuesToExchange(topicExchange, topicRouting); - - assertEquals("Incorrect number of exchanges registered before recovery", - origExchangeCount + 3, _virtualHost.getExchanges().size()); - - reloadVirtualHost(); - - validateExchanges(origExchangeCount, exchanges); - - validateBindingProperties(); - } - - /** - * Tests binding removal by creating a durable exchange, and queue, binding them together, - * recovering to verify the persistence, then removing it from the store, and ensuring - * that following the second reload process it is not recovered. - */ - public void testDurableBindingRemoval() throws Exception - { - //create durable queue and exchange, bind them - ExchangeImpl exch = createExchange(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, directExchangeName, true); - createQueue(durableQueueName, false, true, false, false); - bindQueueToExchange(exch, directRouting, _virtualHost.getQueue(durableQueueName), false); - - assertEquals("Incorrect number of bindings registered before recovery", - 1, _virtualHost.getQueue(durableQueueName).getBindings().size()); - - //verify binding is actually normally recovered - reloadVirtualHost(); - - assertEquals("Incorrect number of bindings registered after first recovery", - 1, _virtualHost.getQueue(durableQueueName).getBindings().size()); - - exch = _virtualHost.getExchange(directExchangeName); - assertNotNull("Exchange was not recovered", exch); - - //remove the binding and verify result after recovery - unbindQueueFromExchange(exch, directRouting, _virtualHost.getQueue(durableQueueName), false); - - reloadVirtualHost(); - - assertEquals("Incorrect number of bindings registered after second recovery", - 0, _virtualHost.getQueue(durableQueueName).getBindings().size()); - } - - /** - * Validates that the durable exchanges are still present, the non durable exchange is not, - * and that the new exchanges are not the same objects as the provided list (i.e. that the - * reload actually generated new exchange objects) - */ - private void validateExchanges(int originalNumExchanges, Map> oldExchanges) - { - Collection> exchanges = (Collection>) _virtualHost.getExchanges(); - Collection exchangeNames = new ArrayList(exchanges.size()); - for(ExchangeImpl exchange : exchanges) - { - exchangeNames.add(exchange.getName()); - } - assertTrue(directExchangeName + " exchange NOT reloaded", - exchangeNames.contains(directExchangeName)); - assertTrue(topicExchangeName + " exchange NOT reloaded", - exchangeNames.contains(topicExchangeName)); - assertTrue(nonDurableExchangeName + " exchange reloaded", - !exchangeNames.contains(nonDurableExchangeName)); - - //check the old exchange objects are not the same as the new exchanges - assertTrue(directExchangeName + " exchange NOT reloaded", - _virtualHost.getExchange(directExchangeName) != oldExchanges.get(directExchangeName)); - assertTrue(topicExchangeName + " exchange NOT reloaded", - _virtualHost.getExchange(topicExchangeName) != oldExchanges.get(topicExchangeName)); - - // There should only be the original exchanges + our 2 recovered durable exchanges - assertEquals("Incorrect number of exchanges available", - originalNumExchanges + 2, _virtualHost.getExchanges().size()); - } - - /** Validates the Durable queues and their properties are as expected following recovery */ - private void validateBindingProperties() - { - - assertEquals("Incorrect number of (durable) queues following recovery", 6, _virtualHost.getQueues().size()); - - validateBindingProperties(_virtualHost.getQueue(durablePriorityQueueName).getBindings(), false); - validateBindingProperties(_virtualHost.getQueue(durablePriorityTopicQueueName).getBindings(), true); - validateBindingProperties(_virtualHost.getQueue(durableQueueName).getBindings(), false); - validateBindingProperties(_virtualHost.getQueue(durableTopicQueueName).getBindings(), true); - validateBindingProperties(_virtualHost.getQueue(durableExclusiveQueueName).getBindings(), false); - } - - /** - * Validate that each queue is bound only once following recovery (i.e. that bindings for non durable - * queues or to non durable exchanges are not recovered), and if a selector should be present - * that it is and contains the correct value - * - * @param bindings the set of bindings to validate - * @param useSelectors if set, check the binding has a JMS_SELECTOR argument and the correct value for it - */ - private void validateBindingProperties(Collection> bindings, boolean useSelectors) - { - assertEquals("Each queue should only be bound once.", 1, bindings.size()); - - Binding binding = bindings.iterator().next(); - - if (useSelectors) - { - assertTrue("Binding does not contain a Selector argument.", - binding.getArguments().containsKey(AMQPFilterTypes.JMS_SELECTOR.toString())); - assertEquals("The binding selector argument is incorrect", SELECTOR_VALUE, - binding.getArguments().get(AMQPFilterTypes.JMS_SELECTOR.toString()).toString()); - } - } - - private void setQueueExclusivity(boolean exclusive) throws MessageSource.ExistingConsumerPreventsExclusive - { - AMQQueue queue = _virtualHost.getQueue(durableExclusiveQueueName); - queue.setAttribute(Queue.EXCLUSIVE, queue.getExclusive(), exclusive ? ExclusivityPolicy.CONTAINER : ExclusivityPolicy.NONE); - } - - private void validateQueueExclusivityProperty(boolean expected) - { - AMQQueue queue = _virtualHost.getQueue(durableExclusiveQueueName); - - assertEquals("Queue exclusivity was incorrect", queue.isExclusive(), expected); - } - - - private void validateDurableQueueProperties() - { - validateQueueProperties(_virtualHost.getQueue(durablePriorityQueueName), true, true, false, false); - validateQueueProperties(_virtualHost.getQueue(durablePriorityTopicQueueName), true, true, false, false); - validateQueueProperties(_virtualHost.getQueue(durableQueueName), false, true, false, false); - validateQueueProperties(_virtualHost.getQueue(durableTopicQueueName), false, true, false, false); - validateQueueProperties(_virtualHost.getQueue(durableExclusiveQueueName), false, true, true, false); - validateQueueProperties(_virtualHost.getQueue(durableLastValueQueueName), false, true, true, true); - } - - private void validateQueueProperties(AMQQueue queue, boolean usePriority, boolean durable, boolean exclusive, boolean lastValueQueue) - { - if(usePriority || lastValueQueue) - { - assertNotSame("Queues cant be both Priority and LastValue based", usePriority, lastValueQueue); - } - - if (usePriority) - { - assertEquals("Queue is no longer a Priority Queue", PriorityQueueImpl.class, queue.getClass()); - assertEquals("Priority Queue does not have set priorities", - DEFAULT_PRIORTY_LEVEL, ((PriorityQueueImpl) queue).getPriorities()); - } - else if (lastValueQueue) - { - assertEquals("Queue is no longer a LastValue Queue", LastValueQueueImpl.class, queue.getClass()); - assertEquals("LastValue Queue Key has changed", LVQ_KEY, ((LastValueQueueImpl) queue).getLvqKey()); - } - else - { - assertEquals("Queue is not 'simple'", StandardQueueImpl.class, queue.getClass()); - } - - assertEquals("Queue owner is not as expected for queue " + queue.getName(), exclusive ? queueOwner : null, queue.getOwner()); - assertEquals("Queue durability is not as expected for queue " + queue.getName(), durable, queue.isDurable()); - assertEquals("Queue exclusivity is not as expected for queue " + queue.getName(), exclusive, queue.isExclusive()); - } - - /** - * Delete the Store Environment path - * - * @param environmentPath The configuration that contains the store environment path. - */ - private void cleanup(File environmentPath) - { - if (environmentPath.exists()) - { - FileUtils.delete(environmentPath, true); - } - } - - private void sendMessageOnExchange(ExchangeImpl exchange, String routingKey, boolean deliveryMode) - { - //Set MessagePersistence - BasicContentHeaderProperties properties = new BasicContentHeaderProperties(); - properties.setDeliveryMode(deliveryMode ? Integer.valueOf(2).byteValue() : Integer.valueOf(1).byteValue()); - FieldTable headers = properties.getHeaders(); - headers.setString("Test", "MST"); - properties.setHeaders(headers); - - MessagePublishInfo messageInfo = new TestMessagePublishInfo(exchange, false, false, routingKey); - - ContentHeaderBody headerBody = new ContentHeaderBody(BasicConsumeBodyImpl.CLASS_ID,0,properties,0l); - - MessageMetaData mmd = new MessageMetaData(messageInfo, headerBody, System.currentTimeMillis()); - - final StoredMessage storedMessage = _virtualHost.getMessageStore().addMessage(mmd); - final AMQMessage currentMessage = new AMQMessage(storedMessage); - - - - ServerTransaction trans = new AutoCommitTransaction(_virtualHost.getMessageStore()); - exchange.send(currentMessage, routingKey, InstanceProperties.EMPTY, trans, null); - - } - - private void createAllQueues() throws Exception - { - //Register Durable Priority Queue - createQueue(durablePriorityQueueName, true, true, false, false); - - //Register Durable Simple Queue - createQueue(durableQueueName, false, true, false, false); - - //Register Durable Exclusive Simple Queue - createQueue(durableExclusiveQueueName, false, true, true, false); - - //Register Durable LastValue Queue - createQueue(durableLastValueQueueName, false, true, true, true); - - //Register NON-Durable Priority Queue - createQueue(priorityQueueName, true, false, false, false); - - //Register NON-Durable Simple Queue - createQueue(queueName, false, false, false, false); - } - - private void createAllTopicQueues() throws Exception - { - //Register Durable Priority Queue - createQueue(durablePriorityTopicQueueName, true, true, false, false); - - //Register Durable Simple Queue - createQueue(durableTopicQueueName, false, true, false, false); - - //Register NON-Durable Priority Queue - createQueue(priorityTopicQueueName, true, false, false, false); - - //Register NON-Durable Simple Queue - createQueue(topicQueueName, false, false, false, false); - } - - private void createQueue(String queueName, boolean usePriority, boolean durable, boolean exclusive, boolean lastValueQueue) - throws Exception - { - - final Map queueArguments = new HashMap(); - - if(usePriority || lastValueQueue) - { - assertNotSame("Queues cant be both Priority and LastValue based", usePriority, lastValueQueue); - } - - if (usePriority) - { - queueArguments.put(PriorityQueue.PRIORITIES, DEFAULT_PRIORTY_LEVEL); - } - - if (lastValueQueue) - { - queueArguments.put(LastValueQueue.LVQ_KEY, LVQ_KEY); - } - - queueArguments.put(Queue.ID, UUIDGenerator.generateRandomUUID()); - queueArguments.put(Queue.NAME, queueName); - queueArguments.put(Queue.DURABLE, durable); - queueArguments.put(Queue.LIFETIME_POLICY, LifetimePolicy.PERMANENT); - queueArguments.put(Queue.EXCLUSIVE, exclusive ? ExclusivityPolicy.CONTAINER : ExclusivityPolicy.NONE); - AMQSessionModel sessionModel = mock(AMQSessionModel.class); - AMQConnectionModel connectionModel = mock(AMQConnectionModel.class); - when(sessionModel.getConnectionModel()).thenReturn(connectionModel); - when(connectionModel.getRemoteContainerName()).thenReturn(queueOwner); - SessionPrincipal principal = new SessionPrincipal(sessionModel); - AMQQueue queue = Subject.doAs(new Subject(true, - Collections.singleton(principal), - Collections.emptySet(), - Collections.emptySet()), - new PrivilegedAction>() - { - @Override - public AMQQueue run() - { - return _virtualHost.createQueue(queueArguments); - - } - }); - - - validateQueueProperties(queue, usePriority, durable, exclusive, lastValueQueue); - } - - private Map> createExchanges() throws Exception - { - Map> exchanges = new HashMap>(); - - //Register non-durable DirectExchange - exchanges.put(nonDurableExchangeName, createExchange(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, nonDurableExchangeName, false)); - - //Register durable DirectExchange and TopicExchange - exchanges.put(directExchangeName ,createExchange(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, directExchangeName, true)); - exchanges.put(topicExchangeName,createExchange(ExchangeDefaults.TOPIC_EXCHANGE_CLASS, topicExchangeName, true)); - - return exchanges; - } - - private ExchangeImpl createExchange(String type, String name, boolean durable) throws Exception - { - ExchangeImpl exchange = null; - - Map attributes = new HashMap(); - - attributes.put(org.apache.qpid.server.model.Exchange.NAME, name); - attributes.put(org.apache.qpid.server.model.Exchange.TYPE, type); - attributes.put(org.apache.qpid.server.model.Exchange.DURABLE, durable); - attributes.put(org.apache.qpid.server.model.Exchange.LIFETIME_POLICY, - durable ? LifetimePolicy.DELETE_ON_NO_LINKS : LifetimePolicy.PERMANENT); - attributes.put(org.apache.qpid.server.model.Exchange.ALTERNATE_EXCHANGE, null); - exchange = _virtualHost.createExchange(attributes); - - return exchange; - } - - private void bindAllQueuesToExchange(ExchangeImpl exchange, String routingKey) - { - bindQueueToExchange(exchange, routingKey, _virtualHost.getQueue(durablePriorityQueueName), false); - bindQueueToExchange(exchange, routingKey, _virtualHost.getQueue(durableQueueName), false); - bindQueueToExchange(exchange, routingKey, _virtualHost.getQueue(priorityQueueName), false); - bindQueueToExchange(exchange, routingKey, _virtualHost.getQueue(queueName), false); - bindQueueToExchange(exchange, routingKey, _virtualHost.getQueue(durableExclusiveQueueName), false); - } - - private void bindAllTopicQueuesToExchange(ExchangeImpl exchange, String routingKey) - { - - bindQueueToExchange(exchange, routingKey, _virtualHost.getQueue(durablePriorityTopicQueueName), true); - bindQueueToExchange(exchange, routingKey, _virtualHost.getQueue(durableTopicQueueName), true); - bindQueueToExchange(exchange, routingKey, _virtualHost.getQueue(priorityTopicQueueName), true); - bindQueueToExchange(exchange, routingKey, _virtualHost.getQueue(topicQueueName), true); - } - - - protected void bindQueueToExchange(ExchangeImpl exchange, - String routingKey, - AMQQueue queue, - boolean useSelector) - { - Map bindArguments = new HashMap(); - - if (useSelector) - { - bindArguments.put(AMQPFilterTypes.JMS_SELECTOR.toString(), SELECTOR_VALUE ); - } - - try - { - exchange.addBinding(routingKey, queue, bindArguments); - } - catch (Exception e) - { - fail(e.getMessage()); - } - } - - protected void unbindQueueFromExchange(ExchangeImpl exchange, - String routingKey, - AMQQueue queue, - boolean useSelector) - { - Map bindArguments = new HashMap(); - - if (useSelector) - { - bindArguments.put(AMQPFilterTypes.JMS_SELECTOR.toString(), SELECTOR_VALUE ); - } - - try - { - exchange.deleteBinding(routingKey, queue); - } - catch (Exception e) - { - fail(e.getMessage()); - } - } - - private void validateMessageOnTopics(long messageCount, boolean allQueues) - { - validateMessageOnQueue(durablePriorityTopicQueueName, messageCount); - validateMessageOnQueue(durableTopicQueueName, messageCount); - - if (allQueues) - { - validateMessageOnQueue(priorityTopicQueueName, messageCount); - validateMessageOnQueue(topicQueueName, messageCount); - } - } - - private void validateMessageOnQueues(long messageCount, boolean allQueues) - { - validateMessageOnQueue(durablePriorityQueueName, messageCount); - validateMessageOnQueue(durableQueueName, messageCount); - - if (allQueues) - { - validateMessageOnQueue(priorityQueueName, messageCount); - validateMessageOnQueue(queueName, messageCount); - } - } - - private void validateMessageOnQueue(String queueName, long messageCount) - { - AMQQueue queue = _virtualHost.getQueue(queueName); - - assertNotNull("Queue(" + queueName + ") not correctly registered:", queue); - - assertEquals("Incorrect Message count on queue:" + queueName, messageCount, queue.getQueueDepthMessages()); - } - - private class TestMessagePublishInfo implements MessagePublishInfo - { - - ExchangeImpl _exchange; - boolean _immediate; - boolean _mandatory; - String _routingKey; - - TestMessagePublishInfo(ExchangeImpl exchange, boolean immediate, boolean mandatory, String routingKey) - { - _exchange = exchange; - _immediate = immediate; - _mandatory = mandatory; - _routingKey = routingKey; - } - - @Override - public AMQShortString getExchange() - { - return new AMQShortString(_exchange.getName()); - } - - @Override - public void setExchange(AMQShortString exchange) - { - //no-op - } - - @Override - public boolean isImmediate() - { - return _immediate; - } - - @Override - public boolean isMandatory() - { - return _mandatory; - } - - @Override - public AMQShortString getRoutingKey() - { - return new AMQShortString(_routingKey); - } - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/util/AveragedRun.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/util/AveragedRun.java deleted file mode 100644 index 941c1d9499..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/util/AveragedRun.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.util; - -import java.util.Collection; -import java.util.concurrent.Callable; - -import org.apache.log4j.Logger; - -public class AveragedRun implements Callable -{ - private static final Logger _logger = Logger.getLogger(AveragedRun.class); - - private final RunStats stats = new RunStats(); - private final TimedRun test; - private final int iterations; - - public AveragedRun(TimedRun test, int iterations) - { - this.test = test; - this.iterations = iterations; - } - - public RunStats call() throws Exception - { - for (int i = 0; i < iterations; i++) - { - stats.record(test.call()); - } - return stats; - } - - public void run() throws Exception - { - _logger.info(test + ": " + call()); - } - - public String toString() - { - return test.toString(); - } - - static void run(Collection tests) throws Exception - { - for(AveragedRun test : tests) - { - test.run(); - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/util/RunStats.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/util/RunStats.java deleted file mode 100644 index ec67fc68b3..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/util/RunStats.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.util; - -public class RunStats -{ - private long min = Long.MAX_VALUE; - private long max; - private long total; - private int count; - - public void record(long time) - { - max = Math.max(time, max); - min = Math.min(time, min); - total += time; - count++; - } - - public long getMin() - { - return min; - } - - public long getMax() - { - return max; - } - - public long getAverage() - { - return total / count; - } - - public String toString() - { - return "avg=" + getAverage() + ", min=" + min + ", max=" + max; - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/util/TimedRun.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/util/TimedRun.java deleted file mode 100644 index 1291380311..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/util/TimedRun.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.util; - -import java.util.concurrent.Callable; - -public abstract class TimedRun implements Callable -{ - private final String description; - - public TimedRun(String description) - { - this.description = description; - } - - public Long call() throws Exception - { - setup(); - long start = System.currentTimeMillis(); - run(); - long stop = System.currentTimeMillis(); - teardown(); - return stop - start; - } - - public String toString() - { - return description; - } - - protected void setup() throws Exception{} - protected void teardown() throws Exception{} - protected abstract void run() throws Exception; -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.java deleted file mode 100644 index f6b56f64ce..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.java +++ /dev/null @@ -1,119 +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.systest.management.jmx; - -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.management.common.mbeans.ManagedBroker; -import org.apache.qpid.management.common.mbeans.ManagedExchange; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -/** - * Tests the JMX API for the Managed Broker. - * - */ -public class BrokerManagementTest extends QpidBrokerTestCase -{ - private static final String VIRTUAL_HOST = "test"; - - /** - * JMX helper. - */ - private JMXTestUtils _jmxUtils; - private ManagedBroker _managedBroker; - - public void setUp() throws Exception - { - getBrokerConfiguration().addJmxManagementConfiguration(); - - _jmxUtils = new JMXTestUtils(this); - - super.setUp(); - _jmxUtils.open(); - _managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST); - } - - public void tearDown() throws Exception - { - if (_jmxUtils != null) - { - _jmxUtils.close(); - } - super.tearDown(); - } - - /** - * Tests queue creation/deletion also verifying the automatic binding to the default exchange. - */ - public void testCreateQueueAndDeletion() throws Exception - { - final String queueName = getTestQueueName(); - - - _managedBroker.createNewQueue(queueName, "testowner", true); - - // Ensure the queue exists - assertNotNull("Queue object name expected to exist", _jmxUtils.getQueueObjectName(VIRTUAL_HOST, queueName)); - assertNotNull("Manager queue expected to be available", _jmxUtils.getManagedQueue(queueName)); - - - // Now delete the queue - _managedBroker.deleteQueue(queueName); - - - } - - /** - * Tests exchange creation/deletion via JMX API. - */ - public void testCreateExchangeAndUnregister() throws Exception - { - String exchangeName = getTestName(); - _managedBroker.createNewExchange(exchangeName, "topic", true); - - ManagedExchange exchange = _jmxUtils.getManagedExchange(exchangeName); - assertNotNull("Exchange should exist", exchange); - - _managedBroker.unregisterExchange(exchangeName); - } - - /** - * Tests that it is disallowed to unregister the default exchange. - */ - public void testUnregisterOfAmqDirectExchangeDisallowed() throws Exception - { - String amqDirectExchangeName = "amq.direct"; - - ManagedExchange amqDirectExchange = _jmxUtils.getManagedExchange(amqDirectExchangeName); - assertNotNull("Exchange should exist", amqDirectExchange); - try - { - _managedBroker.unregisterExchange(amqDirectExchangeName); - fail("Exception not thrown"); - } - catch (UnsupportedOperationException e) - { - // PASS - assertEquals("'"+amqDirectExchangeName+"' is a reserved exchange and can't be deleted", e.getMessage()); - } - amqDirectExchange = _jmxUtils.getManagedExchange(amqDirectExchangeName); - assertNotNull("Exchange should exist", amqDirectExchange); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java deleted file mode 100644 index 34b13dfaca..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java +++ /dev/null @@ -1,285 +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.systest.management.jmx; - -import java.io.IOException; -import java.util.Date; -import java.util.Iterator; -import java.util.List; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.Queue; -import javax.jms.Session; -import javax.management.JMException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.TabularData; - -import org.apache.commons.lang.StringUtils; -import org.apache.qpid.common.QpidProperties; -import org.apache.qpid.management.common.mbeans.ManagedConnection; -import org.apache.qpid.management.common.mbeans.ManagedQueue; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class ConnectionManagementTest extends QpidBrokerTestCase -{ - private static final String VIRTUAL_HOST_NAME = "test"; - - private JMXTestUtils _jmxUtils; - private Connection _connection; - - public void setUp() throws Exception - { - getBrokerConfiguration().addJmxManagementConfiguration(); - - _jmxUtils = new JMXTestUtils(this); - - super.setUp(); - _jmxUtils.open(); - } - - public void tearDown() throws Exception - { - try - { - if (_jmxUtils != null) - { - _jmxUtils.close(); - } - } - finally - { - super.tearDown(); - } - } - - public void testNumberOfManagedConnectionsMatchesNumberOfClientConnections() throws Exception - { - assertEquals("Expected no managed connections", 0, getManagedConnections().size()); - - _connection = getConnection(); - assertEquals("Expected one managed connection", 1, getManagedConnections().size()); - - _connection.close(); - assertEquals("Expected no managed connections after client connection closed", 0, getManagedConnections().size()); - } - - public void testGetAttributes() throws Exception - { - _connection = getConnection(); - final ManagedConnection mBean = getConnectionMBean(); - - checkAuthorisedId(mBean); - checkClientVersion(mBean); - checkClientId(mBean); - } - - public void testNonTransactedSession() throws Exception - { - _connection = getConnection(); - - boolean transactional = false; - boolean flowBlocked = false; - - _connection.createSession(transactional, Session.AUTO_ACKNOWLEDGE); - - final ManagedConnection mBean = getConnectionMBean(); - final CompositeDataSupport row = getTheOneChannelRow(mBean); - assertChannelRowData(row, 0, transactional, flowBlocked); - } - - public void testTransactedSessionWithUnackMessages() throws Exception - { - _connection = getConnection(); - _connection.start(); - - boolean transactional = true; - int numberOfMessages = 2; - final Session session = _connection.createSession(transactional, Session.SESSION_TRANSACTED); - final Destination destination = session.createQueue(getTestQueueName()); - final MessageConsumer consumer = session.createConsumer(destination); - - sendMessage(session, destination, numberOfMessages); - receiveMessagesWithoutCommit(consumer, numberOfMessages); - - final ManagedConnection mBean = getConnectionMBean(); - final CompositeDataSupport row = getTheOneChannelRow(mBean); - boolean flowBlocked = false; - assertChannelRowData(row, numberOfMessages, transactional, flowBlocked); - - // check that commit advances the lastIoTime - final Date initialLastIOTime = mBean.getLastIoTime(); - session.commit(); - assertTrue("commit should have caused last IO time to advance", mBean.getLastIoTime().after(initialLastIOTime)); - - // check that channels() now returns one session with no unacknowledged messages - final CompositeDataSupport rowAfterCommit = getTheOneChannelRow(mBean); - final Number unackCountAfterCommit = (Number) rowAfterCommit.get(ManagedConnection.UNACKED_COUNT); - assertEquals("Unexpected number of unacknowledged messages", 0, unackCountAfterCommit); - } - - - public void testProducerFlowBlocked() throws Exception - { - _connection = getConnection(); - _connection.start(); - - String queueName = getTestQueueName(); - Session session = _connection.createSession(true, Session.SESSION_TRANSACTED); - Queue queue = session.createQueue(queueName); - createQueueOnBroker(session, queue); - - ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - managedQueue.setFlowResumeCapacity(DEFAULT_MESSAGE_SIZE * 2l); - managedQueue.setCapacity(DEFAULT_MESSAGE_SIZE * 3l); - - final ManagedConnection managedConnection = getConnectionMBean(); - - // Check that producer flow is not block before test - final CompositeDataSupport rowBeforeSend = getTheOneChannelRow(managedConnection); - assertFlowBlocked(rowBeforeSend, false); - - - // Check that producer flow does not become block too soon - sendMessage(session, queue, 3); - final CompositeDataSupport rowBeforeFull = getTheOneChannelRow(managedConnection); - assertFlowBlocked(rowBeforeFull, false); - - // Fourth message will over-fill the queue (but as we are not sending more messages, client thread wont't block) - sendMessage(session, queue, 1); - final CompositeDataSupport rowAfterFull = getTheOneChannelRow(managedConnection); - assertFlowBlocked(rowAfterFull, true); - - // Consume two to bring the queue down to the resume capacity - MessageConsumer consumer = session.createConsumer(queue); - assertNotNull("Could not receive first message", consumer.receive(1000)); - assertNotNull("Could not receive second message", consumer.receive(1000)); - session.commit(); - - // Check that producer flow is no longer blocked - final CompositeDataSupport rowAfterReceive = getTheOneChannelRow(managedConnection); - assertFlowBlocked(rowAfterReceive, false); - } - - private void createQueueOnBroker(Session session, Destination destination) throws JMSException - { - session.createConsumer(destination).close(); // Create a consumer only to cause queue creation - } - - private void assertChannelRowData(final CompositeData row, int unacknowledgedMessages, boolean isTransactional, boolean flowBlocked) - { - assertNotNull(row); - assertEquals("Unexpected transactional flag", isTransactional, row.get(ManagedConnection.TRANSACTIONAL)); - assertEquals("Unexpected unacknowledged message count", unacknowledgedMessages, row.get(ManagedConnection.UNACKED_COUNT)); - assertEquals("Unexpected flow blocked", flowBlocked, row.get(ManagedConnection.FLOW_BLOCKED)); - } - - private void assertFlowBlocked(final CompositeData row, boolean flowBlocked) - { - assertNotNull(row); - assertEquals("Unexpected flow blocked", flowBlocked, row.get(ManagedConnection.FLOW_BLOCKED)); - } - - private void checkAuthorisedId(ManagedConnection mBean) throws Exception - { - assertEquals("Unexpected authorized id", GUEST_USERNAME, mBean.getAuthorizedId()); - } - - private void checkClientVersion(ManagedConnection mBean) throws Exception - { - String expectedVersion = QpidProperties.getReleaseVersion(); - assertTrue(StringUtils.isNotBlank(expectedVersion)); - - assertEquals("Unexpected version", expectedVersion, mBean.getVersion()); - } - - private void checkClientId(ManagedConnection mBean) throws Exception - { - String expectedClientId = _connection.getClientID(); - assertTrue(StringUtils.isNotBlank(expectedClientId)); - - assertEquals("Unexpected ClientId", expectedClientId, mBean.getClientId()); - } - - private ManagedConnection getConnectionMBean() - { - List connections = getManagedConnections(); - assertNotNull("Connection MBean is not found", connections); - assertEquals("Unexpected number of connection mbeans", 1, connections.size()); - final ManagedConnection mBean = connections.get(0); - assertNotNull("Connection MBean is null", mBean); - return mBean; - } - - private List getManagedConnections() - { - return _jmxUtils.getManagedConnections(VIRTUAL_HOST_NAME); - } - - private CompositeDataSupport getTheOneChannelRow(final ManagedConnection mBean) throws Exception - { - TabularData channelsData = getChannelsDataWithRetry(mBean); - - assertEquals("Unexpected number of rows in channel table", 1, channelsData.size()); - - @SuppressWarnings("unchecked") - final Iterator rowItr = (Iterator) channelsData.values().iterator(); - final CompositeDataSupport row = rowItr.next(); - return row; - } - - private void receiveMessagesWithoutCommit(final MessageConsumer consumer, int numberOfMessages) throws Exception - { - for (int i = 0; i < numberOfMessages; i++) - { - final Message m = consumer.receive(1000l); - assertNotNull("Message " + i + " is not received", m); - } - } - - private TabularData getChannelsDataWithRetry(final ManagedConnection mBean) - throws IOException, JMException - { - TabularData channelsData = mBean.channels(); - int retries = 0; - while(channelsData.size() == 0 && retries < 5) - { - sleep(); - channelsData = mBean.channels(); - retries++; - } - return channelsData; - } - - private void sleep() - { - try - { - Thread.sleep(50); - } - catch (InterruptedException ie) - { - Thread.currentThread().interrupt(); - } - }} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ExchangeManagementTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ExchangeManagementTest.java deleted file mode 100644 index 8c0a11b7cc..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ExchangeManagementTest.java +++ /dev/null @@ -1,164 +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.systest.management.jmx; - -import java.util.Collections; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; - -import org.apache.qpid.common.AMQPFilterTypes; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.management.common.mbeans.ManagedBroker; -import org.apache.qpid.management.common.mbeans.ManagedExchange; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class ExchangeManagementTest extends QpidBrokerTestCase -{ - private static final String MESSAGE_PROPERTY_INDEX = "index"; - private static final String MESSAGE_PROPERTY_TEST = "test"; - private static final String MESSAGE_PROPERTY_DUMMY = "dummy"; - private static final String SELECTOR_ARGUMENT = AMQPFilterTypes.JMS_SELECTOR.toString(); - private static final String SELECTOR = MESSAGE_PROPERTY_TEST + "='test'"; - private static final String VIRTUAL_HOST = "test"; - - private JMXTestUtils _jmxUtils; - private ManagedBroker _managedBroker; - private String _testQueueName; - private ManagedExchange _directExchange; - private ManagedExchange _topicExchange; - private ManagedExchange _fanoutExchange; - private ManagedExchange _headersExchange; - private Connection _connection; - private Session _session; - - public void setUp() throws Exception - { - getBrokerConfiguration().addJmxManagementConfiguration(); - - // to test exchange selectors the publishing of unroutable messages should be allowed - getBrokerConfiguration().setBrokerAttribute(Broker.CONNECTION_CLOSE_WHEN_NO_ROUTE, false); - - _jmxUtils = new JMXTestUtils(this); - - super.setUp(); - - _jmxUtils.open(); - - _managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST); - _testQueueName = getTestName(); - _managedBroker.createNewQueue(_testQueueName, null, true); - _directExchange = _jmxUtils.getManagedExchange(ExchangeDefaults.DIRECT_EXCHANGE_NAME); - _topicExchange = _jmxUtils.getManagedExchange(ExchangeDefaults.TOPIC_EXCHANGE_NAME); - _fanoutExchange = _jmxUtils.getManagedExchange(ExchangeDefaults.FANOUT_EXCHANGE_NAME); - _headersExchange = _jmxUtils.getManagedExchange(ExchangeDefaults.HEADERS_EXCHANGE_NAME); - - _connection = getConnection(); - _connection.start(); - _session = _connection.createSession(true, Session.SESSION_TRANSACTED); - } - - public void testCreateNewBindingWithArgumentsOnDirectExchange() throws Exception - { - String bindingKey = "test-direct-binding"; - - _directExchange.createNewBinding(_testQueueName, bindingKey, - Collections. singletonMap(SELECTOR_ARGUMENT, SELECTOR)); - - bindingTest(_session.createQueue(bindingKey)); - } - - public void testCreateNewBindingWithArgumentsOnTopicExchange() throws Exception - { - String bindingKey = "test-topic-binding"; - - _topicExchange.createNewBinding(_testQueueName, bindingKey, - Collections. singletonMap(SELECTOR_ARGUMENT, SELECTOR)); - - bindingTest(_session.createTopic(bindingKey)); - } - - public void testCreateNewBindingWithArgumentsOnFanoutExchange() throws Exception - { - _fanoutExchange.createNewBinding(_testQueueName, null, - Collections. singletonMap(SELECTOR_ARGUMENT, SELECTOR)); - - bindingTest(_session.createQueue("fanout://amq.fanout//?routingkey='routing-key-must-not-be-null'")); - } - - public void testCreateNewBindingWithArgumentsOnHeadersExchange() throws Exception - { - // headers exchange uses 'dummy' property to match messages - // i.e. all test messages have matching header value - _headersExchange.createNewBinding(_testQueueName, "x-match=any,dummy=test", - Collections. singletonMap(SELECTOR_ARGUMENT, SELECTOR)); - - bindingTest(_session.createQueue("headers://amq.match//?routingkey='routing-key-must-not-be-null'")); - } - - private void bindingTest(Destination destination) throws JMSException - { - publishMessages(destination, 4); - receiveAndAssertMessages(2); - } - - private void publishMessages(Destination destination, int messageNumber) throws JMSException - { - MessageProducer producer = _session.createProducer(destination); - - for (int i = 0; i < messageNumber; i++) - { - Message m = _session.createMessage(); - m.setStringProperty(MESSAGE_PROPERTY_TEST, i % 2 == 0 ? MESSAGE_PROPERTY_TEST : ""); - m.setIntProperty(MESSAGE_PROPERTY_INDEX, i); - m.setStringProperty(MESSAGE_PROPERTY_DUMMY, "test"); - producer.send(m); - } - _session.commit(); - } - - private void receiveAndAssertMessages(int messageNumber) throws JMSException - { - MessageConsumer consumer = _session.createConsumer(_session.createQueue(_testQueueName)); - - for (int i = 0; i < messageNumber; i++) - { - int index = i * 2; - Message message = consumer.receive(1000l); - assertNotNull("Expected message is not received at " + i, message); - assertEquals("Unexpected test property at " + i, MESSAGE_PROPERTY_TEST, - message.getStringProperty(MESSAGE_PROPERTY_TEST)); - assertEquals("Unexpected index property at " + i, index, message.getIntProperty(MESSAGE_PROPERTY_INDEX)); - } - - Message message = consumer.receive(1000l); - assertNull("Unexpected message received", message); - _session.commit(); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java deleted file mode 100644 index 3717c1594d..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java +++ /dev/null @@ -1,148 +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.systest.management.jmx; - -import java.io.File; -import java.util.List; - -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.TabularData; - -import org.apache.qpid.management.common.mbeans.LoggingManagement; -import org.apache.qpid.server.logging.log4j.LoggingManagementFacadeTest; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.util.FileUtils; -import org.apache.qpid.util.LogMonitor; - -/** - * System test for Logging Management. These tests rely on value set within - * test-profiles/log4j-test.xml. - * - * @see LoggingManagementMBeanTest - * @see LoggingManagementFacadeTest - * - */ -public class LoggingManagementTest extends QpidBrokerTestCase -{ - private JMXTestUtils _jmxUtils; - private LoggingManagement _loggingManagement; - private LogMonitor _monitor; - - public void setUp() throws Exception - { - getBrokerConfiguration().addJmxManagementConfiguration(); - - _jmxUtils = new JMXTestUtils(this); - - // System test normally run with log for4j test config from beneath test-profiles. We need to - // copy it as some of our tests write to this file. - - File tmpLogFile = File.createTempFile("log4j" + "." + getName(), ".xml"); - tmpLogFile.deleteOnExit(); - FileUtils.copy(getBrokerCommandLog4JFile(), tmpLogFile); - setBrokerCommandLog4JFile(tmpLogFile); - - super.setUp(); - _jmxUtils.open(); - - _loggingManagement = _jmxUtils.getLoggingManagement(); - _monitor = new LogMonitor(_outputFile); - } - - public void tearDown() throws Exception - { - try - { - if (_jmxUtils != null) - { - _jmxUtils.close(); - } - } - finally - { - super.tearDown(); - } - } - - public void testViewEffectiveRuntimeLoggerLevels() throws Exception - { - final String qpidMainLogger = "org.apache.qpid"; - - TabularData table = _loggingManagement.viewEffectiveRuntimeLoggerLevels(); - final CompositeData row = table.get(new String[] {qpidMainLogger} ); - assertChannelRow(row, qpidMainLogger, "DEBUG"); - } - - public void testViewConfigFileLoggerLevels() throws Exception - { - final String operationalLoggingLogger = "qpid.message"; - - TabularData table = _loggingManagement.viewConfigFileLoggerLevels(); - final CompositeData row = table.get(new String[] {operationalLoggingLogger} ); - assertChannelRow(row, operationalLoggingLogger, "INFO"); - } - - public void testTurnOffOrgApacheQpidAtRuntime() throws Exception - { - final String logger = "org.apache.qpid"; - _monitor.markDiscardPoint(); - _loggingManagement.setRuntimeLoggerLevel(logger, "OFF"); - - List matches = _monitor.waitAndFindMatches("Setting level to OFF for logger 'org.apache.qpid'", 5000); - assertEquals(1, matches.size()); - - TabularData table = _loggingManagement.viewEffectiveRuntimeLoggerLevels(); - final CompositeData row1 = table.get(new String[] {logger} ); - assertChannelRow(row1, logger, "OFF"); - } - - public void testChangesToConfigFileBecomeEffectiveAfterReload() throws Exception - { - final String operationalLoggingLogger = "qpid.message"; - assertEffectiveLoggingLevel(operationalLoggingLogger, "INFO"); - - _monitor.markDiscardPoint(); - _loggingManagement.setConfigFileLoggerLevel(operationalLoggingLogger, "OFF"); - - List matches = _monitor.waitAndFindMatches("Setting level to OFF for logger 'qpid.message'", 5000); - assertEquals(1, matches.size()); - - assertEffectiveLoggingLevel(operationalLoggingLogger, "INFO"); - - _loggingManagement.reloadConfigFile(); - - assertEffectiveLoggingLevel(operationalLoggingLogger, "OFF"); - } - - private void assertEffectiveLoggingLevel(String operationalLoggingLogger, String expectedLevel) - { - TabularData table = _loggingManagement.viewEffectiveRuntimeLoggerLevels(); - final CompositeData row1 = table.get(new String[] {operationalLoggingLogger} ); - assertChannelRow(row1, operationalLoggingLogger, expectedLevel); - } - - private void assertChannelRow(final CompositeData row, String logger, String level) - { - assertNotNull("No row for " + logger, row); - assertEquals("Unexpected logger name", logger, row.get(LoggingManagement.LOGGER_NAME)); - assertEquals("Unexpected level", level, row.get(LoggingManagement.LOGGER_LEVEL)); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/MBeanLifeCycleTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/MBeanLifeCycleTest.java deleted file mode 100644 index 71f911627e..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/MBeanLifeCycleTest.java +++ /dev/null @@ -1,140 +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.systest.management.jmx; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import javax.management.ObjectName; -import javax.servlet.http.HttpServletResponse; - -import org.apache.qpid.management.common.mbeans.ManagedBroker; -import org.apache.qpid.server.management.plugin.HttpManagement; -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.model.Plugin; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.VirtualHost; -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.model.VirtualHostNode; -import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager; -import org.apache.qpid.server.virtualhost.ProvidedStoreVirtualHostImpl; -import org.apache.qpid.server.virtualhostnode.memory.MemoryVirtualHostNode; -import org.apache.qpid.systest.rest.QpidRestTestCase; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class MBeanLifeCycleTest extends QpidRestTestCase -{ - private final static String TEST_VIRTUAL_HOST_MBEAN_SEARCH_QUERY = "org.apache.qpid:type=VirtualHost.VirtualHostManager,VirtualHost=" - + ObjectName.quote(TEST2_VIRTUALHOST); - private JMXTestUtils _jmxUtils; - - @Override - public void setUp() throws Exception - { - super.setUp(); - _jmxUtils = new JMXTestUtils(this); - _jmxUtils.open(); - } - - @Override - protected void customizeConfiguration() throws IOException - { - TestBrokerConfiguration config = getBrokerConfiguration(); - config.addHttpManagementConfiguration(); - config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.PORT, getRestTestHelper().getHttpPort()); - - Map anonymousProviderAttributes = new HashMap(); - anonymousProviderAttributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); - anonymousProviderAttributes.put(AuthenticationProvider.NAME, ANONYMOUS_AUTHENTICATION_PROVIDER); - config.addObjectConfiguration(AuthenticationProvider.class, anonymousProviderAttributes); - - // set password authentication provider on http port for the tests - config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER, - TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); - config.setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); - getBrokerConfiguration().addJmxManagementConfiguration(); - } - - @Override - public void tearDown() throws Exception - { - if (_jmxUtils != null) - { - _jmxUtils.close(); - } - super.tearDown(); - } - - public void testVirtualHostMBeanIsRegisteredOnVirtualHostCreation() throws Exception - { - String nodeName = "ntmp"; - String hostName = "htmp"; - - Map nodeData = new HashMap<>(); - nodeData.put(VirtualHostNode.NAME, nodeName); - nodeData.put(VirtualHostNode.TYPE, MemoryVirtualHostNode.VIRTUAL_HOST_NODE_TYPE); - getRestTestHelper().submitRequest("virtualhostnode/" + nodeName, "PUT", nodeData, HttpServletResponse.SC_CREATED); - - Map virtualhostData = new HashMap<>(); - virtualhostData.put(VirtualHost.NAME, nodeName); - virtualhostData.put(VirtualHost.TYPE, ProvidedStoreVirtualHostImpl.VIRTUAL_HOST_TYPE); - getRestTestHelper().submitRequest("virtualhost/" + nodeName + "/" + hostName, - "PUT", - virtualhostData, - HttpServletResponse.SC_CREATED); - - - ManagedBroker managedBroker = _jmxUtils.getManagedBroker(hostName); - assertNotNull("Host mBean is not created", managedBroker); - } - - public void testVirtualHostMBeanIsUnregisteredOnVirtualHostDeletion() throws Exception - { - boolean mBeanExists =_jmxUtils.doesManagedObjectExist(TEST_VIRTUAL_HOST_MBEAN_SEARCH_QUERY); - assertTrue("Host mBean is not registered", mBeanExists); - - getRestTestHelper().submitRequest("virtualhostnode/" + TEST2_VIRTUALHOST, "DELETE", HttpServletResponse.SC_OK); - - mBeanExists =_jmxUtils.doesManagedObjectExist(TEST_VIRTUAL_HOST_MBEAN_SEARCH_QUERY); - assertFalse("Host mBean is not unregistered", mBeanExists); - } - - public void testVirtualHostMBeanIsUnregisteredOnVirtualHostNodeStop() throws Exception - { - boolean mBeanExists =_jmxUtils.doesManagedObjectExist(TEST_VIRTUAL_HOST_MBEAN_SEARCH_QUERY); - assertTrue("Host mBean is not registered", mBeanExists); - - ManagedBroker managedBroker = _jmxUtils.getManagedBroker(TEST2_VIRTUALHOST); - assertNotNull("Host mBean is not created", managedBroker); - - Map nodeData = new HashMap(); - nodeData.put(VirtualHostNode.NAME, TEST2_VIRTUALHOST); - nodeData.put(VirtualHostNode.DESIRED_STATE, State.STOPPED.name()); - - int status = getRestTestHelper().submitRequest("virtualhostnode/" + TEST2_VIRTUALHOST, "PUT", nodeData); - assertEquals("Unexpected code", 200, status); - - mBeanExists =_jmxUtils.doesManagedObjectExist(TEST_VIRTUAL_HOST_MBEAN_SEARCH_QUERY); - assertFalse("Host mBean is not unregistered", mBeanExists); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java deleted file mode 100644 index 4358b4b450..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java +++ /dev/null @@ -1,482 +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.systest.management.jmx; - -import org.apache.qpid.management.common.mbeans.ManagedBroker; -import org.apache.qpid.management.common.mbeans.ManagedConnection; -import org.apache.qpid.management.common.mbeans.ManagedExchange; -import org.apache.qpid.server.logging.AbstractTestLogging; -import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject; -import org.apache.qpid.test.utils.JMXTestUtils; - -import javax.jms.Connection; -import javax.jms.ExceptionListener; -import javax.jms.JMSException; -import javax.management.JMException; -import java.io.IOException; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -/** - * Test class to test if any change in the broker JMX code is affesting the management console - * There are some hardcoding of management feature names and parameter names to create a customized - * look in the console. - */ -public class ManagementActorLoggingTest extends AbstractTestLogging -{ - private JMXTestUtils _jmxUtils; - private boolean _closed = false; - - @Override - public void setUp() throws Exception - { - getBrokerConfiguration().addJmxManagementConfiguration(); - - _jmxUtils = new JMXTestUtils(this); - - super.setUp(); - _jmxUtils.open(); - } - - @Override - public void tearDown() throws Exception - { - if(!_closed) - { - _jmxUtils.close(); - } - super.tearDown(); - } - - /** - * Description: - * When a connected client has its connection closed via the Management Console this will be logged as a CON-1002 message. - * Input: - * - * 1. Running Broker - * 2. Connected Client - * 3. Connection is closed via Management Console - * Output: - * - * CON-1002 : Close - * - * Validation Steps: - * 4. The CON ID is correct - * 5. This must be the last CON message for the Connection - * 6. It must be preceded by a CON-1001 for this Connection - * - * @throws Exception - {@see ManagedConnection.closeConnection and #getConnection} - * @throws java.io.IOException - if there is a problem reseting the log monitor - */ - public void testConnectionCloseViaManagement() throws IOException, Exception - { - //Create a connection to the broker - Connection connection = getConnection(); - - // Monitor the connection for an exception being thrown - // this should be a DisconnectionException but it is not this tests - // job to valiate that. Only use the exception as a synchronisation - // to check the log file for the Close message - final CountDownLatch exceptionReceived = new CountDownLatch(1); - connection.setExceptionListener(new ExceptionListener() - { - public void onException(JMSException e) - { - //Failover being attempted. - exceptionReceived.countDown(); - } - }); - - //Remove the connection close from any 0-10 connections - _monitor.markDiscardPoint(); - - // Get a managedConnection - ManagedConnection mangedConnection = _jmxUtils.getManagedObject(ManagedConnection.class, "org.apache.qpid:type=VirtualHost.Connection,*"); - - //Close the connection - mangedConnection.closeConnection(); - - //Wait for the connection to close - assertTrue("Timed out waiting for conneciton to report close", - exceptionReceived.await(2, TimeUnit.SECONDS)); - - //Validate results - List results = waitAndFindMatches("CON-1002"); - - assertEquals("Unexpected Connection Close count", 1, results.size()); - } - - /** - * Description: - * Exchange creation is possible from the Management Console. - * When an exchanged is created in this way then a EXH-1001 create message - * is expected to be logged. - * Input: - * - * 1. Running broker - * 2. Connected Management Console - * 3. Exchange Created via Management Console - * Output: - * - * EXH-1001 : Create : [Durable] Type: Name: - * - * Validation Steps: - * 4. The EXH ID is correct - * 5. The correct tags are present in the message based on the create options - * - * @throws java.io.IOException - if there is a problem reseting the log monitor - * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.deleteQueue} - */ - public void testCreateExchangeDirectTransientViaManagementConsole() throws IOException, JMException - { - _monitor.markDiscardPoint(); - - _jmxUtils.createExchange("test", getName(), "direct", false); - - // Validate - - //1 - ID is correct - List results = waitAndFindMatches("EXH-1001"); - - assertEquals("More than one exchange creation found", 1, results.size()); - - String log = getLogMessage(results, 0); - - // Validate correct exchange name - assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName())); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - } - - public void testCreateExchangeTopicTransientViaManagementConsole() throws IOException, JMException - { - //Remove any previous exchange declares - _monitor.markDiscardPoint(); - - _jmxUtils.createExchange("test", getName(), "topic", false); - - // Validate - - //1 - ID is correct - List results = waitAndFindMatches("EXH-1001"); - - assertEquals("More than one exchange creation found", 1, results.size()); - - String log = getLogMessage(results, 0); - - // Validate correct exchange name - assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName())); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - - } - - public void testCreateExchangeFanoutTransientViaManagementConsole() throws IOException, JMException - { - //Remove any previous exchange declares - _monitor.markDiscardPoint(); - - _jmxUtils.createExchange("test", getName(), "fanout", false); - - // Validate - - //1 - ID is correct - List results = waitAndFindMatches("EXH-1001"); - - assertEquals("More than one exchange creation found", 1, results.size()); - - String log = getLogMessage(results, 0); - - // Validate correct exchange name - assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName())); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - - } - - public void testCreateExchangeHeadersTransientViaManagementConsole() throws IOException, JMException - { - //Remove any previous exchange declares - _monitor.markDiscardPoint(); - - _jmxUtils.createExchange("test", getName(), "headers", false); - - // Validate - - //1 - ID is correct - List results = waitAndFindMatches("EXH-1001"); - - assertEquals("More than one exchange creation found", 1, results.size()); - - String log = getLogMessage(results, 0); - - // Validate correct exchange name - assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName())); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - - } - - /** - * Description: - * Queue creation is possible from the Management Console. When a queue is created in this way then a QUE-1001 create message is expected to be logged. - * Input: - * - * 1. Running broker - * 2. Connected Management Console - * 3. Queue Created via Management Console - * Output: - * - * QUE-1001 : Create : Transient Owner: - * - * Validation Steps: - * 4. The QUE ID is correct - * 5. The correct tags are present in the message based on the create options - * - * @throws java.io.IOException - if there is a problem reseting the log monitor - * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.deleteQueue} - */ - public void testCreateQueueTransientViaManagementConsole() throws IOException, JMException - { - //Remove any previous queue declares - _monitor.markDiscardPoint(); - - _jmxUtils.createQueue("test", getName(), null, false); - - // Validate - - List results = waitAndFindMatches("QUE-1001"); - - assertEquals("More than one queue creation found", 1, results.size()); - - String log = getLogMessage(results, 0); - - // Validate correct queue name - String subject = fromSubject(log); - assertEquals("Incorrect queue name created", getName(), AbstractTestLogSubject.getSlice("qu", subject)); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - } - - /** - * Description: - * The ManagementConsole can be used to delete a queue. When this is done a QUE-1002 Deleted message must be logged. - * Input: - * - * 1. Running Broker - * 2. Queue created on the broker with no subscribers - * 3. Management Console connected - * 4. Queue is deleted via Management Console - * Output: - * - * QUE-1002 : Deleted - * - * Validation Steps: - * 5. The QUE ID is correct - * - * @throws java.io.IOException - if there is a problem reseting the log monitor - * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.deleteQueue} - */ - public void testQueueDeleteViaManagementConsole() throws IOException, JMException - { - //Remove any previous queue declares - _monitor.markDiscardPoint(); - - _jmxUtils.createQueue("test", getName(), null, false); - - ManagedBroker managedBroker = _jmxUtils.getManagedBroker("test"); - - managedBroker.deleteQueue(getName()); - - List results = waitAndFindMatches("QUE-1002"); - - assertEquals("More than one queue deletion found", 1, results.size()); - - String log = getLog(results.get(0)); - - // Validate correct binding - String subject = fromSubject(log); - assertEquals("Incorrect queue named in delete", getName(), AbstractTestLogSubject.getSlice("qu", subject)); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - - } - - /** - * Description: - * The binding of a Queue and an Exchange is done via a Binding. When this Binding is created via the Management Console a BND-1001 Create message will be logged. - * Input: - * - * 1. Running Broker - * 2. Connected Management Console - * 3. Use Management Console to perform binding - * Output: - * - * BND-1001 : Create - * - * Validation Steps: - * 4. The BND ID is correct - * 5. This will be the first message for the given binding - * - * @throws java.io.IOException - if there is a problem reseting the log monitor - * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.createNewBinding} - */ - public void testBindingCreateOnDirectViaManagementConsole() throws IOException, JMException - { - //Remove any previous queue declares - _monitor.markDiscardPoint(); - - _jmxUtils.createQueue("test", getName(), null, false); - - ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.direct"); - - managedExchange.createNewBinding(getName(), getName()); - - List results = waitAndFindMatches("BND-1001"); - - assertEquals("Unexpected number of bindings logged", 1, results.size()); - - String log = getLogMessage(results, 0); - - // Validate correct binding - String subject = fromSubject(log); - assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject)); - assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject)); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - } - - public void testBindingCreateOnTopicViaManagementConsole() throws IOException, JMException - { - //Remove any previous queue declares - _monitor.markDiscardPoint(); - - _jmxUtils.createQueue("test", getName(), null, false); - - ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.topic"); - - managedExchange.createNewBinding(getName(), getName()); - - List results = waitAndFindMatches("BND-1001"); - - assertEquals("Unexpected number of bindings logged", 1, results.size()); - - String log = getLogMessage(results, 0); - - // Validate correct binding - String subject = fromSubject(log); - assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject)); - assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject)); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - } - - public void testBindingCreateOnFanoutViaManagementConsole() throws IOException, JMException - { - //Remove any previous queue declares - _monitor.markDiscardPoint(); - - _jmxUtils.createQueue("test", getName(), null, false); - - ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.fanout"); - - managedExchange.createNewBinding(getName(), getName()); - - List results = waitAndFindMatches("BND-1001"); - - assertEquals("Unexpected number of bindings logged", 1, results.size()); - - String log = getLogMessage(results, 0); - - // Validate correct binding - String subject = fromSubject(log); - assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject)); - assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject)); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - } - - /** - * Description: - * Bindings can be deleted so that a queue can be rebound with a different set of values. This can be performed via the Management Console - * Input: - * - * 1. Running Broker - * 2. Management Console connected - * 3. Management Console is used to perform unbind. - * Output: - * - * BND-1002 : Deleted - * - * Validation Steps: - * 4. The BND ID is correct - * 5. There must have been a BND-1001 Create message first. - * 6. This will be the last message for the given binding - * - * @throws java.io.IOException - if there is a problem reseting the log monitor or an issue with the JMX Connection - * @throws javax.management.JMException - {@see #createExchange and ManagedBroker.unregisterExchange} - */ - public void testUnRegisterExchangeViaManagementConsole() throws IOException, JMException - { - //Remove any previous queue declares - _monitor.markDiscardPoint(); - - _jmxUtils.createExchange("test", getName(), "direct", false); - - ManagedBroker managedBroker = _jmxUtils.getManagedBroker("test"); - - managedBroker.unregisterExchange(getName()); - - List results = waitAndFindMatches("EXH-1002"); - - assertEquals("More than one exchange deletion found", 1, results.size()); - - String log = getLog(results.get(0)); - - // Validate correct binding - String subject = fromSubject(log); - assertEquals("Incorrect exchange named in delete", "direct/" + getName(), AbstractTestLogSubject.getSlice("ex", subject)); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java deleted file mode 100644 index cb6eae013e..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java +++ /dev/null @@ -1,324 +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.systest.management.jmx; - - -import java.util.Collections; -import java.util.List; - -import org.apache.qpid.server.logging.AbstractTestLogging; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.Transport; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.util.LogMonitor; - -/** - * Management Console Test Suite - * - * The Management Console test suite validates that the follow log messages as specified in the Functional Specification. - * - * This suite of tests validate that the management console messages occur correctly and according to the following format: - * - * MNG-1001 : Management Startup - * MNG-1002 : Starting : : Listening on port - * MNG-1003 : Shutting down : : port - * MNG-1004 : Management Ready - * MNG-1005 : Management Stopped - * MNG-1006 : Using SSL Keystore : - * MNG-1007 : Open : User - * MNG-1008 : Close : User - */ -public class ManagementLoggingTest extends AbstractTestLogging -{ - private static final String MNG_PREFIX = "MNG-"; - - public void setUp() throws Exception - { - setLogMessagePrefix(); - - // We either do this here or have a null check in tearDown. - // As when this test is run against profiles other than java it will NPE - _monitor = new LogMonitor(_outputFile); - //We explicitly do not call super.setUp as starting up the broker is - //part of the test case. - - } - - /** - * Description: - * Using the startup configuration validate that the management startup - * message is logged correctly. - * Input: - * Standard configuration with management enabled - * Output: - * - * MNG-1001 : Startup - * - * Constraints: - * This is the FIRST message logged by MNG - * Validation Steps: - * - * 1. The BRK ID is correct - * 2. This is the FIRST message logged by MNG - */ - public void testManagementStartupEnabled() throws Exception - { - // This test only works on java brokers - if (isJavaBroker()) - { - startBrokerAndCreateMonitor(true, false); - - // Ensure we have received the MNG log msg. - waitForMessage("MNG-1001"); - - List results = findMatches(MNG_PREFIX); - // Validation - - assertTrue("MNGer message not logged", results.size() > 0); - - String log = getLogMessage(results, 0); - - //1 - validateMessageID("MNG-1001", log); - - //2 - //There will be 2 copies of the startup message (one via SystemOut, and one via Log4J) - results = findMatches("MNG-1001"); - assertEquals("Unexpected startup message count.", - 2, results.size()); - - //3 - assertEquals("Startup log message is not 'Startup'.", "JMX Management Startup", - getMessageString(log)); - } - } - - /** - * Description: - * Verify that when management is disabled in the configuration file the - * startup message is not logged. - * Input: - * Standard configuration with management disabled - * Output: - * NO MNG messages - * Validation Steps: - * - * 1. Validate that no MNG messages are produced. - */ - public void testManagementStartupDisabled() throws Exception - { - if (isJavaBroker()) - { - startBrokerAndCreateMonitor(false, false); - - List results = findMatches(MNG_PREFIX); - // Validation - - assertEquals("MNGer messages logged", 0, results.size()); - } - } - - /** - * The two MNG-1002 messages are logged at the same time so lets test them - * at the same time. - * - * Description: - * Using the default configuration validate that the RMI Registry socket is - * correctly reported as being opened - * - * Input: - * The default configuration file - * Output: - * - * MESSAGE MNG-1002 : Starting : RMI Registry : Listening on port 8999 - * - * Constraints: - * The RMI ConnectorServer and Registry log messages do not have a prescribed order - * Validation Steps: - * - * 1. The MNG ID is correct - * 2. The specified port is the correct '8999' - * - * Description: - * Using the default configuration validate that the RMI ConnectorServer - * socket is correctly reported as being opened - * - * Input: - * The default configuration file - * Output: - * - * MESSAGE MNG-1002 : Starting : RMI ConnectorServer : Listening on port 9099 - * - * Constraints: - * The RMI ConnectorServer and Registry log messages do not have a prescribed order - * Validation Steps: - * - * 1. The MNG ID is correct - * 2. The specified port is the correct '9099' - */ - public void testManagementStartupRMIEntries() throws Exception - { - if (isJavaBroker()) - { - startBrokerAndCreateMonitor(true, false); - - List results = waitAndFindMatches("MNG-1002"); - // Validation - - //There will be 4 startup messages (two via SystemOut, and two via Log4J) - assertEquals("Unexpected MNG-1002 message count", 4, results.size()); - - String log = getLogMessage(results, 0); - - //1 - validateMessageID("MNG-1002", log); - - //Check the RMI Registry port is as expected - int mPort = getManagementPort(getPort()); - assertTrue("RMI Registry port not as expected(" + mPort + ").:" + getMessageString(log), - getMessageString(log).endsWith(String.valueOf(mPort))); - - log = getLogMessage(results, 2); - - //1 - validateMessageID("MNG-1002", log); - - // We expect the RMI Registry port (the defined 'management port') to be - // 100 lower than the JMX RMIConnector Server Port (the actual JMX server) - int jmxPort = mPort + JMXPORT_CONNECTORSERVER_OFFSET; - assertTrue("JMX RMIConnectorServer port not as expected(" + jmxPort + ").:" + getMessageString(log), - getMessageString(log).endsWith(String.valueOf(jmxPort))); - } - } - - /** - * Description: - * Using the default configuration with SSL enabled for the management port the SSL Keystore path should be reported via MNG-1006 - * Input: - * Management SSL enabled default configuration. - * Output: - * - * MESSAGE MNG-1006 : Using SSL Keystore : test_resources/ssl/keystore.jks - * - * Validation Steps: - * - * 1. The MNG ID is correct - * 2. The keystore path is as specified in the configuration - */ - public void testManagementStartupSSLKeystore() throws Exception - { - if (isJavaBroker()) - { - setSystemProperty("javax.net.debug", "ssl"); - startBrokerAndCreateMonitor(true, true); - - List results = waitAndFindMatches("MNG-1006"); - - assertTrue("MNGer message not logged", results.size() > 0); - - String log = getLogMessage(results, 0); - - //1 - validateMessageID("MNG-1006", log); - - // Validate we only have two MNG-1002 (one via stdout, one via log4j) - results = findMatches("MNG-1006"); - assertEquals("Upexpected SSL Keystore message count", - 2, results.size()); - - // Validate the keystore path is as expected - assertTrue("SSL Keystore entry expected.:" + getMessageString(log), - getMessageString(log).endsWith("systestsKeyStore")); - } - } - - /** - * Description: Tests the management connection open/close are logged correctly. - * - * Output: - * - * MESSAGE MNG-1007 : Open : User - * MESSAGE MNG-1008 : Close : User - * - * Validation Steps: - * - * 1. The MNG ID is correct - * 2. The message and username are correct - */ - public void testManagementUserOpenClose() throws Exception - { - if (isJavaBroker()) - { - startBrokerAndCreateMonitor(true, false); - - final JMXTestUtils jmxUtils = new JMXTestUtils(this); - List openResults = null; - List closeResults = null; - try - { - jmxUtils.open(); - openResults = waitAndFindMatches("MNG-1007"); - } - finally - { - if (jmxUtils != null) - { - jmxUtils.close(); - closeResults = waitAndFindMatches("MNG-1008"); - } - } - - assertNotNull("Management Open results null", openResults.size()); - assertEquals("Management Open logged unexpected number of times", 1, openResults.size()); - - assertNotNull("Management Close results null", closeResults.size()); - assertEquals("Management Close logged unexpected number of times", 1, closeResults.size()); - - final String openMessage = getMessageString(getLogMessage(openResults, 0)); - assertTrue("Unexpected open message " + openMessage, openMessage.endsWith("Open : User admin")); - final String closeMessage = getMessageString(getLogMessage(closeResults, 0)); - assertTrue("Unexpected close message " + closeMessage, closeMessage.endsWith("Close : User admin")); - } - } - - private void startBrokerAndCreateMonitor(boolean managementEnabled, boolean useManagementSSL) throws Exception - { - TestBrokerConfiguration config = getBrokerConfiguration(); - - if (managementEnabled) - { - config.addJmxManagementConfiguration(); - } - - if(useManagementSSL) - { - // This test requires we have ssl, change the transport and add they keystore to the port config - config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_JMX_PORT, Port.TRANSPORTS, Collections.singleton(Transport.SSL)); - config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_JMX_PORT, Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); - } - - startBroker(); - - // Now we can create the monitor as _outputFile will now be defined - _monitor = new LogMonitor(_outputFile); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java deleted file mode 100644 index d0f133aa73..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java +++ /dev/null @@ -1,869 +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.systest.management.jmx; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageListener; -import javax.jms.Queue; -import javax.jms.Session; -import javax.jms.TextMessage; -import javax.management.Notification; -import javax.management.NotificationListener; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.TabularData; -import javax.naming.NamingException; - -import org.apache.commons.lang.time.FastDateFormat; -import org.apache.log4j.Logger; - -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.management.common.mbeans.ManagedBroker; -import org.apache.qpid.management.common.mbeans.ManagedQueue; -import org.apache.qpid.server.queue.NotificationCheckTest; -import org.apache.qpid.server.queue.QueueArgumentsConverter; -import org.apache.qpid.server.queue.StandardQueueImpl; -import org.apache.qpid.test.client.destination.AddressBasedDestinationTest; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -/** - * Tests the JMX API for the Managed Queue. - * - */ -public class QueueManagementTest extends QpidBrokerTestCase -{ - - private static final Logger LOGGER = Logger.getLogger(QueueManagementTest.class); - - private static final String VIRTUAL_HOST = "test"; - private static final String TEST_QUEUE_DESCRIPTION = "my description"; - - private JMXTestUtils _jmxUtils; - private Connection _connection; - private Session _session; - - private String _sourceQueueName; - private String _destinationQueueName; - private Destination _sourceQueue; - private Destination _destinationQueue; - private ManagedQueue _managedSourceQueue; - private ManagedQueue _managedDestinationQueue; - - public void setUp() throws Exception - { - getBrokerConfiguration().addJmxManagementConfiguration(); - - _jmxUtils = new JMXTestUtils(this); - - super.setUp(); - _sourceQueueName = getTestQueueName() + "_src"; - _destinationQueueName = getTestQueueName() + "_dest"; - - createConnectionAndSession(); - - _sourceQueue = _session.createQueue(_sourceQueueName); - _destinationQueue = _session.createQueue(_destinationQueueName); - createQueueOnBroker(_sourceQueue); - createQueueOnBroker(_destinationQueue); - - _jmxUtils.open(); - - createManagementInterfacesForQueues(); - } - - public void tearDown() throws Exception - { - if (_jmxUtils != null) - { - _jmxUtils.close(); - } - super.tearDown(); - } - - public void testQueueAttributes() throws Exception - { - Queue queue = _session.createQueue(getTestQueueName()); - createQueueOnBroker(queue); - - final String queueName = queue.getQueueName(); - - final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertEquals("Unexpected name", queueName, managedQueue.getName()); - assertEquals("Unexpected queue type", "standard", managedQueue.getQueueType()); - } - - public void testExclusiveQueueHasJmsClientIdAsOwner() throws Exception - { - final String subName = "testOwner"; - _session.createDurableSubscriber(getTestTopic(), subName); - - final String queueName = _connection.getClientID() + ":" + subName; - - final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertNotNull(_connection.getClientID()); - assertEquals("Unexpected owner", _connection.getClientID(), managedQueue.getOwner()); - } - - public void testNonExclusiveQueueHasNoOwner() throws Exception - { - Queue nonExclusiveQueue = _session.createQueue(getTestQueueName()); - createQueueOnBroker(nonExclusiveQueue); - - final String queueName = nonExclusiveQueue.getQueueName(); - - final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertNull("Unexpected owner", managedQueue.getOwner()); - } - - public void testSetNewQueueDescriptionOnExistingQueue() throws Exception - { - Queue queue = _session.createQueue(getTestQueueName()); - createQueueOnBroker(queue); - - final String queueName = queue.getQueueName(); - - final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertNull("Unexpected description", managedQueue.getDescription()); - - managedQueue.setDescription(TEST_QUEUE_DESCRIPTION); - assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription()); - } - - public void testNewQueueWithDescription() throws Exception - { - String queueName = getTestQueueName(); - Map arguments = Collections.singletonMap(QueueArgumentsConverter.X_QPID_DESCRIPTION, (Object)TEST_QUEUE_DESCRIPTION); - ((AMQSession)_session).createQueue(AMQShortString.valueOf(queueName), false, true, false, arguments); - - final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription()); - } - - /** - * Requires persistent store. - */ - public void testQueueDescriptionSurvivesRestart() throws Exception - { - String queueName = getTestQueueName(); - Map arguments = Collections.singletonMap(QueueArgumentsConverter.X_QPID_DESCRIPTION, (Object)TEST_QUEUE_DESCRIPTION); - - ((AMQSession)_session).createQueue(AMQShortString.valueOf(queueName), false, true, false, arguments); - - ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription()); - - restartBroker(); - - managedQueue = _jmxUtils.getManagedQueue(queueName); - assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription()); - } - - /** - * Tests queue creation with {@link QueueArgumentsConverter#X_QPID_MAXIMUM_DELIVERY_COUNT} argument. Also tests - * that the attribute is exposed correctly through {@link ManagedQueue#getMaximumDeliveryCount()}. - */ - public void testCreateQueueWithMaximumDeliveryCountSet() throws Exception - { - final String queueName = getName(); - final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST); - - final Integer deliveryCount = 1; - final Map arguments = Collections.singletonMap(QueueArgumentsConverter.X_QPID_MAXIMUM_DELIVERY_COUNT, (Object)deliveryCount); - managedBroker.createNewQueue(queueName, null, true, arguments); - - // Ensure the queue exists - assertNotNull("Queue object name expected to exist", _jmxUtils.getQueueObjectName(VIRTUAL_HOST, queueName)); - assertNotNull("Manager queue expected to be available", _jmxUtils.getManagedQueue(queueName)); - - final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertEquals("Unexpected maximum delivery count", deliveryCount, managedQueue.getMaximumDeliveryCount()); - } - - public void testCreateQueueWithAlertingThresholdsSet() throws Exception - { - final String queueName = getName(); - final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST); - - final Long maximumMessageCount = 100l; - final Long maximumMessageSize = 200l; - final Long maximumQueueDepth = 300l; - final Long maximumMessageAge = 400l; - final Map arguments = new HashMap(); - arguments.put(QueueArgumentsConverter.X_QPID_MAXIMUM_MESSAGE_COUNT, maximumMessageCount); - arguments.put(QueueArgumentsConverter.X_QPID_MAXIMUM_MESSAGE_SIZE, maximumMessageSize); - arguments.put(QueueArgumentsConverter.X_QPID_MAXIMUM_QUEUE_DEPTH, maximumQueueDepth); - arguments.put(QueueArgumentsConverter.X_QPID_MAXIMUM_MESSAGE_AGE, maximumMessageAge); - - managedBroker.createNewQueue(queueName, null, true, arguments); - - // Ensure the queue exists - assertNotNull("Queue object name expected to exist", _jmxUtils.getQueueObjectName(VIRTUAL_HOST, queueName)); - assertNotNull("Manager queue expected to be available", _jmxUtils.getManagedQueue(queueName)); - - ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertEquals("Unexpected maximum message count", maximumMessageCount, managedQueue.getMaximumMessageCount()); - assertEquals("Unexpected maximum message size", maximumMessageSize, managedQueue.getMaximumMessageSize()); - assertEquals("Unexpected maximum queue depth", maximumQueueDepth, managedQueue.getMaximumQueueDepth()); - assertEquals("Unexpected maximum message age", maximumMessageAge, managedQueue.getMaximumMessageAge()); - } - - /** - * Requires 0-10 as relies on ADDR addresses. - * @see AddressBasedDestinationTest for the testing of message routing to the alternate exchange - */ - public void testGetSetAlternateExchange() throws Exception - { - String queueName = getTestQueueName(); - String altExchange = "amq.fanout"; - String addrWithAltExch = String.format("ADDR:%s;{create:always,node:{type:queue,x-declare:{alternate-exchange:'%s'}}}", queueName, altExchange); - Queue queue = _session.createQueue(addrWithAltExch); - - createQueueOnBroker(queue); - - final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertEquals("Newly created queue does not have expected alternate exchange", altExchange, managedQueue.getAlternateExchange()); - - String newAltExch = "amq.topic"; - managedQueue.setAlternateExchange(newAltExch); - assertEquals("Unexpected alternate exchange after set", newAltExch, managedQueue.getAlternateExchange()); - } - - /** - * Requires 0-10 as relies on ADDR addresses. - */ - public void testRemoveAlternateExchange() throws Exception - { - String queueName = getTestQueueName(); - String altExchange = "amq.fanout"; - String addrWithAltExch = String.format("ADDR:%s;{create:always,node:{type:queue,x-declare:{alternate-exchange:'%s'}}}", queueName, altExchange); - Queue queue = _session.createQueue(addrWithAltExch); - - createQueueOnBroker(queue); - - final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertEquals("Newly created queue does not have expected alternate exchange", altExchange, managedQueue.getAlternateExchange()); - - managedQueue.setAlternateExchange(""); - assertNull("Unexpected alternate exchange after set", managedQueue.getAlternateExchange()); - } - - /** - * Requires persistent store - * Requires 0-10 as relies on ADDR addresses. - */ - public void testAlternateExchangeSurvivesRestart() throws Exception - { - String nonMandatoryExchangeName = "exch" + getName(); - - final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST); - managedBroker.createNewExchange(nonMandatoryExchangeName, "fanout", true); - - String queueName1 = getTestQueueName() + "1"; - String altExchange1 = "amq.fanout"; - String addr1WithAltExch = String.format("ADDR:%s;{create:always,node:{durable: true,type:queue,x-declare:{alternate-exchange:'%s'}}}", queueName1, altExchange1); - Queue queue1 = _session.createQueue(addr1WithAltExch); - - String queueName2 = getTestQueueName() + "2"; - String addr2WithoutAltExch = String.format("ADDR:%s;{create:always,node:{durable: true,type:queue}}", queueName2); - Queue queue2 = _session.createQueue(addr2WithoutAltExch); - - createQueueOnBroker(queue1); - createQueueOnBroker(queue2); - - ManagedQueue managedQueue1 = _jmxUtils.getManagedQueue(queueName1); - assertEquals("Newly created queue1 does not have expected alternate exchange", altExchange1, managedQueue1.getAlternateExchange()); - - ManagedQueue managedQueue2 = _jmxUtils.getManagedQueue(queueName2); - assertNull("Newly created queue2 does not have expected alternate exchange", managedQueue2.getAlternateExchange()); - - String altExchange2 = nonMandatoryExchangeName; - managedQueue2.setAlternateExchange(altExchange2); - - restartBroker(); - - managedQueue1 = _jmxUtils.getManagedQueue(queueName1); - assertEquals("Queue1 does not have expected alternate exchange after restart", altExchange1, managedQueue1.getAlternateExchange()); - - managedQueue2 = _jmxUtils.getManagedQueue(queueName2); - assertEquals("Queue2 does not have expected updated alternate exchange after restart", altExchange2, managedQueue2.getAlternateExchange()); - } - - /** - * Tests the ability to receive queue alerts as JMX notifications. - * - * @see NotificationCheckTest - * @see SimpleAMQQueueTest#testNotificationFiredAsync() - * @see SimpleAMQQueueTest#testNotificationFiredOnEnqueue() - */ - public void testQueueNotification() throws Exception - { - final String queueName = getName(); - final long maximumMessageCount = 3; - - Queue queue = _session.createQueue(queueName); - createQueueOnBroker(queue); - - ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - managedQueue.setMaximumMessageCount(maximumMessageCount); - - RecordingNotificationListener listener = new RecordingNotificationListener(1); - - _jmxUtils.addNotificationListener(_jmxUtils.getQueueObjectName(VIRTUAL_HOST, queueName), listener, null, null); - - // Send two messages - this should *not* trigger the notification - sendMessage(_session, queue, 2); - - assertEquals("Premature notification received", 0, listener.getNumberOfNotificationsReceived()); - - // A further message should trigger the message count alert - sendMessage(_session, queue, 1); - - listener.awaitExpectedNotifications(5, TimeUnit.SECONDS); - - assertEquals("Unexpected number of JMX notifications received", 1, listener.getNumberOfNotificationsReceived()); - - Notification notification = listener.getLastNotification(); - assertEquals("Unexpected notification message", "MESSAGE_COUNT_ALERT 3: Maximum count on queue threshold (3) breached.", notification.getMessage()); - } - - /** - * Tests {@link ManagedQueue#viewMessages(long, long)} interface. - */ - public void testViewSingleMessage() throws Exception - { - final List sentMessages = sendMessage(_session, _sourceQueue, 1); - syncSession(_session); - final Message sentMessage = sentMessages.get(0); - - assertEquals("Unexpected queue depth", 1, _managedSourceQueue.getMessageCount().intValue()); - - // Check the contents of the message - final TabularData tab = _managedSourceQueue.viewMessages(1l, 1l); - assertEquals("Unexpected number of rows in table", 1, tab.size()); - final Iterator rowItr = (Iterator) tab.values().iterator(); - - final CompositeData row1 = rowItr.next(); - assertNotNull("Message should have AMQ message id", row1.get(ManagedQueue.MSG_AMQ_ID)); - assertEquals("Unexpected queue position", 1l, row1.get(ManagedQueue.MSG_QUEUE_POS)); - assertEquals("Unexpected redelivered flag", Boolean.FALSE, row1.get(ManagedQueue.MSG_REDELIVERED)); - - // Check the contents of header (encoded in a string array) - final String[] headerArray = (String[]) row1.get(ManagedQueue.MSG_HEADER); - assertNotNull("Expected message header array", headerArray); - final Map headers = headerArrayToMap(headerArray); - - final String expectedJMSMessageID = isBroker010() ? sentMessage.getJMSMessageID().replace("ID:", "") : sentMessage.getJMSMessageID(); - final String expectedFormattedJMSTimestamp = FastDateFormat.getInstance(ManagedQueue.JMSTIMESTAMP_DATETIME_FORMAT).format(sentMessage.getJMSTimestamp()); - assertEquals("Unexpected JMSMessageID within header", expectedJMSMessageID, headers.get("JMSMessageID")); - assertEquals("Unexpected JMSPriority within header", String.valueOf(sentMessage.getJMSPriority()), headers.get("JMSPriority")); - assertEquals("Unexpected JMSTimestamp within header", expectedFormattedJMSTimestamp, headers.get("JMSTimestamp")); - } - - /** - * Tests {@link ManagedQueue#moveMessages(long, long, String)} interface. - */ - public void testMoveMessagesBetweenQueues() throws Exception - { - final int numberOfMessagesToSend = 10; - - sendMessage(_session, _sourceQueue, numberOfMessagesToSend); - syncSession(_session); - assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); - - List amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); - - // Move first three messages to destination - long fromMessageId = amqMessagesIds.get(0); - long toMessageId = amqMessagesIds.get(2); - _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName); - - assertEquals("Unexpected queue depth on destination queue after first move", 3, _managedDestinationQueue.getMessageCount().intValue()); - assertEquals("Unexpected queue depth on source queue after first move", 7, _managedSourceQueue.getMessageCount().intValue()); - - // Now move a further two messages to destination - fromMessageId = amqMessagesIds.get(7); - toMessageId = amqMessagesIds.get(8); - _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName); - assertEquals("Unexpected queue depth on destination queue after second move", 5, _managedDestinationQueue.getMessageCount().intValue()); - assertEquals("Unexpected queue depth on source queue after second move", 5, _managedSourceQueue.getMessageCount().intValue()); - - assertMessageIndicesOn(_destinationQueue, 0, 1, 2, 7, 8); - } - - /** - * Tests {@link ManagedQueue#copyMessages(long, long, String)} interface. - */ - public void testCopyMessagesBetweenQueues() throws Exception - { - final int numberOfMessagesToSend = 10; - sendMessage(_session, _sourceQueue, numberOfMessagesToSend); - syncSession(_session); - assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); - - List amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); - - // Copy first three messages to destination - long fromMessageId = amqMessagesIds.get(0); - long toMessageId = amqMessagesIds.get(2); - _managedSourceQueue.copyMessages(fromMessageId, toMessageId, _destinationQueueName); - - assertEquals("Unexpected queue depth on destination queue after first copy", 3, _managedDestinationQueue.getMessageCount().intValue()); - assertEquals("Unexpected queue depth on source queue after first copy", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); - - // Now copy a further two messages to destination - fromMessageId = amqMessagesIds.get(7); - toMessageId = amqMessagesIds.get(8); - _managedSourceQueue.copyMessages(fromMessageId, toMessageId, _destinationQueueName); - assertEquals("Unexpected queue depth on destination queue after second copy", 5, _managedDestinationQueue.getMessageCount().intValue()); - assertEquals("Unexpected queue depth on source queue after second copy", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); - - assertMessageIndicesOn(_destinationQueue, 0, 1, 2, 7, 8); - } - - - /** - * Tests {@link ManagedQueue#copyMessages(long, long, String)} interface. - */ - public void testCopyMessagesBetweenQueuesWithDuplicates() throws Exception - { - final int numberOfMessagesToSend = 10; - sendMessage(_session, _sourceQueue, numberOfMessagesToSend); - syncSession(_session); - assertEquals("Unexpected queue depth after send", - numberOfMessagesToSend, - _managedSourceQueue.getMessageCount().intValue()); - - List amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); - - // Copy first three messages to destination - long fromMessageId = amqMessagesIds.get(0); - long toMessageId = amqMessagesIds.get(2); - _managedSourceQueue.copyMessages(fromMessageId, toMessageId, _destinationQueueName); - - assertEquals("Unexpected queue depth on destination queue after first copy", - 3, - _managedDestinationQueue.getMessageCount().intValue()); - assertEquals("Unexpected queue depth on source queue after first copy", - numberOfMessagesToSend, - _managedSourceQueue.getMessageCount().intValue()); - - // Now copy a further two messages to destination - fromMessageId = amqMessagesIds.get(7); - toMessageId = amqMessagesIds.get(8); - _managedSourceQueue.copyMessages(fromMessageId, toMessageId, _destinationQueueName); - assertEquals("Unexpected queue depth on destination queue after second copy", - 5, - _managedDestinationQueue.getMessageCount().intValue()); - assertEquals("Unexpected queue depth on source queue after second copy", - numberOfMessagesToSend, - _managedSourceQueue.getMessageCount().intValue()); - - // Attempt to copy mixture of messages already on and some not already on the queue - - fromMessageId = amqMessagesIds.get(5); - toMessageId = amqMessagesIds.get(8); - _managedSourceQueue.copyMessages(fromMessageId, toMessageId, _destinationQueueName); - assertEquals("Unexpected queue depth on destination queue after second copy", - 7, - _managedDestinationQueue.getMessageCount().intValue()); - assertEquals("Unexpected queue depth on source queue after second copy", - numberOfMessagesToSend, - _managedSourceQueue.getMessageCount().intValue()); - - assertMessageIndicesOn(_destinationQueue, 0, 1, 2, 7, 8, 5, 6); - - - } - - public void testMoveMessagesBetweenQueuesWithActiveConsumerOnSourceQueue() throws Exception - { - setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, new Integer(1).toString()); - Connection asyncConnection = getConnection(); - asyncConnection.start(); - - final int numberOfMessagesToSend = 50; - sendMessage(_session, _sourceQueue, numberOfMessagesToSend); - syncSession(_session); - assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); - - List amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); - - long fromMessageId = amqMessagesIds.get(0); - long toMessageId = amqMessagesIds.get(numberOfMessagesToSend - 1); - - CountDownLatch consumerReadToHalfwayLatch = new CountDownLatch(numberOfMessagesToSend / 2); - AtomicInteger totalConsumed = new AtomicInteger(0); - startAsyncConsumerOn(_sourceQueue, asyncConnection, consumerReadToHalfwayLatch, totalConsumed); - - boolean halfwayPointReached = consumerReadToHalfwayLatch.await(5000, TimeUnit.MILLISECONDS); - assertTrue("Did not read half of messages within time allowed", halfwayPointReached); - - _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName); - - asyncConnection.stop(); - - // The exact number of messages moved will be non deterministic, as the number of messages processed - // by the consumer cannot be predicted. There is also the possibility that a message can remain - // on the source queue. This situation will arise if a message has been acquired by the consumer, but not - // yet delivered to the client application (i.e. MessageListener#onMessage()) when the Connection#stop() occurs. - // - // The number of messages moved + the number consumed + any messages remaining on source should - // *always* be equal to the number we originally sent. - - int numberOfMessagesReadByConsumer = totalConsumed.intValue(); - int numberOfMessagesOnDestinationQueue = _managedDestinationQueue.getMessageCount().intValue(); - int numberOfMessagesRemainingOnSourceQueue = _managedSourceQueue.getMessageCount().intValue(); - - LOGGER.debug("Async consumer read : " + numberOfMessagesReadByConsumer - + " Number of messages moved to destination : " + numberOfMessagesOnDestinationQueue - + " Number of messages remaining on source : " + numberOfMessagesRemainingOnSourceQueue); - assertEquals("Unexpected number of messages after move", numberOfMessagesToSend, numberOfMessagesReadByConsumer + numberOfMessagesOnDestinationQueue + numberOfMessagesRemainingOnSourceQueue); - } - - public void testMoveMessagesBetweenQueuesWithActiveConsumerOnDestinationQueue() throws Exception - { - setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, new Integer(1).toString()); - Connection asyncConnection = getConnection(); - asyncConnection.start(); - - final int numberOfMessagesToSend = 50; - sendMessage(_session, _sourceQueue, numberOfMessagesToSend); - syncSession(_session); - assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); - - List amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); - long fromMessageId = amqMessagesIds.get(0); - long toMessageId = amqMessagesIds.get(numberOfMessagesToSend - 1); - - AtomicInteger totalConsumed = new AtomicInteger(0); - CountDownLatch allMessagesConsumedLatch = new CountDownLatch(numberOfMessagesToSend); - startAsyncConsumerOn(_destinationQueue, asyncConnection, allMessagesConsumedLatch, totalConsumed); - - _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName); - - allMessagesConsumedLatch.await(5000, TimeUnit.MILLISECONDS); - assertEquals("Did not consume all messages from destination queue", numberOfMessagesToSend, totalConsumed.intValue()); - } - - /** - * Tests {@link ManagedQueue#moveMessages(long, long, String)} interface. - */ - public void testMoveMessageBetweenQueuesWithBrokerRestart() throws Exception - { - final int numberOfMessagesToSend = 1; - - sendMessage(_session, _sourceQueue, numberOfMessagesToSend); - syncSession(_session); - assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); - - restartBroker(); - - createManagementInterfacesForQueues(); - createConnectionAndSession(); - - List amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); - - // Move messages to destination - long messageId = amqMessagesIds.get(0); - _managedSourceQueue.moveMessages(messageId, messageId, _destinationQueueName); - - assertEquals("Unexpected queue depth on destination queue after move", 1, _managedDestinationQueue.getMessageCount().intValue()); - assertEquals("Unexpected queue depth on source queue after move", 0, _managedSourceQueue.getMessageCount().intValue()); - - assertMessageIndicesOn(_destinationQueue, 0); - } - - /** - * Tests {@link ManagedQueue#copyMessages(long, long, String)} interface. - */ - public void testCopyMessageBetweenQueuesWithBrokerRestart() throws Exception - { - final int numberOfMessagesToSend = 1; - - sendMessage(_session, _sourceQueue, numberOfMessagesToSend); - syncSession(_session); - assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); - - restartBroker(); - - createManagementInterfacesForQueues(); - createConnectionAndSession(); - - List amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); - - // Move messages to destination - long messageId = amqMessagesIds.get(0); - _managedSourceQueue.copyMessages(messageId, messageId, _destinationQueueName); - - assertEquals("Unexpected queue depth on destination queue after copy", 1, _managedDestinationQueue.getMessageCount().intValue()); - assertEquals("Unexpected queue depth on source queue after copy", 1, _managedSourceQueue.getMessageCount().intValue()); - - assertMessageIndicesOn(_destinationQueue, 0); - } - - /** - * Tests {@link ManagedQueue#deleteMessages(long, long)} interface. - */ - public void testDeleteMessages() throws Exception - { - final int numberOfMessagesToSend = 15; - - sendMessage(_session, _sourceQueue, numberOfMessagesToSend); - syncSession(_session); - assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); - List amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); - // Current expected queue state, in terms of message header indices: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] - - // Delete the first message (Remember the amqMessagesIds list, and the message indices added as a property when sending, are both 0-based index) - long fromMessageId = amqMessagesIds.get(0); - long toMessageId = fromMessageId; - _managedSourceQueue.deleteMessages(fromMessageId, toMessageId); - assertEquals("Unexpected message count after first deletion", numberOfMessagesToSend - 1, _managedSourceQueue.getMessageCount().intValue()); - // Current expected queue state, in terms of message header indices: [X,1,2,3,4,5,6,7,8,9,10,11,12,13,14] - - // Delete the 9th-10th messages, in the middle of the queue - fromMessageId = amqMessagesIds.get(8); - toMessageId = amqMessagesIds.get(9); - _managedSourceQueue.deleteMessages(fromMessageId, toMessageId); - assertEquals("Unexpected message count after third deletion", numberOfMessagesToSend - 3, _managedSourceQueue.getMessageCount().intValue()); - // Current expected queue state, in terms of message header indices: [X,1,2,3,4,5,6,7,X,X,10,11,12,13,14] - - // Delete the 11th and 12th messages, but still include the IDs for the 9th and 10th messages in the - // range to ensure their IDs are 'skipped' until the matching messages are found - fromMessageId = amqMessagesIds.get(8); - toMessageId = amqMessagesIds.get(11); - _managedSourceQueue.deleteMessages(fromMessageId, toMessageId); - assertEquals("Unexpected message count after fourth deletion", numberOfMessagesToSend - 5, _managedSourceQueue.getMessageCount().intValue()); - // Current expected queue state, in terms of message header indices: [X,1,2,3,4,5,6,7,X,X,X,X,12,13,14] - - // Delete the 8th message and the 13th message, including the IDs for the 9th-12th messages in the - // range to ensure their IDs are 'skipped' and the other matching message is found - fromMessageId = amqMessagesIds.get(7); - toMessageId = amqMessagesIds.get(12); - _managedSourceQueue.deleteMessages(fromMessageId, toMessageId); - assertEquals("Unexpected message count after fourth deletion", numberOfMessagesToSend - 7, _managedSourceQueue.getMessageCount().intValue()); - // Current expected queue state, in terms of message header indices: [X,1,2,3,4,5,6,X,X,X,X,X,X,13,14] - - // Delete the last message message - fromMessageId = amqMessagesIds.get(numberOfMessagesToSend -1); - toMessageId = fromMessageId; - _managedSourceQueue.deleteMessages(fromMessageId, toMessageId); - assertEquals("Unexpected message count after second deletion", numberOfMessagesToSend - 8, _managedSourceQueue.getMessageCount().intValue()); - // Current expected queue state, in terms of message header indices: [X,1,2,3,4,5,6,X,X,X,X,X,X,13,X] - - // Verify the message indices with a consumer - assertMessageIndicesOn(_sourceQueue, 1,2,3,4,5,6,13); - } - - public void testGetMessageGroupKey() throws Exception - { - final String queueName = getName(); - final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST); - - final Object messageGroupKey = "test"; - final Map arguments = Collections.singletonMap(QueueArgumentsConverter.QPID_GROUP_HEADER_KEY, messageGroupKey); - managedBroker.createNewQueue(queueName, null, true, arguments); - - final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - - assertNotNull("Manager queue expected to be available", managedQueue); - assertEquals("Unexpected message group key", messageGroupKey, managedQueue.getMessageGroupKey()); - assertEquals("Unexpected message group sharing", false, managedQueue.isMessageGroupSharedGroups()); - } - - public void testIsMessageGroupSharedGroups() throws Exception - { - final String queueName = getName(); - final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST); - - final Object messageGroupKey = "test"; - final Map arguments = new HashMap(2); - arguments.put(QueueArgumentsConverter.QPID_GROUP_HEADER_KEY, messageGroupKey); - arguments.put(QueueArgumentsConverter.QPID_SHARED_MSG_GROUP, StandardQueueImpl.SHARED_MSG_GROUP_ARG_VALUE); - managedBroker.createNewQueue(queueName, null, true, arguments); - - final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - - assertNotNull("Manager queue expected to be available", managedQueue); - assertEquals("Unexpected message group key", messageGroupKey, managedQueue.getMessageGroupKey()); - assertEquals("Unexpected message group sharing", true, managedQueue.isMessageGroupSharedGroups()); - } - - @Override - public Message createNextMessage(Session session, int messageNumber) throws JMSException - { - Message message = session.createTextMessage(getContentForMessageNumber(messageNumber)); - message.setIntProperty(INDEX, messageNumber); - return message; - } - - private void startAsyncConsumerOn(Destination queue, Connection asyncConnection, - final CountDownLatch requiredNumberOfMessagesRead, final AtomicInteger totalConsumed) throws Exception - { - Session session = asyncConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer consumer = session.createConsumer(queue); - consumer.setMessageListener(new MessageListener() - { - - @Override - public void onMessage(Message arg0) - { - totalConsumed.incrementAndGet(); - requiredNumberOfMessagesRead.countDown(); - } - }); - } - - private void assertMessageIndicesOn(Destination queue, int... expectedIndices) throws Exception - { - MessageConsumer consumer = _session.createConsumer(queue); - - for (int i : expectedIndices) - { - TextMessage message = (TextMessage)consumer.receive(1000); - assertNotNull("Expected message with index " + i, message); - assertEquals("Expected message with index " + i, i, message.getIntProperty(INDEX)); - assertEquals("Expected message content", getContentForMessageNumber(i), message.getText()); - } - - assertNull("Unexpected message encountered", consumer.receive(1000)); - } - - private List getAMQMessageIdsOn(ManagedQueue managedQueue, long startIndex, long endIndex) throws Exception - { - final SortedSet messageIds = new TreeSet(); - - final TabularData tab = managedQueue.viewMessages(startIndex, endIndex); - final Iterator rowItr = (Iterator) tab.values().iterator(); - while(rowItr.hasNext()) - { - final CompositeData row = rowItr.next(); - long amqMessageId = (Long)row.get(ManagedQueue.MSG_AMQ_ID); - messageIds.add(amqMessageId); - } - - return new ArrayList(messageIds); - } - - /** - * - * Utility method to convert array of Strings in the form x = y into a - * map with key/value x => y. - * - */ - private Map headerArrayToMap(final String[] headerArray) - { - final Map headerMap = new HashMap(); - final List headerList = Arrays.asList(headerArray); - for (Iterator iterator = headerList.iterator(); iterator.hasNext();) - { - final String nameValuePair = iterator.next(); - final String[] nameValue = nameValuePair.split(" *= *", 2); - headerMap.put(nameValue[0], nameValue[1]); - } - return headerMap; - } - - private void createQueueOnBroker(Destination destination) throws JMSException - { - _session.createConsumer(destination).close(); // Create a consumer only to cause queue creation - } - - private void syncSession(Session session) throws Exception - { - ((AMQSession)session).sync(); - } - - private void createConnectionAndSession() throws JMSException, - NamingException - { - _connection = getConnection(); - _connection.start(); - _session = _connection.createSession(true, Session.SESSION_TRANSACTED); - } - - private void createManagementInterfacesForQueues() - { - _managedSourceQueue = _jmxUtils.getManagedQueue(_sourceQueueName); - _managedDestinationQueue = _jmxUtils.getManagedQueue(_destinationQueueName); - } - - private String getContentForMessageNumber(int msgCount) - { - return "Message count " + msgCount; - } - - private final class RecordingNotificationListener implements NotificationListener - { - private final CountDownLatch _notificationReceivedLatch; - private final AtomicInteger _numberOfNotifications; - private final AtomicReference _lastNotification; - - private RecordingNotificationListener(int expectedNumberOfNotifications) - { - _notificationReceivedLatch = new CountDownLatch(expectedNumberOfNotifications); - _numberOfNotifications = new AtomicInteger(0); - _lastNotification = new AtomicReference(); - } - - @Override - public void handleNotification(Notification notification, Object handback) - { - _lastNotification.set(notification); - _numberOfNotifications.incrementAndGet(); - _notificationReceivedLatch.countDown(); - } - - public int getNumberOfNotificationsReceived() - { - return _numberOfNotifications.get(); - } - - public Notification getLastNotification() - { - return _lastNotification.get(); - } - - public void awaitExpectedNotifications(long timeout, TimeUnit timeunit) throws InterruptedException - { - _notificationReceivedLatch.await(timeout, timeunit); - } - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java deleted file mode 100644 index 4ea071f3ac..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java +++ /dev/null @@ -1,211 +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.systest.management.jmx; - -import java.util.List; - -import javax.jms.Connection; -import javax.jms.MessageConsumer; -import javax.jms.Queue; -import javax.jms.Session; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.management.common.mbeans.ManagedBroker; -import org.apache.qpid.management.common.mbeans.ManagedConnection; -import org.apache.qpid.management.common.mbeans.ServerInformation; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class StatisticsTest extends QpidBrokerTestCase -{ - private static final String TEST_VIRTUALHOST1 = "test1"; - private static final String TEST_VIRTUALHOST2 = "test2"; - - private static final String TEST_USER = "admin"; - private static final String TEST_PASSWORD = "admin"; - private static final int MESSAGE_COUNT_TEST = 5; - private static final int MESSAGE_COUNT_DEV = 9; - - private JMXTestUtils _jmxUtils; - private Connection _vhost1Connection, _vhost2Connection; - private Session _vhost1Session, _vhost2Session; - private Queue _vhost1Queue, _vhost2Queue; - protected String _brokerUrl; - - @Override - public void setUp() throws Exception - { - createTestVirtualHostNode(0, TEST_VIRTUALHOST1); - createTestVirtualHostNode(0, TEST_VIRTUALHOST2); - - getBrokerConfiguration().addJmxManagementConfiguration(); - - _jmxUtils = new JMXTestUtils(this, TEST_USER, TEST_PASSWORD); - - super.setUp(); - - _brokerUrl = getBroker().toString(); - _vhost1Connection = new AMQConnection(_brokerUrl, TEST_USER, TEST_PASSWORD, "clientid", TEST_VIRTUALHOST1); - _vhost2Connection = new AMQConnection(_brokerUrl, TEST_USER, TEST_PASSWORD, "clientid", TEST_VIRTUALHOST2); - _vhost1Connection.start(); - _vhost2Connection.start(); - - _vhost1Session = _vhost1Connection.createSession(true, Session.SESSION_TRANSACTED); - _vhost2Session = _vhost2Connection.createSession(true, Session.SESSION_TRANSACTED); - - _vhost1Queue = _vhost2Session.createQueue(getTestQueueName()); - _vhost2Queue = _vhost1Session.createQueue(getTestQueueName()); - - //Create queues by opening and closing consumers - final MessageConsumer vhost1Consumer = _vhost1Session.createConsumer(_vhost2Queue); - vhost1Consumer.close(); - final MessageConsumer vhost2Consumer = _vhost2Session.createConsumer(_vhost1Queue); - vhost2Consumer.close(); - - _jmxUtils.open(); - } - - @Override - public void tearDown() throws Exception - { - _jmxUtils.close(); - - super.tearDown(); - } - - public void testInitialStatisticValues() throws Exception - { - //Check initial values - checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, 0, 0, 0, 0); - checkVHostStatistics(TEST_VIRTUALHOST1, 0, 0, 0, 0); - checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0); - checkVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0); - checkBrokerStatistics(0, 0, 0, 0); - } - - public void testSendOnSingleVHost() throws Exception - { - sendMessagesAndSync(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST); - - //Check values - checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); - checkVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); - checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0); - checkVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0); - checkBrokerStatistics(MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); - } - - public void testSendOnTwoVHosts() throws Exception - { - sendMessagesAndSync(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST); - sendMessagesAndSync(_vhost2Session, _vhost1Queue, MESSAGE_COUNT_DEV); - - //Check values - checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); - checkVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); - checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, MESSAGE_COUNT_DEV, 0, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, 0); - checkVHostStatistics(TEST_VIRTUALHOST2, MESSAGE_COUNT_DEV, 0, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, 0); - checkBrokerStatistics(MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV, 0, (MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV) * DEFAULT_MESSAGE_SIZE, 0); - } - - public void testSendAndConsumeOnSingleVHost() throws Exception - { - sendMessagesAndSync(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST); - consumeMessages(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST); - - //Check values - checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); - checkVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); - checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0); - checkVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0); - checkBrokerStatistics(MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); - } - - public void testSendAndConsumeOnTwoVHosts() throws Exception - { - sendMessagesAndSync(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST); - sendMessagesAndSync(_vhost2Session, _vhost1Queue, MESSAGE_COUNT_DEV); - consumeMessages(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST); - consumeMessages(_vhost2Session, _vhost1Queue, MESSAGE_COUNT_DEV); - - //Check values - checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); - checkVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); - checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE); - checkVHostStatistics(TEST_VIRTUALHOST2, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE); - checkBrokerStatistics(MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV, MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV, (MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV) * DEFAULT_MESSAGE_SIZE, (MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV) * DEFAULT_MESSAGE_SIZE); - } - - private void sendMessagesAndSync(Session session, Queue queue, int numberOfMessages) throws Exception - { - //Send messages via connection on and sync - sendMessage(session, queue, numberOfMessages); - ((AMQSession)session).sync(); - } - - private void consumeMessages(Session session, Queue queue, int numberOfMessages) throws Exception - { - //consume the messages on the virtual host - final MessageConsumer consumer = session.createConsumer(queue); - for (int i = 0 ; i < numberOfMessages ; i++) - { - assertNotNull("an expected message was not received", consumer.receive(1500)); - } - session.commit(); - consumer.close(); - } - - private void checkSingleConnectionOnVHostStatistics(String vHostName, long messagesSent, long messagesReceived, long dataSent, long dataReceived) - { - List managedConnections = _jmxUtils.getManagedConnections(vHostName); - assertEquals(1, managedConnections.size()); - - ManagedConnection managedConnection = managedConnections.get(0); - - assertEquals(messagesSent, managedConnection.getTotalMessagesReceived()); - assertEquals(messagesReceived, managedConnection.getTotalMessagesDelivered()); - - assertEquals(dataSent, managedConnection.getTotalDataReceived()); - assertEquals(dataReceived, managedConnection.getTotalDataDelivered()); - } - - private void checkVHostStatistics(String vHostName, long messagesSent, long messagesReceived, long dataSent, long dataReceived) - { - ManagedBroker vhost = _jmxUtils.getManagedBroker(vHostName); - - assertEquals(messagesSent, vhost.getTotalMessagesReceived()); - assertEquals(messagesReceived, vhost.getTotalMessagesDelivered()); - - assertEquals(dataSent, vhost.getTotalDataReceived()); - assertEquals(dataReceived, vhost.getTotalDataDelivered()); - } - - private void checkBrokerStatistics(long messagesSent, long messagesReceived, long dataSent, long dataReceived) - { - ServerInformation broker = _jmxUtils.getServerInformation(); - - assertEquals(messagesSent, broker.getTotalMessagesReceived()); - assertEquals(messagesReceived, broker.getTotalMessagesDelivered()); - - assertEquals(dataSent, broker.getTotalDataReceived()); - assertEquals(dataReceived, broker.getTotalDataDelivered()); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java deleted file mode 100644 index 25b09f04c3..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java +++ /dev/null @@ -1,261 +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.systest.management.jmx; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import javax.jms.Connection; -import javax.jms.JMSException; - -import org.apache.qpid.management.common.mbeans.UserManagement; -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.security.auth.manager.PlainPasswordDatabaseAuthenticationManager; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.tools.security.Passwd; - -/** - * System test for User Management. - * - */ -public class UserManagementTest extends QpidBrokerTestCase -{ - private static final String TEST_NEWPASSWORD = "newpassword"; - private static final String TEST_PASSWORD = "password"; - private JMXTestUtils _jmxUtils; - private String _testUserName; - private File _passwordFile; - private UserManagement _userManagement; - private Passwd _passwd; - - public void setUp() throws Exception - { - _passwd = createPasswordEncodingUtility(); - _passwordFile = createTemporaryPasswordFileWithJmxAdminUser(); - - Map newAttributes = new HashMap(); - newAttributes.put(AuthenticationProvider.TYPE, getAuthenticationManagerType()); - newAttributes.put("path", _passwordFile.getAbsolutePath()); - getBrokerConfiguration().setObjectAttributes(AuthenticationProvider.class,TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, newAttributes); - getBrokerConfiguration().addJmxManagementConfiguration(); - - _jmxUtils = new JMXTestUtils(this); - - super.setUp(); - _jmxUtils.open(); - - _testUserName = getTestName() + System.currentTimeMillis(); - - _userManagement = _jmxUtils.getUserManagement(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); - } - - - public void tearDown() throws Exception - { - try - { - if (_jmxUtils != null) - { - _jmxUtils.close(); - } - } - finally - { - super.tearDown(); - } - } - - public void testCreateUser() throws Exception - { - final int initialNumberOfUsers = _userManagement.viewUsers().size(); - assertFileDoesNotContainsPasswordForUser(_testUserName); - - boolean success = _userManagement.createUser(_testUserName, TEST_PASSWORD); - assertTrue("Should have been able to create new user " + _testUserName, success); - assertEquals("Unexpected number of users after add", initialNumberOfUsers + 1, _userManagement.viewUsers().size()); - - assertFileContainsPasswordForUser(_testUserName); - } - - public void testJmsLoginForNewUser() throws Exception - { - assertJmsConnectionFails(_testUserName, TEST_PASSWORD); - testCreateUser(); - - assertJmsConnectionSucceeds(_testUserName, TEST_PASSWORD); - } - - public void testDeleteUser() throws Exception - { - final int initialNumberOfUsers = _userManagement.viewUsers().size(); - - testCreateUser(); - - boolean success = _userManagement.deleteUser(_testUserName); - assertTrue("Should have been able to delete new user " + _testUserName, success); - assertEquals("Unexpected number of users after delete", initialNumberOfUsers, _userManagement.viewUsers().size()); - assertFileDoesNotContainsPasswordForUser(_testUserName); - } - - public void testJmsLoginNotPossibleForDeletedUser() throws Exception - { - testDeleteUser(); - - assertJmsConnectionFails(_testUserName, TEST_PASSWORD); - } - - public void testSetPassword() throws Exception - { - testCreateUser(); - - _userManagement.setPassword(_testUserName, TEST_NEWPASSWORD); - - assertFileContainsPasswordForUser(_testUserName); - } - - public void testJmsLoginForPasswordChangedUser() throws Exception - { - testSetPassword(); - - assertJmsConnectionSucceeds(_testUserName, TEST_NEWPASSWORD); - assertJmsConnectionFails(_testUserName, TEST_PASSWORD); - } - - public void testReload() throws Exception - { - writePasswordFile(_passwordFile, JMXTestUtils.DEFAULT_USERID, JMXTestUtils.DEFAULT_PASSWORD, _testUserName, TEST_PASSWORD); - - assertJmsConnectionFails(_testUserName, TEST_PASSWORD); - - _userManagement.reloadData(); - - assertJmsConnectionSucceeds(_testUserName, TEST_PASSWORD); - } - - public void testGetAuthenticationProviderType() throws Exception - { - String actualType = _userManagement.getAuthenticationProviderType(); - assertEquals("unexpected authentication provider type", getAuthenticationManagerType(), actualType); - } - - protected Passwd createPasswordEncodingUtility() - { - return new Passwd() - { - @Override - public String getOutput(String username, String password) - { - return username + ":" + password; - } - }; - } - - protected String getAuthenticationManagerType() - { - return PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE; - } - - private File createTemporaryPasswordFileWithJmxAdminUser() throws Exception - { - File passwordFile = File.createTempFile("passwd", "pwd"); - passwordFile.deleteOnExit(); - writePasswordFile(passwordFile, JMXTestUtils.DEFAULT_USERID, JMXTestUtils.DEFAULT_PASSWORD); - return passwordFile; - } - - private void writePasswordFile(File passwordFile, String... userNamePasswordPairs) throws Exception - { - FileWriter writer = null; - try - { - writer = new FileWriter(passwordFile); - for (int i = 0; i < userNamePasswordPairs.length; i=i+2) - { - String username = userNamePasswordPairs[i]; - String password = userNamePasswordPairs[i+1]; - writer.append(_passwd.getOutput(username, password) + "\n"); - } - } - finally - { - writer.close(); - } - } - - - private void assertFileContainsPasswordForUser(String username) throws IOException - { - assertTrue("Could not find password for user " + username + " within " + _passwordFile, passwordFileContainsUser(username)); - } - - private void assertFileDoesNotContainsPasswordForUser(String username) throws IOException - { - assertFalse("Could not find password for user " + username + " within " + _passwordFile, passwordFileContainsUser(username)); - } - - private boolean passwordFileContainsUser(String username) throws IOException - { - BufferedReader reader = null; - try - { - reader = new BufferedReader(new FileReader(_passwordFile)); - String line = reader.readLine(); - while(line != null) - { - if (line.startsWith(username)) - { - return true; - } - line = reader.readLine(); - } - - return false; - } - finally - { - reader.close(); - } - } - - private void assertJmsConnectionSucceeds(String username, String password) throws Exception - { - Connection connection = getConnection(username, password); - assertNotNull(connection); - } - - private void assertJmsConnectionFails(String username, String password) throws Exception - { - try - { - getConnection(username, password); - fail("Exception not thrown"); - } - catch (JMSException e) - { - // PASS - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java deleted file mode 100644 index ff441169b3..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java +++ /dev/null @@ -1,37 +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.systest.management.jmx; - -import org.apache.qpid.server.security.auth.manager.Base64MD5PasswordDatabaseAuthenticationManager; -import org.apache.qpid.tools.security.Passwd; - -public class UserManagementWithBase64MD5PasswordsTest extends UserManagementTest -{ - @Override - protected Passwd createPasswordEncodingUtility() - { - return new Passwd(); - } - - @Override - protected String getAuthenticationManagerType() - { - return Base64MD5PasswordDatabaseAuthenticationManager.PROVIDER_TYPE; - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AccessControlProviderRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AccessControlProviderRestTest.java deleted file mode 100644 index 4140c9c12c..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AccessControlProviderRestTest.java +++ /dev/null @@ -1,288 +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.systest.rest; - -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import org.apache.qpid.server.BrokerOptions; -import org.apache.qpid.server.management.plugin.HttpManagement; -import org.apache.qpid.server.model.AccessControlProvider; -import org.apache.qpid.server.model.Plugin; -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.security.access.FileAccessControlProviderConstants; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.test.utils.TestFileUtils; - -public class AccessControlProviderRestTest extends QpidRestTestCase -{ - private static final String ALLOWED_USER = "allowed"; - private static final String DENIED_USER = "denied"; - private static final String OTHER_USER = "other"; - - private String _aclFileContent1 = - "ACL ALLOW-LOG " + ALLOWED_USER + " ACCESS MANAGEMENT\n" + - "ACL ALLOW-LOG " + ALLOWED_USER + " CONFIGURE BROKER\n" + - "ACL DENY-LOG ALL ALL"; - - private String _aclFileContent2 = - "ACL ALLOW-LOG " + ALLOWED_USER + " ACCESS MANAGEMENT\n" + - "ACL ALLOW-LOG " + OTHER_USER + " ACCESS MANAGEMENT\n" + - "ACL ALLOW-LOG " + ALLOWED_USER + " CONFIGURE BROKER\n" + - "ACL DENY-LOG ALL ALL"; - - @Override - protected void customizeConfiguration() throws IOException - { - super.customizeConfiguration(); - getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER, OTHER_USER); - - getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, - HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); - } - - public void testCreateAccessControlProvider() throws Exception - { - String accessControlProviderName = getTestName(); - - //verify that the access control provider doesn't exist, and - //in doing so implicitly verify that the 'denied' user can - //actually currently connect because no ACL is in effect yet - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - assertAccessControlProviderExistence(accessControlProviderName, false); - - //create the access control provider using the 'allowed' user - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - int responseCode = createAccessControlProvider(accessControlProviderName, _aclFileContent1); - assertEquals("Access control provider creation should be allowed", 201, responseCode); - - //verify it exists with the 'allowed' user - assertAccessControlProviderExistence(accessControlProviderName, true); - - //verify the 'denied' user can no longer access the management interface - //due to the just-created ACL file now preventing it - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - assertCanAccessManagementInterface(accessControlProviderName, false); - } - - public void testRemoveAccessControlProvider() throws Exception - { - String accessControlProviderName = getTestName(); - - //verify that the access control provider doesn't exist, and - //in doing so implicitly verify that the 'denied' user can - //actually currently connect because no ACL is in effect yet - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - assertAccessControlProviderExistence(accessControlProviderName, false); - - //create the access control provider using the 'allowed' user - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - int responseCode = createAccessControlProvider(accessControlProviderName, _aclFileContent1); - assertEquals("Access control provider creation should be allowed", 201, responseCode); - - //verify it exists with the 'allowed' user - assertAccessControlProviderExistence(accessControlProviderName, true); - - //verify the 'denied' user can no longer access the management interface - //due to the just-created ACL file now preventing it - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - assertCanAccessManagementInterface(accessControlProviderName, false); - - //remove the access control provider using the 'allowed' user - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "DELETE"); - assertEquals("Access control provider deletion should be allowed", 200, responseCode); - assertAccessControlProviderExistence(accessControlProviderName, false); - - //verify it is gone again, using the 'denied' user to implicitly confirm it is - //now able to connect to the management interface again because the ACL was removed. - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - assertAccessControlProviderExistence(accessControlProviderName, false); - } - - public void testReplaceAccessControlProvider() throws Exception - { - String accessControlProviderName1 = getTestName() + "1"; - - //verify that the access control provider doesn't exist, and - //in doing so implicitly verify that the 'denied' user can - //actually currently connect because no ACL is in effect yet - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - assertAccessControlProviderExistence(accessControlProviderName1, false); - - //create the access control provider using the 'allowed' user - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - int responseCode = createAccessControlProvider(accessControlProviderName1, _aclFileContent1); - assertEquals("Access control provider creation should be allowed", 201, responseCode); - - //verify it exists with the 'allowed' user - assertAccessControlProviderExistence(accessControlProviderName1, true); - - //verify the 'denied' and 'other' user can no longer access the management - //interface due to the just-created ACL file now preventing them - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - assertCanAccessManagementInterface(accessControlProviderName1, false); - getRestTestHelper().setUsernameAndPassword(OTHER_USER, OTHER_USER); - assertCanAccessManagementInterface(accessControlProviderName1, false); - - //create the replacement access control provider using the 'allowed' user. - String accessControlProviderName2 = getTestName() + "2"; - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - responseCode = createAccessControlProvider(accessControlProviderName2, _aclFileContent2); - assertEquals("Access control provider creation should be allowed", 201, responseCode); - - //Verify that it took effect immediately, replacing the first access control provider - - //verify the 'denied' user still can't access the management interface, but the 'other' user now CAN. - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - assertCanAccessManagementInterface(accessControlProviderName2, false); - getRestTestHelper().setUsernameAndPassword(OTHER_USER, OTHER_USER); - assertCanAccessManagementInterface(accessControlProviderName2, true); - - //remove the original access control provider using the 'allowed' user - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName1, "DELETE"); - assertEquals("Access control provider deletion should be allowed", 200, responseCode); - assertAccessControlProviderExistence(accessControlProviderName1, false); - - //verify the 'denied' user still can't access the management interface, the 'other' user still can, thus - //confirming that the second access control provider is still in effect - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - assertCanAccessManagementInterface(accessControlProviderName2, false); - getRestTestHelper().setUsernameAndPassword(OTHER_USER, OTHER_USER); - assertCanAccessManagementInterface(accessControlProviderName2, true); - } - - - public void testAddAndRemoveSecondAccessControlProviderReinstatesOriginal() throws Exception - { - String accessControlProviderName1 = getTestName() + "1"; - - //verify that the access control provider doesn't exist, and - //in doing so implicitly verify that the 'denied' user can - //actually currently connect because no ACL is in effect yet - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - assertAccessControlProviderExistence(accessControlProviderName1, false); - - //create the access control provider using the 'allowed' user - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - int responseCode = createAccessControlProvider(accessControlProviderName1, _aclFileContent1); - assertEquals("Access control provider creation should be allowed", 201, responseCode); - - //verify it exists with the 'allowed' user - assertAccessControlProviderExistence(accessControlProviderName1, true); - - //verify the 'denied' and 'other' user can no longer access the management - //interface due to the just-created ACL file now preventing them - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - assertCanAccessManagementInterface(accessControlProviderName1, false); - getRestTestHelper().setUsernameAndPassword(OTHER_USER, OTHER_USER); - assertCanAccessManagementInterface(accessControlProviderName1, false); - - //create the replacement access control provider using the 'allowed' user. - String accessControlProviderName2 = getTestName() + "2"; - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - responseCode = createAccessControlProvider(accessControlProviderName2, _aclFileContent2); - assertEquals("Access control provider creation should be allowed", 201, responseCode); - - //Verify that it took effect immediately, replacing the first access control provider - - //verify the 'denied' user still can't access the management interface, but the 'other' user now CAN. - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - assertCanAccessManagementInterface(accessControlProviderName2, false); - getRestTestHelper().setUsernameAndPassword(OTHER_USER, OTHER_USER); - assertCanAccessManagementInterface(accessControlProviderName2, true); - - //remove the second access control provider using the 'allowed' user - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName2, "DELETE"); - assertEquals("Access control provider deletion should be allowed", 200, responseCode); - assertAccessControlProviderExistence(accessControlProviderName2, false); - - //verify the 'denied' user still can't access the management interface, the - //'other' now CANT again, the 'allowed' still can, thus confirming that the - //first access control provider is now in effect once again - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - assertCanAccessManagementInterface(accessControlProviderName2, false); - getRestTestHelper().setUsernameAndPassword(OTHER_USER, OTHER_USER); - assertCanAccessManagementInterface(accessControlProviderName2, false); - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - assertCanAccessManagementInterface(accessControlProviderName2, true); - } - - public void testRemovalOfAccessControlProviderInErrorStateUsingManagementMode() throws Exception - { - stopBroker(); - - File file = new File(TMP_FOLDER, getTestName()); - if (file.exists()) - { - file.delete(); - } - assertFalse("ACL file should not exist", file.exists()); - UUID id = getBrokerConfiguration().addAclFileConfiguration(file.getAbsolutePath()); - getBrokerConfiguration().setSaved(false); - startBroker(0, true); - - getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD); - - Map acl = getRestTestHelper().getJsonAsSingletonList("accesscontrolprovider/" + TestBrokerConfiguration.ENTRY_NAME_ACL_FILE); - assertEquals("Unexpected id", id.toString(), acl.get(AccessControlProvider.ID)); - assertEquals("Unexpected path", file.getAbsolutePath() , acl.get(FileAccessControlProviderConstants.PATH)); - assertEquals("Unexpected state", State.ERRORED.name() , acl.get(AccessControlProvider.STATE)); - - int status = getRestTestHelper().submitRequest("accesscontrolprovider/" + TestBrokerConfiguration.ENTRY_NAME_ACL_FILE, "DELETE"); - assertEquals("ACL was not deleted", 200, status); - - List> acls = getRestTestHelper().getJsonAsList("accesscontrolprovider/" + TestBrokerConfiguration.ENTRY_NAME_ACL_FILE); - assertEquals("ACL exists", 0, acls.size()); - } - - private void assertCanAccessManagementInterface(String accessControlProviderName, boolean canAccess) throws Exception - { - int expected = canAccess ? 200 : 403; - int responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "GET"); - assertEquals("Unexpected response code", expected, responseCode); - } - - private void assertAccessControlProviderExistence(String accessControlProviderName, boolean exists) throws Exception - { - String path = "accesscontrolprovider/" + accessControlProviderName; - List> providers = getRestTestHelper().getJsonAsList(path); - assertEquals("Unexpected result", exists, !providers.isEmpty()); - } - - private int createAccessControlProvider(String accessControlProviderName, String content) throws Exception - { - File file = TestFileUtils.createTempFile(this, ".acl", content); - Map attributes = new HashMap(); - attributes.put(AccessControlProvider.NAME, accessControlProviderName); - attributes.put(AccessControlProvider.TYPE, FileAccessControlProviderConstants.ACL_FILE_PROVIDER_TYPE); - attributes.put(FileAccessControlProviderConstants.PATH, file.getAbsoluteFile()); - - return getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "PUT", attributes); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AnonymousAccessRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AnonymousAccessRestTest.java deleted file mode 100644 index 3f944da8c7..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AnonymousAccessRestTest.java +++ /dev/null @@ -1,115 +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.systest.rest; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import org.apache.qpid.server.management.plugin.HttpManagement; -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.Plugin; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class AnonymousAccessRestTest extends QpidRestTestCase -{ - @Override - public void startBroker() - { - // prevent broker from starting in setUp - } - - public void startBrokerNow() throws Exception - { - super.startBroker(); - } - - @Override - protected void customizeConfiguration() throws IOException - { - super.customizeConfiguration(); - TestBrokerConfiguration config = getBrokerConfiguration(); - - Map anonymousAuthProviderAttributes = new HashMap(); - anonymousAuthProviderAttributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); - anonymousAuthProviderAttributes.put(AuthenticationProvider.NAME, TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER); - config.addObjectConfiguration(AuthenticationProvider.class, anonymousAuthProviderAttributes); - - // set anonymous authentication provider on http port for the tests - config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER, - TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER); - config.setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, false); - - // reset credentials - getRestTestHelper().setUsernameAndPassword(null, null); - } - - public void testGetWithAnonymousProvider() throws Exception - { - startBrokerNow(); - - Map brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker"); - assertNotNull("Unexpected broker attributes", brokerDetails); - assertNotNull("Unexpected value of attribute " + Broker.ID, brokerDetails.get(Broker.ID)); - } - - public void testPutAnonymousProvider() throws Exception - { - startBrokerNow(); - - Map brokerAttributes = new HashMap(); - brokerAttributes.put(Broker.DEFAULT_VIRTUAL_HOST, TEST3_VIRTUALHOST); - - int response = getRestTestHelper().submitRequest("broker", "PUT", brokerAttributes); - assertEquals("Unexpected update response", 200, response); - - Map brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker"); - assertNotNull("Unexpected broker attributes", brokerDetails); - assertNotNull("Unexpected value of attribute " + Broker.ID, brokerDetails.get(Broker.ID)); - assertEquals("Unexpected default virtual host", TEST3_VIRTUALHOST, brokerDetails.get(Broker.DEFAULT_VIRTUAL_HOST)); - } - - public void testGetWithPasswordAuthProvider() throws Exception - { - getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER, - TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); - startBrokerNow(); - - int response = getRestTestHelper().submitRequest("broker", "GET"); - assertEquals("Anonymous access should be denied", 401, response); - } - - public void testPutWithPasswordAuthProvider() throws Exception - { - getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER, - TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); - startBrokerNow(); - - Map brokerAttributes = new HashMap(); - brokerAttributes.put(Broker.DEFAULT_VIRTUAL_HOST, TEST3_VIRTUALHOST); - - int response = getRestTestHelper().submitRequest("broker", "PUT", brokerAttributes); - assertEquals("Anonymous access should be denied", 401, response); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java deleted file mode 100644 index 2467705903..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java +++ /dev/null @@ -1,337 +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.systest.rest; - -import java.io.File; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import org.apache.qpid.server.BrokerOptions; -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.model.BrokerModel; -import org.apache.qpid.server.model.ConfiguredObject; -import org.apache.qpid.server.model.ExternalFileBasedAuthenticationManager; -import org.apache.qpid.server.model.LifetimePolicy; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.model.User; -import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager; -import org.apache.qpid.server.security.auth.manager.PlainPasswordDatabaseAuthenticationManager; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class AuthenticationProviderRestTest extends QpidRestTestCase -{ - - public void testGet() throws Exception - { - List> providerDetails = getRestTestHelper().getJsonAsList("authenticationprovider"); - assertNotNull("Providers details cannot be null", providerDetails); - assertEquals("Unexpected number of providers", 2, providerDetails.size()); - for (Map provider : providerDetails) - { - boolean managesPrincipals = true; - String type = PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE; - if (ANONYMOUS_AUTHENTICATION_PROVIDER.equals(provider.get(AuthenticationProvider.NAME))) - { - type = AnonymousAuthenticationManager.PROVIDER_TYPE; - managesPrincipals = false; - } - assertProvider(managesPrincipals, type , provider); - Map data = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" - + provider.get(AuthenticationProvider.NAME)); - assertNotNull("Cannot load data for " + provider.get(AuthenticationProvider.NAME), data); - assertProvider(managesPrincipals, type, data); - } - } - - public void testPutCreateSecondPlainPrincipalDatabaseProviderSucceeds() throws Exception - { - File principalDatabase = getRestTestHelper().createTemporaryPasswdFile(new String[]{"admin2", "guest2", "test2"}); - - String providerName = "test-provider"; - Map attributes = new HashMap(); - attributes.put(AuthenticationProvider.NAME, providerName); - attributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE); - attributes.put(ExternalFileBasedAuthenticationManager.PATH, principalDatabase.getAbsolutePath()); - - int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); - assertEquals("failed to create authentication provider", 201, responseCode); - } - - public void testPutCreateNewAnonymousProvider() throws Exception - { - String providerName = "test-provider"; - Map attributes = new HashMap(); - attributes.put(AuthenticationProvider.NAME, providerName); - attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); - - int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); - assertEquals("Unexpected response code", 201, responseCode); - - List> providerDetails = getRestTestHelper().getJsonAsList("authenticationprovider/" + providerName); - assertNotNull("Providers details cannot be null", providerDetails); - assertEquals("Unexpected number of providers", 1, providerDetails.size()); - Map provider = providerDetails.get(0); - assertProvider(false, AnonymousAuthenticationManager.PROVIDER_TYPE, provider); - } - - public void testUpdateAuthenticationProviderIdFails() throws Exception - { - String providerName = "test-provider"; - Map attributes = new HashMap(); - attributes.put(AuthenticationProvider.NAME, providerName); - attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); - - int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); - assertEquals("Unexpected response code", 201, responseCode); - - attributes.put(AuthenticationProvider.ID, UUID.randomUUID()); - - responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); - assertEquals("Update with new ID should fail", 409, responseCode); - } - - public void testDeleteOfUsedAuthenticationProviderFails() throws Exception - { - // create provider - String providerName = "test-provider"; - Map attributes = new HashMap(); - attributes.put(AuthenticationProvider.NAME, providerName); - attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); - - int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); - assertEquals("Unexpected response code for provider creation", 201, responseCode); - - // create port - String portName = "test-port"; - Map portAttributes = new HashMap(); - portAttributes.put(Port.NAME, portName); - portAttributes.put(Port.AUTHENTICATION_PROVIDER, providerName); - portAttributes.put(Port.PORT, findFreePort()); - - responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", portAttributes); - assertEquals("Unexpected response code for port creation", 201, responseCode); - - responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName , "DELETE"); - assertEquals("Unexpected response code for provider deletion", 409, responseCode); - - List> providerDetails = getRestTestHelper().getJsonAsList("authenticationprovider/" + providerName); - assertNotNull("Providers details cannot be null", providerDetails); - assertEquals("Unexpected number of providers", 1, providerDetails.size()); - assertProvider(false, AnonymousAuthenticationManager.PROVIDER_TYPE, providerDetails.get(0)); - } - - public void testDeleteOfUnusedAuthenticationProvider() throws Exception - { - // create provider - String providerName = "test-provider"; - Map attributes = new HashMap(); - attributes.put(AuthenticationProvider.NAME, providerName); - attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); - - int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); - assertEquals("Unexpected response code for provider creation", 201, responseCode); - - responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName , "DELETE"); - assertEquals("Unexpected response code for provider deletion", 200, responseCode); - - List> providerDetails = getRestTestHelper().getJsonAsList("authenticationprovider/" + providerName); - assertNotNull("Providers details cannot be null", providerDetails); - assertEquals("Unexpected number of providers", 0, providerDetails.size()); - } - - public void testRemovalOfAuthenticationProviderInErrorStateUsingManagementMode() throws Exception - { - stopBroker(); - - File file = new File(TMP_FOLDER, getTestName()); - if (file.exists()) - { - file.delete(); - } - assertFalse("Group file should not exist", file.exists()); - - TestBrokerConfiguration config = getBrokerConfiguration(); - - String providerName = getTestName(); - Map attributes = new HashMap(); - attributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE); - attributes.put(AuthenticationProvider.NAME, providerName); - attributes.put(ExternalFileBasedAuthenticationManager.PATH, file.getAbsoluteFile()); - - UUID id = config.addObjectConfiguration(AuthenticationProvider.class, attributes); - config.setSaved(false); - startBroker(0, true); - - getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD); - - Map provider = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + providerName); - assertEquals("Unexpected id", id.toString(), provider.get(AuthenticationProvider.ID)); - assertEquals("Unexpected name", providerName, provider.get(AuthenticationProvider.NAME)); - assertEquals("Unexpected path", file.getAbsolutePath() , provider.get(ExternalFileBasedAuthenticationManager.PATH)); - assertEquals("Unexpected state", State.ERRORED.name() , provider.get(AuthenticationProvider.STATE)); - - int status = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "DELETE"); - assertEquals("ACL was not deleted", 200, status); - - List> providers = getRestTestHelper().getJsonAsList("authenticationprovider/" + providerName); - assertEquals("Provider exists", 0, providers.size()); - } - - public void testUpdateOfAuthenticationProviderInErrorStateUsingManagementMode() throws Exception - { - stopBroker(); - - File file = new File(TMP_FOLDER, getTestName()); - if (file.exists()) - { - file.delete(); - } - assertFalse("Group file should not exist", file.exists()); - - TestBrokerConfiguration config = getBrokerConfiguration(); - - String providerName = getTestName(); - Map attributes = new HashMap(); - attributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE); - attributes.put(AuthenticationProvider.NAME, providerName); - attributes.put(ExternalFileBasedAuthenticationManager.PATH, file.getAbsoluteFile()); - - UUID id = config.addObjectConfiguration(AuthenticationProvider.class, attributes); - config.setSaved(false); - startBroker(0, true); - - getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD); - - Map provider = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + providerName); - assertEquals("Unexpected id", id.toString(), provider.get(AuthenticationProvider.ID)); - assertEquals("Unexpected name", providerName, provider.get(AuthenticationProvider.NAME)); - assertEquals("Unexpected path", file.getAbsolutePath() , provider.get(ExternalFileBasedAuthenticationManager.PATH)); - assertEquals("Unexpected state", State.ERRORED.name() , provider.get(AuthenticationProvider.STATE)); - - File principalDatabase = null; - try - { - principalDatabase = getRestTestHelper().createTemporaryPasswdFile(new String[]{"admin2", "guest2", "test2"}); - attributes = new HashMap(); - attributes.put(AuthenticationProvider.NAME, providerName); - attributes.put(AuthenticationProvider.ID, id); - attributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE); - attributes.put(ExternalFileBasedAuthenticationManager.PATH, principalDatabase.getAbsolutePath()); - - int status = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); - assertEquals("ACL was not deleted", 200, status); - - provider = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + providerName); - assertEquals("Unexpected id", id.toString(), provider.get(AuthenticationProvider.ID)); - assertEquals("Unexpected name", providerName, provider.get(AuthenticationProvider.NAME)); - assertEquals("Unexpected path", principalDatabase.getAbsolutePath() , provider.get( - ExternalFileBasedAuthenticationManager.PATH)); - assertEquals("Unexpected state", State.ACTIVE.name() , provider.get(AuthenticationProvider.STATE)); - } - finally - { - if (principalDatabase != null) - { - principalDatabase.delete(); - } - } - } - - public void testCreateAndDeletePasswordAuthenticationProviderWithNonExistingFile() throws Exception - { - stopBroker(); - getBrokerConfiguration().setSaved(false); - getBrokerConfiguration().removeObjectConfiguration(AuthenticationProvider.class, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); - getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT, Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER); - getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER); - - startBroker(); - - File file = new File(TMP_FOLDER + File.separator + getTestName()); - if (file.exists()) - { - file.delete(); - } - assertFalse("File " + file.getAbsolutePath() + " should not exist", file.exists()); - - // create provider - String providerName = "test-provider"; - Map attributes = new HashMap(); - attributes.put(AuthenticationProvider.NAME, providerName); - attributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE); - attributes.put(ExternalFileBasedAuthenticationManager.PATH, file.getAbsolutePath()); - - int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); - assertEquals("Password provider was not created", 201, responseCode); - - - Map providerDetails = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + providerName); - assertNotNull("Providers details cannot be null", providerDetails); - assertEquals("Unexpected name", providerName, providerDetails.get(AuthenticationProvider.NAME)); - assertEquals("Unexpected type", PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE, providerDetails.get(AuthenticationProvider.TYPE)); - assertEquals("Unexpected path", file.getAbsolutePath(), providerDetails.get( - ExternalFileBasedAuthenticationManager.PATH)); - - assertTrue("User file should be created", file.exists()); - - responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName , "DELETE"); - assertEquals("Unexpected response code for provider deletion", 200, responseCode); - - List> providers = getRestTestHelper().getJsonAsList("authenticationprovider/" + providerName); - assertNotNull("Providers details cannot be null", providers); - assertEquals("Unexpected number of providers", 0, providers.size()); - - assertFalse("File " + file.getAbsolutePath() + " should be deleted", file.exists()); - } - - private void assertProvider(boolean managesPrincipals, String type, Map provider) - { - Asserts.assertAttributesPresent(provider, BrokerModel.getInstance().getTypeRegistry().getAttributeNames( - AuthenticationProvider.class), - AuthenticationProvider.DESCRIPTION, ConfiguredObject.CONTEXT, - ConfiguredObject.DESIRED_STATE, ConfiguredObject.CREATED_BY, - ConfiguredObject.CREATED_TIME, ConfiguredObject.LAST_UPDATED_BY, ConfiguredObject.LAST_UPDATED_TIME); - assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.STATE, State.ACTIVE.name(), - provider.get(AuthenticationProvider.STATE)); - assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.LIFETIME_POLICY, - LifetimePolicy.PERMANENT.name(), provider.get(AuthenticationProvider.LIFETIME_POLICY)); - assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.DURABLE, Boolean.TRUE, - provider.get(AuthenticationProvider.DURABLE)); - assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.TYPE, type, - provider.get(AuthenticationProvider.TYPE)); - - if (managesPrincipals) - { - @SuppressWarnings("unchecked") - List> users = (List>) provider.get("users"); - assertNotNull("Users are not found", users); - assertTrue("Unexpected number of users", users.size() > 1); - for (Map user : users) - { - assertNotNull("Attribute " + User.ID, user.get(User.ID)); - assertNotNull("Attribute " + User.NAME, user.get(User.NAME)); - } - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java deleted file mode 100644 index c51457cdab..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java +++ /dev/null @@ -1,122 +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.systest.rest; - -import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE; -import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD; - -import java.io.IOException; -import java.util.Collections; - -import javax.servlet.http.HttpServletResponse; - -import org.apache.qpid.server.management.plugin.HttpManagement; -import org.apache.qpid.server.model.Plugin; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.Transport; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class BasicAuthRestTest extends QpidRestTestCase -{ - private static final String USERNAME = "admin"; - - @Override - public void setUp() throws Exception - { - setSystemProperty("javax.net.debug", "ssl"); - - //don't call super method, we will configure the broker in the test before doing so - } - - @Override - protected void customizeConfiguration() throws IOException - { - //do nothing, we will configure this locally - } - - private void configure(boolean useSsl) throws IOException - { - getRestTestHelper().setUseSsl(useSsl); - if (useSsl) - { - getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.TRANSPORTS, Collections.singleton(Transport.SSL)); - getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); - } - super.customizeConfiguration(); - } - - private void verifyGetBrokerAttempt(int responseCode) throws IOException - { - assertEquals(responseCode, getRestTestHelper().submitRequest("broker", "GET")); - } - - public void testBasicAuthWhenEnabledWithHttps() throws Exception - { - configure(true); - super.setUp(); - setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); - setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); - - // Try the attempt with authentication, it should succeed because - // BASIC auth is enabled by default on secure connections. - getRestTestHelper().setUsernameAndPassword(USERNAME, USERNAME); - verifyGetBrokerAttempt(HttpServletResponse.SC_OK); - } - - public void testBasicAuthWhenDisabledWithHttp() throws Exception - { - configure(false); - getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, false); - super.setUp(); - - // Try the attempt with authentication, it should fail because - // BASIC auth is disabled by default on non-secure connections. - getRestTestHelper().setUsernameAndPassword(USERNAME, USERNAME); - verifyGetBrokerAttempt(HttpServletResponse.SC_UNAUTHORIZED); - } - - public void testEnablingForHttp() throws Exception - { - configure(false); - - getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); - super.setUp(); - - // Try the attempt with authentication, it should succeed because - // BASIC auth is now enabled on non-secure connections. - getRestTestHelper().setUsernameAndPassword(USERNAME, USERNAME); - verifyGetBrokerAttempt(HttpServletResponse.SC_OK); - } - - public void testDisablingForHttps() throws Exception - { - configure(true); - getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, "httpsBasicAuthenticationEnabled", false); - super.setUp(); - setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); - setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); - - // Try the attempt with authentication, it should fail because - // BASIC auth is now disabled on secure connections. - getRestTestHelper().setUsernameAndPassword(USERNAME, USERNAME); - verifyGetBrokerAttempt(HttpServletResponse.SC_UNAUTHORIZED); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BindingRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BindingRestTest.java deleted file mode 100644 index 368bc90d3d..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BindingRestTest.java +++ /dev/null @@ -1,131 +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.systest.rest; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.qpid.server.model.Binding; - -public class BindingRestTest extends QpidRestTestCase -{ - - @Override - public void setUp() throws Exception - { - super.setUp(); - getRestTestHelper().createTestQueues(); - } - - public void testGetAllBindings() throws Exception - { - List> bindings = getRestTestHelper().getJsonAsList("binding/test"); - assertNotNull("Bindings cannot be null", bindings); - assertEquals("Unexpected number of bindings", RestTestHelper.EXPECTED_QUEUES.length, bindings.size()); - for (Map binding : bindings) - { - Asserts.assertBinding((String) binding.get(Binding.NAME), (String) binding.get(Binding.EXCHANGE), binding); - } - } - - public void testGetVirtualHostExchangeBindings() throws Exception - { - List> bindings = getRestTestHelper().getJsonAsList("binding/test/test/amq.direct"); - assertNotNull("Bindings cannot be null", bindings); - assertEquals("Unexpected number of bindings", RestTestHelper.EXPECTED_QUEUES.length, bindings.size()); - for (String queueName : RestTestHelper.EXPECTED_QUEUES) - { - Map binding = getRestTestHelper().find(Binding.NAME, queueName, bindings); - Asserts.assertBinding(queueName, "amq.direct", binding); - } - } - - public void testGetVirtualHostExchangeQueueBindings() throws Exception - { - List> bindings = getRestTestHelper().getJsonAsList("binding/test/test/amq.direct/queue"); - assertNotNull("Bindings cannot be null", bindings); - assertEquals("Unexpected number of bindings", 1, bindings.size()); - Asserts.assertBinding("queue", "amq.direct", bindings.get(0)); - } - - - public void testDeleteBinding() throws Exception - { - String bindingUrl = "binding/test/test/amq.direct/queue/queue"; - List> bindings = getRestTestHelper().getJsonAsList(bindingUrl); - assertEquals("Unexpected number of bindings", 1, bindings.size()); - Asserts.assertBinding("queue", "amq.direct", bindings.get(0)); - - int responseCode = getRestTestHelper().submitRequest(bindingUrl, "DELETE"); - assertEquals("Unexpected response code", 200, responseCode); - - bindings = getRestTestHelper().getJsonAsList(bindingUrl); - assertEquals("Binding should be deleted", 0, bindings.size()); - } - - public void testDeleteBindingById() throws Exception - { - Map binding = getRestTestHelper().getJsonAsSingletonList("binding/test/test/amq.direct/queue"); - int responseCode = getRestTestHelper().submitRequest("binding/test/test/amq.direct?id=" + binding.get(Binding.ID), "DELETE"); - assertEquals("Unexpected response code", 200, responseCode); - List> bindings = getRestTestHelper().getJsonAsList("binding/test/test/amq.direct/queue"); - assertEquals("Binding should be deleted", 0, bindings.size()); - } - - public void testCreateBinding() throws Exception - { - String bindingName = getTestName(); - Map bindingData = new HashMap(); - bindingData.put(Binding.NAME, bindingName); - bindingData.put(Binding.QUEUE, "queue"); - bindingData.put(Binding.EXCHANGE, "amq.direct"); - - String bindingUrl = "binding/test/test/amq.direct/queue/" + bindingName; - - int responseCode = getRestTestHelper().submitRequest(bindingUrl, "PUT", bindingData); - assertEquals("Unexpected response code", 201, responseCode); - - Map binding = getRestTestHelper().getJsonAsSingletonList(bindingUrl); - Asserts.assertBinding(bindingName, "queue", "amq.direct", binding); - } - - public void testSetBindingAttributesUnsupported() throws Exception - { - String bindingName = getTestName(); - Map attributes = new HashMap(); - attributes.put(Binding.NAME, bindingName); - attributes.put(Binding.QUEUE, "queue"); - attributes.put(Binding.EXCHANGE, "amq.direct"); - - String bindingUrl = "binding/test/test/amq.direct/queue/" + bindingName; - int responseCode = getRestTestHelper().submitRequest(bindingUrl, "PUT", attributes); - assertEquals("Unexpected response code", 201, responseCode); - - Map binding = getRestTestHelper().getJsonAsSingletonList(bindingUrl); - Asserts.assertBinding(bindingName, "queue", "amq.direct", binding); - - attributes.put(Binding.ARGUMENTS, "blah"); - - responseCode = getRestTestHelper().submitRequest(bindingUrl, "PUT", attributes); - assertEquals("Update should be unsupported", 409, responseCode); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpAndHttpsTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpAndHttpsTest.java deleted file mode 100644 index 74db3e7040..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpAndHttpsTest.java +++ /dev/null @@ -1,85 +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.systest.rest; - -import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE; -import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.Protocol; -import org.apache.qpid.server.model.Transport; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class BrokerRestHttpAndHttpsTest extends QpidRestTestCase -{ - @Override - public void setUp() throws Exception - { - setSystemProperty("javax.net.debug", "ssl"); - super.setUp(); - setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); - setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); - } - - @Override - protected void customizeConfiguration() throws IOException - { - super.customizeConfiguration(); - Map newAttributes = new HashMap(); - newAttributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.HTTP)); - newAttributes.put(Port.TRANSPORTS, Arrays.asList(Transport.SSL, Transport.TCP)); - newAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); - getBrokerConfiguration().setObjectAttributes(Port.class,TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT,newAttributes); - getBrokerConfiguration().setObjectAttribute(AuthenticationProvider.class, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, - "secureOnlyMechanisms", - "[\"PLAIN\"]"); - - } - - public void testGetWithHttps() throws Exception - { - Collection results = getMechanisms(true); - assertTrue("mechanisms did not contain PLAIN: " + results, results.contains("PLAIN")); - } - - - public void testGetWithHttp() throws Exception - { - Collection results = getMechanisms(false); - assertFalse("mechanisms incorrectly contain PLAIN: " + results, results.contains("PLAIN")); - } - - - private Collection getMechanisms(final boolean useSsl) throws IOException - { - getRestTestHelper().setUseSsl(useSsl); - Map mechanisms = getRestTestHelper().getJsonAsMap("/service/sasl"); - return (Collection) mechanisms.get("mechanisms"); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpsClientCertAuthTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpsClientCertAuthTest.java deleted file mode 100644 index 5b8d919d3e..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpsClientCertAuthTest.java +++ /dev/null @@ -1,86 +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.systest.rest; - -import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE; -import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE_PASSWORD; -import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE; -import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD; - -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.Protocol; -import org.apache.qpid.server.model.Transport; -import org.apache.qpid.server.security.auth.manager.ExternalAuthenticationManager; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class BrokerRestHttpsClientCertAuthTest extends QpidRestTestCase -{ - - @Override - public void setUp() throws Exception - { - setSystemProperty("javax.net.debug", "ssl"); - super.setUp(); - setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); - setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); - setSystemProperty("javax.net.ssl.keystore", KEYSTORE); - setSystemProperty("javax.net.ssl.keyStorePassword", KEYSTORE_PASSWORD); - - } - - @Override - protected void customizeConfiguration() throws IOException - { - super.customizeConfiguration(); - getRestTestHelper().setUseSslAuth(true); - Map newAttributes = new HashMap(); - newAttributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.HTTP)); - newAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); - newAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); - newAttributes.put(Port.TRUST_STORES, Collections.singleton(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE)); - newAttributes.put(Port.NEED_CLIENT_AUTH,"true"); - - - Map externalProviderAttributes = new HashMap(); - externalProviderAttributes.put(AuthenticationProvider.TYPE, ExternalAuthenticationManager.PROVIDER_TYPE); - externalProviderAttributes.put(AuthenticationProvider.NAME, EXTERNAL_AUTHENTICATION_PROVIDER); - getBrokerConfiguration().addObjectConfiguration(AuthenticationProvider.class, externalProviderAttributes); - - // set password authentication provider on http port for the tests - getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER, - EXTERNAL_AUTHENTICATION_PROVIDER); - - getBrokerConfiguration().setObjectAttributes(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, newAttributes); - } - - public void testGetWithHttps() throws Exception - { - Map saslData = getRestTestHelper().getJsonAsMap("/service/sasl"); - - Asserts.assertAttributesPresent(saslData, "user"); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java deleted file mode 100644 index 319cc1c9da..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java +++ /dev/null @@ -1,77 +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.systest.rest; - -import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE; -import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD; - -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.BrokerModel; -import org.apache.qpid.server.model.ConfiguredObject; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.Protocol; -import org.apache.qpid.server.model.Transport; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class BrokerRestHttpsTest extends QpidRestTestCase -{ - @Override - public void setUp() throws Exception - { - setSystemProperty("javax.net.debug", "ssl"); - super.setUp(); - setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); - setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); - } - - @Override - protected void customizeConfiguration() throws IOException - { - super.customizeConfiguration(); - getRestTestHelper().setUseSsl(true); - Map newAttributes = new HashMap(); - newAttributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.HTTP)); - newAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); - newAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); - getBrokerConfiguration().setObjectAttributes(Port.class,TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT,newAttributes); - } - - public void testGetWithHttps() throws Exception - { - Map brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker"); - - Asserts.assertAttributesPresent(brokerDetails, BrokerModel.getInstance().getTypeRegistry().getAttributeNames(Broker.class), - Broker.PROCESS_PID, - ConfiguredObject.TYPE, - ConfiguredObject.CREATED_BY, - ConfiguredObject.CREATED_TIME, - ConfiguredObject.LAST_UPDATED_BY, - ConfiguredObject.LAST_UPDATED_TIME, - ConfiguredObject.DESCRIPTION, - ConfiguredObject.CONTEXT, - ConfiguredObject.DESIRED_STATE); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestTest.java deleted file mode 100644 index bae27b802c..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestTest.java +++ /dev/null @@ -1,242 +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.systest.rest; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; - -import javax.jms.Connection; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.TextMessage; - -import org.apache.qpid.common.QpidProperties; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.BrokerModel; -import org.apache.qpid.server.model.ConfiguredObject; -import org.apache.qpid.server.model.LifetimePolicy; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.model.VirtualHostNode; -import org.apache.qpid.test.client.UnroutableMessageTestExceptionListener; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.util.SystemUtils; - -public class BrokerRestTest extends QpidRestTestCase -{ - private static final String BROKER_AUTHENTICATIONPROVIDERS_ATTRIBUTE = "authenticationproviders"; - private static final String BROKER_PORTS_ATTRIBUTE = "ports"; - private static final String BROKER_VIRTUALHOST_NODES_ATTRIBUTE = "virtualhostnodes"; - private static final String BROKER_STATISTICS_ATTRIBUTE = "statistics"; - - public void testGet() throws Exception - { - Map brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker"); - - assertBrokerAttributes(brokerDetails); - - @SuppressWarnings("unchecked") - Map statistics = (Map) brokerDetails.get(BROKER_STATISTICS_ATTRIBUTE); - Asserts.assertAttributesPresent(statistics, new String[]{ "bytesIn", "messagesOut", "bytesOut", "messagesIn" }); - - @SuppressWarnings("unchecked") - List> nodes = (List>) brokerDetails.get(BROKER_VIRTUALHOST_NODES_ATTRIBUTE); - assertEquals("Unexpected number of virtual hosts", 3, nodes.size()); - - for (String nodeName: EXPECTED_VIRTUALHOSTS) - { - Map nodeAttributes = getRestTestHelper().find(VirtualHostNode.NAME, nodeName, nodes); - assertNotNull("Node attributes are not found for node with name " + nodeName, nodeAttributes); - } - - @SuppressWarnings("unchecked") - List> ports = (List>) brokerDetails.get(BROKER_PORTS_ATTRIBUTE); - assertEquals("Unexpected number of ports", 2, ports.size()); - - for (Map port : ports) - { - Asserts.assertPortAttributes(port); - } - - Map amqpPort = getRestTestHelper().find(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT, ports); - Map httpPort = getRestTestHelper().find(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, ports); - - assertEquals("Unexpected binding address", "*", amqpPort.get(Port.BINDING_ADDRESS)); - assertNotNull("Cannot find AMQP port", amqpPort); - assertNotNull("Cannot find HTTP port", httpPort); - - @SuppressWarnings("unchecked") - Collection port1Protocols = (Collection) amqpPort.get(Port.PROTOCOLS); - assertFalse("AMQP protocol list cannot contain HTTP", port1Protocols != null && port1Protocols.contains("HTTP")); - - @SuppressWarnings("unchecked") - Collection port2Protocols = (Collection) httpPort.get(Port.PROTOCOLS); - assertEquals("Unexpected value of attribute " + Port.PROTOCOLS, new HashSet(Arrays.asList("HTTP")), - new HashSet(port2Protocols)); - } - - public void testPutToUpdateWithValidAttributeValues() throws Exception - { - Map brokerAttributes = getValidBrokerAttributes(); - - int response = getRestTestHelper().submitRequest("broker", "PUT", brokerAttributes); - assertEquals("Unexpected update response", 200, response); - - restartBroker(); - Map brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker"); - assertBrokerAttributes(brokerAttributes, brokerDetails); - } - - public void testPutUpdateWhereNumericAttributesAreSetAsStringValues() throws Exception - { - Map validAttributes = getValidBrokerAttributes(); - Map attributes = new HashMap(); - - for (Map.Entry entry : validAttributes.entrySet()) - { - Object value = entry.getValue(); - if (value instanceof Number) - { - value = String.valueOf(value); - } - attributes.put(entry.getKey(), value); - } - - int response = getRestTestHelper().submitRequest("broker", "PUT", attributes); - assertEquals("Unexpected update response", 200, response); - - Map brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker"); - assertBrokerAttributes(validAttributes, brokerDetails); - } - - public void testPutToUpdateWithInvalidAttributeValues() throws Exception - { - Map invalidAttributes = new HashMap(); - invalidAttributes.put(Broker.DEFAULT_VIRTUAL_HOST, "non-existing-host"); - invalidAttributes.put(Broker.CONNECTION_SESSION_COUNT_LIMIT, -10); - invalidAttributes.put(Broker.CONNECTION_HEART_BEAT_DELAY, -11000); - invalidAttributes.put(Broker.STATISTICS_REPORTING_PERIOD, -12000); - - for (Map.Entry entry : invalidAttributes.entrySet()) - { - Map brokerAttributes = getValidBrokerAttributes(); - brokerAttributes.put(entry.getKey(), entry.getValue()); - int response = getRestTestHelper().submitRequest("broker", "PUT", brokerAttributes); - assertEquals("Unexpected update response for invalid attribute " + entry.getKey() + "=" + entry.getValue(), 409, response); - } - - } - - public void testSetCloseOnNoRoute() throws Exception - { - Map brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker"); - assertTrue("closeOnNoRoute should be true", (Boolean)brokerDetails.get(Broker.CONNECTION_CLOSE_WHEN_NO_ROUTE)); - - Map brokerAttributes = new HashMap(); - brokerAttributes.put(Broker.CONNECTION_CLOSE_WHEN_NO_ROUTE, false); - - int response = getRestTestHelper().submitRequest("broker", "PUT", brokerAttributes); - assertEquals("Unexpected update response", 200, response); - - brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker"); - assertFalse("closeOnNoRoute should be false", (Boolean)brokerDetails.get(Broker.CONNECTION_CLOSE_WHEN_NO_ROUTE)); - - Connection connection = getConnection(); - UnroutableMessageTestExceptionListener exceptionListener = new UnroutableMessageTestExceptionListener(); - connection.setExceptionListener(exceptionListener); - Session session = connection.createSession(true, Session.SESSION_TRANSACTED); - MessageProducer producer = session.createProducer(getTestQueue()); - TextMessage message = session.createTextMessage("Test"); - producer.send(message); - - session.commit(); - - exceptionListener.assertReceivedNoRouteWithReturnedMessage(message, getTestQueueName()); - } - - private Map getValidBrokerAttributes() - { - Map brokerAttributes = new HashMap(); - brokerAttributes.put(Broker.DEFAULT_VIRTUAL_HOST, TEST3_VIRTUALHOST); - brokerAttributes.put(Broker.CONNECTION_SESSION_COUNT_LIMIT, 10); - brokerAttributes.put(Broker.CONNECTION_HEART_BEAT_DELAY, 11000); - brokerAttributes.put(Broker.STATISTICS_REPORTING_PERIOD, 12000); - brokerAttributes.put(Broker.STATISTICS_REPORTING_RESET_ENABLED, true); - return brokerAttributes; - } - - private void assertBrokerAttributes(Map expectedAttributes, Map actualAttributes) - { - for (Map.Entry entry : expectedAttributes.entrySet()) - { - String attributeName = entry.getKey(); - Object attributeValue = entry.getValue(); - - Object currentValue = actualAttributes.get(attributeName); - assertEquals("Unexpected attribute " + attributeName + " value:", attributeValue, currentValue); - } - } - - protected void assertBrokerAttributes(Map brokerDetails) - { - Asserts.assertAttributesPresent(brokerDetails, BrokerModel.getInstance().getTypeRegistry().getAttributeNames( - Broker.class), - Broker.PROCESS_PID, - ConfiguredObject.TYPE, - ConfiguredObject.CREATED_BY, - ConfiguredObject.CREATED_TIME, - ConfiguredObject.LAST_UPDATED_BY, - ConfiguredObject.LAST_UPDATED_TIME, - ConfiguredObject.DESCRIPTION, - ConfiguredObject.CONTEXT, - ConfiguredObject.DESIRED_STATE); - - assertEquals("Unexpected value of attribute " + Broker.BUILD_VERSION, QpidProperties.getBuildVersion(), - brokerDetails.get(Broker.BUILD_VERSION)); - assertEquals("Unexpected value of attribute " + Broker.OPERATING_SYSTEM, SystemUtils.getOSString(), - brokerDetails.get(Broker.OPERATING_SYSTEM)); - assertEquals( - "Unexpected value of attribute " + Broker.PLATFORM, - System.getProperty("java.vendor") + " " - + System.getProperty("java.runtime.version", System.getProperty("java.version")), - brokerDetails.get(Broker.PLATFORM)); - assertEquals("Unexpected value of attribute " + Broker.DURABLE, Boolean.TRUE, brokerDetails.get(Broker.DURABLE)); - assertEquals("Unexpected value of attribute " + Broker.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(), - brokerDetails.get(Broker.LIFETIME_POLICY)); - assertEquals("Unexpected value of attribute " + Broker.NAME, "Broker", brokerDetails.get(Broker.NAME)); - assertEquals("Unexpected value of attribute " + Broker.STATE, State.ACTIVE.name(), brokerDetails.get(Broker.STATE)); - - assertNotNull("Unexpected value of attribute " + Broker.ID, brokerDetails.get(Broker.ID)); - assertNotNull("Unexpected value of attribute statistics", brokerDetails.get(BROKER_STATISTICS_ATTRIBUTE)); - assertNotNull("Unexpected value of attribute virtual host nodes", brokerDetails.get(BROKER_VIRTUALHOST_NODES_ATTRIBUTE)); - assertNotNull("Unexpected value of attribute ports", brokerDetails.get(BROKER_PORTS_ATTRIBUTE)); - assertNotNull("Unexpected value of attribute authenticationproviders", brokerDetails.get(BROKER_AUTHENTICATIONPROVIDERS_ATTRIBUTE)); - - assertNotNull("Unexpected value of attribute supportedVirtualHostTypes", brokerDetails.get(Broker.SUPPORTED_VIRTUALHOST_TYPES)); - assertNotNull("Unexpected value of attribute supportedVirtualHostNodeTypes", brokerDetails.get(Broker.SUPPORTED_VIRTUALHOSTNODE_TYPES)); - - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/ConnectionRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/ConnectionRestTest.java deleted file mode 100644 index 439e592a7e..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/ConnectionRestTest.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.systest.rest; - -import java.io.IOException; -import java.net.URLDecoder; -import java.util.List; -import java.util.Map; - -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.servlet.http.HttpServletResponse; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.server.model.BrokerModel; -import org.apache.qpid.server.model.ConfiguredObject; -import org.apache.qpid.server.model.Connection; -import org.apache.qpid.server.model.Session; - -public class ConnectionRestTest extends QpidRestTestCase -{ - /** - * Message number to publish into queue - */ - private static final int MESSAGE_NUMBER = 5; - private static final int MESSAGE_SIZE = 6; - - private static final String SESSIONS_ATTRIBUTE = "sessions"; - - private javax.jms.Connection _connection; - private javax.jms.Session _session; - - public void setUp() throws Exception - { - super.setUp(); - - _connection = getConnection(); - _session = _connection.createSession(true, javax.jms.Session.SESSION_TRANSACTED); - String queueName = getTestQueueName(); - Destination queue = _session.createQueue(queueName); - MessageConsumer consumer = _session.createConsumer(queue); - MessageProducer producer = _session.createProducer(queue); - _connection.start(); - - // send messages - for (int i = 0; i < MESSAGE_NUMBER; i++) - { - producer.send(_session.createTextMessage("Test-" + i)); - } - _session.commit(); - Message m = consumer.receive(1000l); - assertNotNull("First message was not received", m); - _session.commit(); - - // receive the rest of messages for rollback - for (int i = 0; i < MESSAGE_NUMBER - 1; i++) - { - m = consumer.receive(1000l); - assertNotNull("Subsequent messages were not received", m); - } - _session.rollback(); - - // receive them again - for (int i = 0; i < MESSAGE_NUMBER - 1; i++) - { - m = consumer.receive(1000l); - assertNotNull("Message was not received after rollback", m); - } - - // Session left open - } - - public void testGetAllConnections() throws Exception - { - List> connections = getRestTestHelper().getJsonAsList("connection"); - assertEquals("Unexpected number of connections", 1, connections.size()); - Asserts.assertConnection(connections.get(0), (AMQConnection) _connection); - } - - public void testGetVirtualHostConnections() throws Exception - { - List> connections = getRestTestHelper().getJsonAsList("connection/test/test"); - assertEquals("Unexpected number of connections", 1, connections.size()); - Asserts.assertConnection(connections.get(0), (AMQConnection) _connection); - } - - public void testGetConnectionByName() throws Exception - { - // get connection name - String connectionName = getConnectionName(); - - Map connectionDetails = getRestTestHelper().getJsonAsSingletonList("connection/test/test/" - + URLDecoder.decode(connectionName, "UTF-8")); - assertConnection(connectionDetails); - } - - public void testDeleteConnection() throws Exception - { - // get connection name - String connectionName = getConnectionName(); - - List> connections = getRestTestHelper().getJsonAsList("connection/test/test"); - assertEquals("Unexpected number of connections before deletion", 1, connections.size()); - - String connectionUrl = "connection/test/test/" + URLDecoder.decode(connectionName, "UTF-8"); - getRestTestHelper().submitRequest(connectionUrl, "DELETE", HttpServletResponse.SC_OK); - - connections = getRestTestHelper().getJsonAsList("connection/test/test"); - assertEquals("Unexpected number of connections before deletion", 0, connections.size()); - - try - { - _connection.createSession(true, javax.jms.Session.SESSION_TRANSACTED); - fail("Exception not thrown"); - } - catch (JMSException je) - { - // PASS - } - } - - public void testGetAllSessions() throws Exception - { - List> sessions = getRestTestHelper().getJsonAsList("session"); - assertEquals("Unexpected number of sessions", 1, sessions.size()); - assertSession(sessions.get(0), (AMQSession) _session); - } - - public void testGetVirtualHostSessions() throws Exception - { - List> sessions = getRestTestHelper().getJsonAsList("session/test/test"); - assertEquals("Unexpected number of sessions", 1, sessions.size()); - assertSession(sessions.get(0), (AMQSession) _session); - } - - public void testGetConnectionSessions() throws Exception - { - // get connection name - String connectionName = getConnectionName(); - - List> sessions = getRestTestHelper().getJsonAsList("session/test/test/" - + URLDecoder.decode(connectionName, "UTF-8")); - assertEquals("Unexpected number of sessions", 1, sessions.size()); - assertSession(sessions.get(0), (AMQSession) _session); - } - - public void testGetSessionByName() throws Exception - { - // get connection name - String connectionName = getConnectionName(); - - List> sessions = getRestTestHelper().getJsonAsList("session/test/test/" - + URLDecoder.decode(connectionName, "UTF-8") + "/" + ((AMQSession) _session).getChannelId()); - assertEquals("Unexpected number of sessions", 1, sessions.size()); - assertSession(sessions.get(0), (AMQSession) _session); - } - - public void testProducerSessionOpenHasTransactionStartAndUpdateTimes() throws Exception - { - Destination queue = _session.createQueue(getTestQueueName()); - MessageProducer producer = _session.createProducer(queue); - producer.send(_session.createMessage()); - // session left open - ((AMQSession)_session).sync(); - String connectionName = getConnectionName(); - - List> sessions = getRestTestHelper().getJsonAsList("session/test/test/" - + URLDecoder.decode(connectionName, "UTF-8") + "/" + ((AMQSession) _session).getChannelId()); - assertEquals("Unexpected number of sessions", 1, sessions.size()); - - final Map sessionData = sessions.get(0); - - @SuppressWarnings("unchecked") - Map statistics = (Map) sessionData.get(Asserts.STATISTICS_ATTRIBUTE); - - long transactionStartTime = ((Number) statistics.get("transactionStartTime")).longValue(); - long transactionUpdateTime = ((Number) statistics.get("transactionUpdateTime")).longValue(); - - assertTrue("Unexpected transaction start value for open transaction " + transactionStartTime, transactionStartTime > 0); - assertTrue("Unexpected transaction update value for open transaction " + transactionUpdateTime, transactionUpdateTime > 0); - assertTrue("Expected transaction update value " + transactionUpdateTime + " to be greater than transaction start time " + transactionStartTime, transactionUpdateTime >= transactionStartTime); - - - } - - private void assertConnection(Map connectionDetails) throws JMSException - { - Asserts.assertConnection(connectionDetails, (AMQConnection) _connection); - - @SuppressWarnings("unchecked") - Map statistics = (Map) connectionDetails.get(Asserts.STATISTICS_ATTRIBUTE); - assertEquals("Unexpected value of connection statistics attribute " + "bytesIn", MESSAGE_NUMBER - * MESSAGE_SIZE, statistics.get("bytesIn")); - assertEquals("Unexpected value of connection statistics attribute " + "bytesOut", MESSAGE_SIZE - + ((MESSAGE_NUMBER - 1) * MESSAGE_SIZE) * 2, statistics.get("bytesOut")); - assertEquals("Unexpected value of connection statistics attribute " + "messagesIn", MESSAGE_NUMBER, - statistics.get("messagesIn")); - assertEquals("Unexpected value of connection statistics attribute " + "messagesOut", - MESSAGE_NUMBER * 2 - 1, statistics.get("messagesOut")); - - @SuppressWarnings("unchecked") - List> sessions = (List>) connectionDetails.get(SESSIONS_ATTRIBUTE); - assertNotNull("Sessions cannot be found", sessions); - assertEquals("Unexpected number of sessions", 1, sessions.size()); - assertSession(sessions.get(0), (AMQSession) _session); - } - - private void assertSession(Map sessionData, AMQSession session) - { - assertNotNull("Session map cannot be null", sessionData); - Asserts.assertAttributesPresent(sessionData, BrokerModel.getInstance().getTypeRegistry().getAttributeNames( - Session.class), - ConfiguredObject.TYPE, - ConfiguredObject.CREATED_BY, - ConfiguredObject.CREATED_TIME, - ConfiguredObject.LAST_UPDATED_BY, - ConfiguredObject.LAST_UPDATED_TIME, - ConfiguredObject.DESCRIPTION, - ConfiguredObject.CONTEXT, - ConfiguredObject.DESIRED_STATE, - Session.STATE, - Session.DURABLE, - Session.LIFETIME_POLICY); - assertEquals("Unexpected value of attribute " + Session.NAME, session.getChannelId() + "", - sessionData.get(Session.NAME)); - assertEquals("Unexpected value of attribute " + Session.PRODUCER_FLOW_BLOCKED, Boolean.FALSE, - sessionData.get(Session.PRODUCER_FLOW_BLOCKED)); - assertEquals("Unexpected value of attribute " + Session.CHANNEL_ID, session.getChannelId(), - sessionData.get(Session.CHANNEL_ID)); - - @SuppressWarnings("unchecked") - Map statistics = (Map) sessionData.get(Asserts.STATISTICS_ATTRIBUTE); - Asserts.assertAttributesPresent(statistics, "consumerCount", - "localTransactionBegins", "localTransactionOpen", - "localTransactionRollbacks", "unacknowledgedMessages", - "transactionStartTime", "transactionUpdateTime"); - - assertEquals("Unexpected value of statistic attribute " + "unacknowledgedMessages", MESSAGE_NUMBER - 1, - statistics.get("unacknowledgedMessages")); - assertEquals("Unexpected value of statistic attribute " + "localTransactionBegins", 4, - statistics.get("localTransactionBegins")); - assertEquals("Unexpected value of statistic attribute " + "localTransactionRollbacks", 1, - statistics.get("localTransactionRollbacks")); - assertEquals("Unexpected value of statistic attribute " + "consumerCount", 1, - statistics.get("consumerCount")); - } - - private String getConnectionName() throws IOException - { - Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test/test"); - @SuppressWarnings("unchecked") - List> connections = (List>) hostDetails - .get(VirtualHostRestTest.VIRTUALHOST_CONNECTIONS_ATTRIBUTE); - assertEquals("Unexpected number of connections", 1, connections.size()); - Map connection = connections.get(0); - String connectionName = (String) connection.get(Connection.NAME); - return connectionName; - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/ExchangeRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/ExchangeRestTest.java deleted file mode 100644 index 51cb6dde1a..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/ExchangeRestTest.java +++ /dev/null @@ -1,120 +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.systest.rest; - -import java.net.URLDecoder; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.qpid.server.model.Binding; -import org.apache.qpid.server.model.Exchange; - -public class ExchangeRestTest extends QpidRestTestCase -{ - @Override - public void setUp() throws Exception - { - super.setUp(); - getRestTestHelper().createTestQueues(); - } - - public void testGet() throws Exception - { - List> exchanges = getRestTestHelper().getJsonAsList("exchange"); - assertNotNull("Exchanges cannot be null", exchanges); - assertTrue("Unexpected number of exchanges", exchanges.size() >= EXPECTED_VIRTUALHOSTS.length * EXPECTED_EXCHANGES.length); - for (Map exchange : exchanges) - { - Asserts.assertExchange((String) exchange.get(Exchange.NAME), (String) exchange.get(Exchange.TYPE), exchange); - } - } - - public void testGetHostExchanges() throws Exception - { - List> exchanges = getRestTestHelper().getJsonAsList("exchange/test"); - assertNotNull("Users cannot be null", exchanges); - assertEquals("Unexpected number of exchanges", exchanges.size(), EXPECTED_EXCHANGES.length); - for (String exchangeName : EXPECTED_EXCHANGES) - { - Map exchange = getRestTestHelper().find(Exchange.NAME, exchangeName, exchanges); - assertExchange(exchangeName, exchange); - } - } - - public void testGetHostExchangeByName() throws Exception - { - for (String exchangeName : EXPECTED_EXCHANGES) - { - Map exchange = getRestTestHelper().getJsonAsSingletonList("exchange/test/test/" - + URLDecoder.decode(exchangeName, "UTF-8")); - assertExchange(exchangeName, exchange); - } - } - - public void testSetExchangeSupported() throws Exception - { - String exchangeName = getTestName(); - String exchangeUrl = "exchange/test/test/" + exchangeName; - - Map attributes = new HashMap(); - attributes.put(Exchange.NAME, exchangeName); - attributes.put(Exchange.TYPE, "direct"); - int responseCode = getRestTestHelper().submitRequest(exchangeUrl, "PUT", attributes); - assertEquals("Exchange should be created", 201, responseCode); - - Map exchange = getRestTestHelper().getJsonAsSingletonList(exchangeUrl); - assertNotNull("Exchange not found", exchange); - - attributes = new HashMap(); - attributes.put(Exchange.NAME, exchangeName); - attributes.put(Exchange.ALTERNATE_EXCHANGE, "amq.direct"); - - responseCode = getRestTestHelper().submitRequest(exchangeUrl, "PUT", attributes); - assertEquals("Exchange update should be supported", 200, responseCode); - exchange = getRestTestHelper().getJsonAsSingletonList(exchangeUrl); - assertNotNull("Exchange not found", exchange); - assertEquals("amq.direct",exchange.get(Exchange.ALTERNATE_EXCHANGE)); - } - - private void assertExchange(String exchangeName, Map exchange) - { - assertNotNull("Exchange with name " + exchangeName + " is not found", exchange); - String type = (String) exchange.get(Exchange.TYPE); - Asserts.assertExchange(exchangeName, type, exchange); - if ("direct".equals(type)) - { - assertBindings(exchange); - } - } - - private void assertBindings(Map exchange) - { - @SuppressWarnings("unchecked") - List> bindings = (List>) exchange.get("bindings"); - for (String queueName : RestTestHelper.EXPECTED_QUEUES) - { - Map binding = getRestTestHelper().find(Binding.NAME, queueName, bindings); - Asserts.assertBinding(queueName, (String) exchange.get(Exchange.NAME), binding); - } - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java deleted file mode 100644 index 4f1c1ad7a7..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java +++ /dev/null @@ -1,373 +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.systest.rest; - -import java.io.File; -import java.io.FileOutputStream; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.UUID; - -import org.apache.qpid.server.BrokerOptions; -import org.apache.qpid.server.model.BrokerModel; -import org.apache.qpid.server.model.ConfiguredObject; -import org.apache.qpid.server.model.Group; -import org.apache.qpid.server.model.GroupProvider; -import org.apache.qpid.server.model.LifetimePolicy; -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.model.adapter.FileBasedGroupProvider; -import org.apache.qpid.server.model.adapter.FileBasedGroupProviderImpl; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.test.utils.TestFileUtils; - -public class GroupProviderRestTest extends QpidRestTestCase -{ - private static final String FILE_GROUP_MANAGER = TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE; - private File _groupFile; - - @Override - public void setUp() throws Exception - { - _groupFile = createTemporaryGroupFile(); - - getBrokerConfiguration().addGroupFileConfiguration(_groupFile.getAbsolutePath()); - - super.setUp(); - } - - @Override - public void tearDown() throws Exception - { - super.tearDown(); - - if (_groupFile != null) - { - if (_groupFile.exists()) - { - _groupFile.delete(); - } - } - } - - public void testGet() throws Exception - { - List> providerDetails = getRestTestHelper().getJsonAsList("groupprovider"); - assertNotNull("Providers details cannot be null", providerDetails); - assertEquals("Unexpected number of providers", 1, providerDetails.size()); - for (Map provider : providerDetails) - { - assertProvider(FILE_GROUP_MANAGER, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE, provider); - Map data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" - + provider.get(GroupProvider.NAME)); - assertNotNull("Cannot load data for " + provider.get(GroupProvider.NAME), data); - assertProvider(FILE_GROUP_MANAGER, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE, data); - } - } - - public void testCreateNewGroup() throws Exception - { - String groupName = "newGroup"; - - Map data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); - assertNotNull("Cannot load data for provider", data); - - getRestTestHelper().assertNumberOfGroups(data, 1); - - getRestTestHelper().createGroup(groupName, FILE_GROUP_MANAGER); - - data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); - assertNotNull("Cannot load data for provider", data); - - getRestTestHelper().assertNumberOfGroups(data, 2); - } - - public void testRemoveGroup() throws Exception - { - String groupName = "myGroup"; - - Map data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); - assertNotNull("Cannot load data for provider", data); - - getRestTestHelper().assertNumberOfGroups(data, 1); - - getRestTestHelper().removeGroup(groupName, FILE_GROUP_MANAGER); - - data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); - assertNotNull("Cannot load data for provider", data); - - getRestTestHelper().assertNumberOfGroups(data, 0); - } - - public void testCreateNewFileGroupProviderFromExistingGroupFile() throws Exception - { - String[] groupMemberNames = {"test1","test2"}; - File groupFile = TestFileUtils.createTempFile(this, ".groups", "testusers.users=" + groupMemberNames[0] + "," + groupMemberNames[1]); - try - { - String providerName = getTestName(); - Map attributes = new HashMap(); - attributes.put(GroupProvider.NAME, providerName); - attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); - attributes.put(FileBasedGroupProvider.PATH, groupFile.getAbsolutePath()); - - int responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes); - assertEquals("Group provider was not created", 201, responseCode); - - Map data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + providerName + "?depth=2"); - assertProvider(providerName, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE, data); - assertEquals("Unexpected name", providerName, data.get(GroupProvider.NAME)); - assertEquals("Unexpected path", groupFile.getAbsolutePath(), data.get(FileBasedGroupProvider.PATH)); - - @SuppressWarnings("unchecked") - List> groups = (List>) data.get("groups"); - assertEquals("Unexpected group size", 1, groups.size()); - Map group = groups.get(0); - assertEquals("Unexpected group name", "testusers",group.get("name")); - - @SuppressWarnings("unchecked") - List> groupMemberList = (List>) group.get("groupmembers"); - assertEquals("Unexpected group members size", 2, groupMemberList.size()); - - for (String memberName : groupMemberNames) - { - boolean found = false; - for (Map memberData : groupMemberList) - { - Object name = memberData.get("name"); - if (memberName.equals(name)) - { - found = true; - break; - } - } - assertTrue("Cannot find group member " + memberName + " in " + groupMemberList , found); - } - } - finally - { - groupFile.delete(); - } - } - - public void testCreationOfNewFileGroupProviderFailsWhenPathIsMissed() throws Exception - { - String providerName = getTestName(); - Map attributes = new HashMap(); - attributes.put(GroupProvider.NAME, providerName); - attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); - - int responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes); - assertEquals("Group provider was created", 409, responseCode); - } - - public void testCreateNewFileGroupProviderFromNonExistingGroupFile() throws Exception - { - File groupFile = new File(TMP_FOLDER + File.separator + getTestName() + File.separator + "groups"); - assertFalse("Group file should not exist", groupFile.exists()); - try - { - String providerName = getTestName(); - Map attributes = new HashMap(); - attributes.put(GroupProvider.NAME, providerName); - attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); - attributes.put(FileBasedGroupProvider.PATH, groupFile.getAbsolutePath()); - - int responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes); - assertEquals("Group provider was not created", 201, responseCode); - - Map data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + providerName); - assertEquals("Unexpected name", providerName, data.get(GroupProvider.NAME)); - assertEquals("Unexpected path", groupFile.getAbsolutePath(), data.get(FileBasedGroupProvider.PATH)); - - @SuppressWarnings("unchecked") - List> groups = (List>) data.get("groups"); - assertNull("Unexpected groups", groups); - - assertTrue("Group file has not been created", groupFile.exists()); - } - finally - { - groupFile.delete(); - groupFile.getParentFile().delete(); - } - } - - public void testCreateNewFileGroupProviderForTheSameGroupFileFails() throws Exception - { - File groupFile = TestFileUtils.createTempFile(this, ".groups", "testusers.users=test1,test2"); - String providerName = getTestName(); - try - { - Map attributes = new HashMap(); - attributes.put(GroupProvider.NAME, providerName); - attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); - attributes.put(FileBasedGroupProvider.PATH, groupFile.getAbsolutePath()); - - int responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes); - assertEquals("Group provider was not created", 201, responseCode); - - attributes.put(GroupProvider.NAME, providerName + 2); - responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName + 2, "PUT", attributes); - assertEquals("Group provider for the same group file was created", 409, responseCode); - } - finally - { - groupFile.delete(); - } - } - - public void testDeleteGroupProvider() throws Exception - { - File groupFile = TestFileUtils.createTempFile(this, ".groups", "testusers.users=test1,test2"); - String providerName = getTestName(); - try - { - Map attributes = new HashMap(); - attributes.put(GroupProvider.NAME, providerName); - attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); - attributes.put(FileBasedGroupProvider.PATH, groupFile.getAbsolutePath()); - - int responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes); - assertEquals("Expected to fail because we can have only one password provider", 201, responseCode); - - responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName , "DELETE"); - assertEquals("Group provider was not deleted", 200, responseCode); - - List> providerDetails = getRestTestHelper().getJsonAsList("groupprovider/" + providerName); - assertEquals("Provider was not deleted", 0, providerDetails.size()); - assertFalse("Groups file should be deleted", groupFile.exists()); - } - finally - { - groupFile.delete(); - } - } - - public void testUpdateGroupProviderAttributesFails() throws Exception - { - File groupFile = TestFileUtils.createTempFile(this, ".groups", "testusers.users=test1,test2"); - String providerName = getTestName(); - try - { - Map attributes = new HashMap(); - attributes.put(GroupProvider.NAME, providerName); - attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); - attributes.put(FileBasedGroupProvider.PATH, groupFile.getAbsolutePath()); - - int responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes); - assertEquals("Expected to fail because we can have only one password provider", 201, responseCode); - - File newGroupFile = new File(TMP_FOLDER + File.separator + getTestName() + File.separator + "groups"); - attributes.put(FileBasedGroupProvider.PATH, newGroupFile.getAbsolutePath()); - - responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes); - assertEquals("Expected to fail because we can have only one password provider", 409, responseCode); - } - finally - { - groupFile.delete(); - } - } - - public void testRemovalOfGroupProviderInErrorStateUsingManagementMode() throws Exception - { - stopBroker(); - - File file = new File(TMP_FOLDER, getTestName()); - if (file.exists()) - { - file.delete(); - } - assertFalse("Group file should not exist", file.exists()); - - TestBrokerConfiguration config = getBrokerConfiguration(); - config.removeObjectConfiguration(GroupProvider.class, TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE); - UUID id = config.addGroupFileConfiguration(file.getAbsolutePath()); - config.setSaved(false); - startBroker(0, true); - - getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD); - - Map groupProvider = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE); - assertEquals("Unexpected id", id.toString(), groupProvider.get(GroupProvider.ID)); - assertEquals("Unexpected path", file.getAbsolutePath() , groupProvider.get(FileBasedGroupProvider.PATH)); - assertEquals("Unexpected state", State.ERRORED.name() , groupProvider.get(GroupProvider.STATE)); - - int status = getRestTestHelper().submitRequest("groupprovider/" + TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE, "DELETE"); - assertEquals("ACL was not deleted", 200, status); - - List> providers = getRestTestHelper().getJsonAsList("groupprovider/" + TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE); - assertEquals("Provider exists", 0, providers.size()); - } - - private void assertProvider(String name, String type, Map provider) - { - Asserts.assertAttributesPresent(provider, BrokerModel.getInstance().getTypeRegistry().getAttributeNames( - GroupProvider.class), - ConfiguredObject.TYPE, - ConfiguredObject.CREATED_BY, - ConfiguredObject.CREATED_TIME, - ConfiguredObject.LAST_UPDATED_BY, - ConfiguredObject.LAST_UPDATED_TIME, - ConfiguredObject.DESCRIPTION, - ConfiguredObject.CONTEXT, - ConfiguredObject.DESIRED_STATE); - assertEquals("Unexpected value of provider attribute " + GroupProvider.STATE, State.ACTIVE.name(), - provider.get(GroupProvider.STATE)); - assertEquals("Unexpected value of provider attribute " + GroupProvider.LIFETIME_POLICY, - LifetimePolicy.PERMANENT.name(), provider.get(GroupProvider.LIFETIME_POLICY)); - assertEquals("Unexpected value of provider attribute " + GroupProvider.DURABLE, Boolean.TRUE, - provider.get(GroupProvider.DURABLE)); - assertEquals("Unexpected value of provider attribute " + GroupProvider.TYPE, type, - provider.get(GroupProvider.TYPE)); - - assertEquals("Unexpected value of provider attribute " + GroupProvider.NAME, name, - (String) provider.get(GroupProvider.NAME)); - - @SuppressWarnings("unchecked") - List> groups = (List>) provider.get("groups"); - assertNotNull("Groups were not found", groups); - assertEquals("Unexpected number of groups", 1, groups.size()); - for (Map group : groups) - { - - final String groupName = (String) group.get(Group.NAME); - assertNotNull("Attribute " + Group.NAME, groupName); - - assertNotNull("Attribute " + Group.ID, group.get(Group.ID)); - } - } - - private File createTemporaryGroupFile() throws Exception - { - File groupFile = File.createTempFile("group", "grp"); - groupFile.deleteOnExit(); - - Properties props = new Properties(); - props.put("myGroup.users", "guest"); - - props.store(new FileOutputStream(groupFile), "test group file"); - - return groupFile; - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupRestTest.java deleted file mode 100644 index eeb9511289..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupRestTest.java +++ /dev/null @@ -1,109 +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.systest.rest; - -import java.io.File; -import java.io.FileOutputStream; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import org.apache.qpid.server.model.GroupMember; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class GroupRestTest extends QpidRestTestCase -{ - private static final String GROUP_NAME = "myGroup"; - private static final String FILE_GROUP_MANAGER = TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE; - private static final String EXISTING_MEMBER = "user1"; - private static final String NEW_MEMBER = "user2"; - - private File _groupFile; - - @Override - public void setUp() throws Exception - { - _groupFile = createTemporaryGroupFile(); - - getBrokerConfiguration().addGroupFileConfiguration(_groupFile.getAbsolutePath()); - - super.setUp(); - } - - @Override - public void tearDown() throws Exception - { - super.tearDown(); - - if (_groupFile != null) - { - if (_groupFile.exists()) - { - _groupFile.delete(); - } - } - } - - public void testGet() throws Exception - { - Map group = getRestTestHelper().getJsonAsSingletonList("group/" + FILE_GROUP_MANAGER + "/myGroup"); - List> groupmembers = (List>) group.get("groupmembers"); - assertEquals(1, groupmembers.size()); - - Map member1 = groupmembers.get(0); - assertEquals(EXISTING_MEMBER, (String)member1.get(GroupMember.NAME)); - } - - public void testCreateNewMemberOfGroup() throws Exception - { - Map group = getRestTestHelper().getJsonAsSingletonList("group/" + FILE_GROUP_MANAGER + "/myGroup"); - getRestTestHelper().assertNumberOfGroupMembers(group, 1); - - getRestTestHelper().createNewGroupMember(FILE_GROUP_MANAGER, GROUP_NAME, NEW_MEMBER); - - group = getRestTestHelper().getJsonAsSingletonList("group/" + FILE_GROUP_MANAGER + "/myGroup"); - getRestTestHelper().assertNumberOfGroupMembers(group, 2); - } - - public void testRemoveMemberFromGroup() throws Exception - { - Map group = getRestTestHelper().getJsonAsSingletonList("group/" + FILE_GROUP_MANAGER + "/myGroup"); - getRestTestHelper().assertNumberOfGroupMembers(group, 1); - - getRestTestHelper().removeMemberFromGroup(FILE_GROUP_MANAGER, GROUP_NAME, EXISTING_MEMBER); - - group = getRestTestHelper().getJsonAsSingletonList("group/" + FILE_GROUP_MANAGER + "/myGroup"); - getRestTestHelper().assertNumberOfGroupMembers(group, 0); - } - - private File createTemporaryGroupFile() throws Exception - { - File groupFile = File.createTempFile("group", "grp"); - groupFile.deleteOnExit(); - - Properties props = new Properties(); - props.put(GROUP_NAME + ".users", EXISTING_MEMBER); - - props.store(new FileOutputStream(groupFile), "test group file"); - - return groupFile; - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/HttpManagementRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/HttpManagementRestTest.java deleted file mode 100644 index abafb7fcaf..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/HttpManagementRestTest.java +++ /dev/null @@ -1,91 +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.systest.rest; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.qpid.server.management.plugin.HttpManagement; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class HttpManagementRestTest extends QpidRestTestCase -{ - - public void testGetHttpManagement() throws Exception - { - Map details = getRestTestHelper().getJsonAsSingletonList( - "plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT); - - assertEquals("Unexpected session timeout", HttpManagement.DEFAULT_TIMEOUT_IN_SECONDS, - details.get(HttpManagement.TIME_OUT)); - assertEquals("Unexpected http basic auth enabled", true, - details.get(HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED)); - assertEquals("Unexpected https basic auth enabled", true, - details.get(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED)); - assertEquals("Unexpected http sasl auth enabled", true, - details.get(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED)); - assertEquals("Unexpected https sasl auth enabled", true, - details.get(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED)); - } - - public void testUpdateAttributes() throws Exception - { - Map attributes = new HashMap(); - attributes.put(HttpManagement.NAME, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT); - attributes.put(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED, false); - attributes.put(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED, false); - attributes.put(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED, false); - attributes.put(HttpManagement.TIME_OUT, 10000); - - getRestTestHelper().submitRequest("plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, "PUT", attributes); - - Map details = getRestTestHelper().getJsonAsSingletonList( - "plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT); - - assertEquals("Unexpected session timeout", 10000, details.get(HttpManagement.TIME_OUT)); - assertEquals("Unexpected http basic auth enabled", true, details.get(HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED)); - assertEquals("Unexpected https basic auth enabled", false, details.get(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED)); - assertEquals("Unexpected http sasl auth enabled", false, details.get(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED)); - assertEquals("Unexpected https sasl auth enabled", false, details.get(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED)); - } - - public void testUpdateAttributesWithInvalidValues() throws Exception - { - Map invalidAttributes = new HashMap(); - invalidAttributes.put(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED, 1); - invalidAttributes.put(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED, 2); - invalidAttributes.put(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED, 3); - invalidAttributes.put(HttpManagement.TIME_OUT, "undefined"); - - for (Map.Entry invalidAttribute : invalidAttributes.entrySet()) - { - Map attributes = new HashMap(); - attributes.put(invalidAttribute.getKey(), invalidAttribute.getValue()); - int response = getRestTestHelper().submitRequest("plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, "PUT", attributes); - assertEquals("Update should fail for attribute " + invalidAttribute.getKey() + " with value " + invalidAttribute.getValue() , 409, response); - } - - Map attributes = new HashMap(); - attributes.put(HttpManagement.TIME_OUT, -1l); - int response = getRestTestHelper().submitRequest("plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, "PUT", attributes); - assertEquals("Update should fail for invalid session timeout", 409, response); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/KeyStoreRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/KeyStoreRestTest.java deleted file mode 100644 index 4b881d1e9f..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/KeyStoreRestTest.java +++ /dev/null @@ -1,272 +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.systest.rest; - -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.codehaus.jackson.JsonGenerationException; -import org.codehaus.jackson.JsonParseException; -import org.codehaus.jackson.map.JsonMappingException; - -import org.apache.qpid.server.model.AbstractConfiguredObject; -import org.apache.qpid.server.model.KeyStore; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.Transport; -import org.apache.qpid.server.security.FileKeyStore; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.test.utils.TestSSLConstants; - -public class KeyStoreRestTest extends QpidRestTestCase -{ - @Override - public void setUp() throws Exception - { - // not calling super.setUp() to avoid broker start-up until - // after any necessary configuration - } - - public void testGet() throws Exception - { - super.setUp(); - - //verify existence of the default keystore used by the systests - List> keyStores = assertNumberOfKeyStores(1); - - Map keystore = keyStores.get(0); - assertKeyStoreAttributes(keystore, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE, - System.getProperty(QPID_HOME) + "/../" + TestSSLConstants.BROKER_KEYSTORE, null); - } - - public void testCreate() throws Exception - { - super.setUp(); - - String name = getTestName(); - String certAlias = "app2"; - - assertNumberOfKeyStores(1); - createKeyStore(name, certAlias); - assertNumberOfKeyStores(2); - - List> keyStores = getRestTestHelper().getJsonAsList("keystore/" + name); - assertNotNull("details cannot be null", keyStores); - - assertKeyStoreAttributes(keyStores.get(0), name, TestSSLConstants.KEYSTORE, certAlias); - } - - public void testDelete() throws Exception - { - super.setUp(); - - String name = getTestName(); - String certAlias = "app2"; - - assertNumberOfKeyStores(1); - createKeyStore(name, certAlias); - assertNumberOfKeyStores(2); - - int responseCode = getRestTestHelper().submitRequest("keystore/" + name , "DELETE"); - assertEquals("Unexpected response code for provider deletion", 200, responseCode); - - List> keyStore = getRestTestHelper().getJsonAsList("keystore/" + name); - assertNotNull("details should not be null", keyStore); - assertTrue("details should be empty as the keystore no longer exists", keyStore.isEmpty()); - - //check only the default systests key store remains - List> keyStores = assertNumberOfKeyStores(1); - Map keystore = keyStores.get(0); - assertKeyStoreAttributes(keystore, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE, - System.getProperty(QPID_HOME) + "/../" + TestSSLConstants.BROKER_KEYSTORE, null); - } - - public void testDeleteFailsWhenKeyStoreInUse() throws Exception - { - String name = "testDeleteFailsWhenKeyStoreInUse"; - - //add a new key store config to use - Map sslKeyStoreAttributes = new HashMap(); - sslKeyStoreAttributes.put(KeyStore.NAME, name); - sslKeyStoreAttributes.put(FileKeyStore.PATH, TestSSLConstants.BROKER_KEYSTORE); - sslKeyStoreAttributes.put(FileKeyStore.PASSWORD, TestSSLConstants.BROKER_KEYSTORE_PASSWORD); - getBrokerConfiguration().addObjectConfiguration(KeyStore.class,sslKeyStoreAttributes); - - //add the SSL port using it - Map sslPortAttributes = new HashMap(); - sslPortAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); - sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT); - sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT); - sslPortAttributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); - sslPortAttributes.put(Port.KEY_STORE, name); - getBrokerConfiguration().addObjectConfiguration(Port.class,sslPortAttributes); - - super.setUp(); - - //verify the keystore is there - assertNumberOfKeyStores(2); - - List> keyStore = getRestTestHelper().getJsonAsList("keystore/" + name); - assertNotNull("details should not be null", keyStore); - assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.BROKER_KEYSTORE, null); - - //try to delete it, which should fail as it is in use - int responseCode = getRestTestHelper().submitRequest("keystore/" + name , "DELETE"); - assertEquals("Unexpected response code for provider deletion", 409, responseCode); - - //check its still there - assertNumberOfKeyStores(2); - keyStore = getRestTestHelper().getJsonAsList("keystore/" + name); - assertNotNull("details should not be null", keyStore); - assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.BROKER_KEYSTORE, null); - } - - public void testUpdateWithGoodPathSucceeds() throws Exception - { - super.setUp(); - - String name = getTestName(); - - assertNumberOfKeyStores(1); - createKeyStore(name, null); - assertNumberOfKeyStores(2); - - Map attributes = new HashMap(); - attributes.put(KeyStore.NAME, name); - attributes.put(FileKeyStore.PATH, TestSSLConstants.UNTRUSTED_KEYSTORE); - - int responseCode = getRestTestHelper().submitRequest("keystore/" + name , "PUT", attributes); - assertEquals("Unexpected response code for keystore update", 200, responseCode); - - List> keyStore = getRestTestHelper().getJsonAsList("keystore/" + name); - assertNotNull("details should not be null", keyStore); - - assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.UNTRUSTED_KEYSTORE, null); - } - - public void testUpdateWithNonExistentPathFails() throws Exception - { - super.setUp(); - - String name = getTestName(); - - assertNumberOfKeyStores(1); - createKeyStore(name, null); - assertNumberOfKeyStores(2); - - Map attributes = new HashMap(); - attributes.put(KeyStore.NAME, name); - attributes.put(FileKeyStore.PATH, "does.not.exist"); - - int responseCode = getRestTestHelper().submitRequest("keystore/" + name , "PUT", attributes); - assertEquals("Unexpected response code for keystore update", 409, responseCode); - - List> keyStore = getRestTestHelper().getJsonAsList("keystore/" + name); - assertNotNull("details should not be null", keyStore); - - //verify the details remain unchanged - assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.KEYSTORE, null); - } - - public void testUpdateCertificateAlias() throws Exception - { - super.setUp(); - - String name = getTestName(); - - assertNumberOfKeyStores(1); - createKeyStore(name, "app1"); - assertNumberOfKeyStores(2); - - List> keyStore = getRestTestHelper().getJsonAsList("keystore/" + name); - assertNotNull("details should not be null", keyStore); - assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.KEYSTORE, "app1"); - - //Update the certAlias from app1 to app2 - Map attributes = new HashMap(); - attributes.put(KeyStore.NAME, name); - attributes.put(FileKeyStore.CERTIFICATE_ALIAS, "app2"); - - int responseCode = getRestTestHelper().submitRequest("keystore/" + name , "PUT", attributes); - assertEquals("Unexpected response code for keystore update", 200, responseCode); - - keyStore = getRestTestHelper().getJsonAsList("keystore/" + name); - assertNotNull("details should not be null", keyStore); - - assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.KEYSTORE, "app2"); - - //Update the certAlias to clear it (i.e go from from app1 to null) - attributes = new HashMap(); - attributes.put(KeyStore.NAME, name); - attributes.put(FileKeyStore.CERTIFICATE_ALIAS, null); - - responseCode = getRestTestHelper().submitRequest("keystore/" + name , "PUT", attributes); - assertEquals("Unexpected response code for keystore update", 200, responseCode); - - keyStore = getRestTestHelper().getJsonAsList("keystore/" + name); - assertNotNull("details should not be null", keyStore); - - assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.KEYSTORE, null); - } - - private List> assertNumberOfKeyStores(int numberOfKeystores) throws IOException, - JsonParseException, JsonMappingException - { - List> keyStores = getRestTestHelper().getJsonAsList("keystore"); - assertNotNull("keystores should not be null", keyStores); - assertEquals("Unexpected number of keystores", numberOfKeystores, keyStores.size()); - - return keyStores; - } - - private void createKeyStore(String name, String certAlias) throws IOException, JsonGenerationException, JsonMappingException - { - Map keyStoreAttributes = new HashMap(); - keyStoreAttributes.put(KeyStore.NAME, name); - keyStoreAttributes.put(FileKeyStore.PATH, TestSSLConstants.KEYSTORE); - keyStoreAttributes.put(FileKeyStore.PASSWORD, TestSSLConstants.KEYSTORE_PASSWORD); - keyStoreAttributes.put(FileKeyStore.CERTIFICATE_ALIAS, certAlias); - - int responseCode = getRestTestHelper().submitRequest("keystore/" + name, "PUT", keyStoreAttributes); - assertEquals("Unexpected response code", 201, responseCode); - } - - private void assertKeyStoreAttributes(Map keystore, String name, String path, String certAlias) - { - assertEquals("default systests key store is missing", - name, keystore.get(KeyStore.NAME)); - assertEquals("unexpected path to key store", - path, keystore.get(FileKeyStore.PATH)); - assertEquals("unexpected (dummy) password of default systests key store", - AbstractConfiguredObject.SECURED_STRING_VALUE, keystore.get(FileKeyStore.PASSWORD)); - assertEquals("unexpected type of default systests key store", - java.security.KeyStore.getDefaultType(), keystore.get(FileKeyStore.KEY_STORE_TYPE)); - assertEquals("unexpected certificateAlias value", - certAlias, keystore.get(FileKeyStore.CERTIFICATE_ALIAS)); - if(certAlias == null) - { - assertFalse("should not be a certificateAlias attribute", - keystore.containsKey(FileKeyStore.CERTIFICATE_ALIAS)); - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/LogRecordsRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/LogRecordsRestTest.java deleted file mode 100644 index 4d06c7b624..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/LogRecordsRestTest.java +++ /dev/null @@ -1,63 +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.systest.rest; - -import java.util.List; -import java.util.Map; - -public class LogRecordsRestTest extends QpidRestTestCase -{ - public void testGet() throws Exception - { - List> logs = getRestTestHelper().getJsonAsList("/service/logrecords"); - assertNotNull("Logs data cannot be null", logs); - assertTrue("Logs are not found", logs.size() > 0); - Map record = getRestTestHelper().find("message", "[Broker] BRK-1004 : Qpid Broker Ready", logs); - - assertNotNull("BRK-1004 message is not found", record); - assertNotNull("Message id cannot be null", record.get("id")); - assertNotNull("Message timestamp cannot be null", record.get("timestamp")); - assertEquals("Unexpected log level", "INFO", record.get("level")); - assertEquals("Unexpected thread", "main", record.get("thread")); - assertEquals("Unexpected logger", "qpid.message.broker.ready", record.get("logger")); - } - - public void testGetLogsFromGivenId() throws Exception - { - List> logs = getRestTestHelper().getJsonAsList("/service/logrecords"); - assertNotNull("Logs data cannot be null", logs); - assertTrue("Logs are not found", logs.size() > 0); - - Map lastLog = logs.get(logs.size() -1); - Object lastId = lastLog.get("id"); - - //make sure that new logs are created - getConnection(); - - List> newLogs = getRestTestHelper().getJsonAsList("/service/logrecords?lastLogId=" + lastId); - assertNotNull("Logs data cannot be null", newLogs); - assertTrue("Logs are not found", newLogs.size() > 0); - - Object nextId = newLogs.get(0).get("id"); - - assertEquals("Unexpected next log id", ((Number)lastId).longValue() + 1, ((Number)nextId).longValue()); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/LogViewerTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/LogViewerTest.java deleted file mode 100644 index f2fb2581f7..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/LogViewerTest.java +++ /dev/null @@ -1,105 +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.systest.rest; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.util.List; -import java.util.Map; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -import org.apache.qpid.server.BrokerOptions; - -public class LogViewerTest extends QpidRestTestCase -{ - public static final String DEFAULT_FILE_APPENDER_NAME = "FileAppender"; - private String _expectedLogFileName; - - public void setUp() throws Exception - { - setSystemProperty("logsuffix", "-" + getTestQueueName()); - _expectedLogFileName = System.getProperty("logprefix", "") + "qpid" + System.getProperty("logsuffix", "") + ".log"; - - // use real broker log file - File brokerLogFile = new File(System.getProperty(QPID_HOME), BrokerOptions.DEFAULT_LOG_CONFIG_FILE); - setBrokerCommandLog4JFile(brokerLogFile); - - super.setUp(); - } - - public void testGetLogFiles() throws Exception - { - List> logFiles = getRestTestHelper().getJsonAsList("/service/logfilenames"); - assertNotNull("Log files data cannot be null", logFiles); - - // 1 file appender is configured in QPID default log4j xml: - assertTrue("Unexpected number of log files", logFiles.size() > 0); - - Map logFileDetails = logFiles.get(0); - assertEquals("Unexpected log file name", _expectedLogFileName, logFileDetails.get("name")); - assertEquals("Unexpected log file mime type", "text/plain", logFileDetails.get("mimeType")); - assertEquals("Unexpected log file appender",DEFAULT_FILE_APPENDER_NAME, logFileDetails.get("appenderName")); - assertTrue("Unexpected log file size", ((Number)logFileDetails.get("size")).longValue()>0); - assertTrue("Unexpected log file modification time", ((Number)logFileDetails.get("lastModified")).longValue()>0); - } - - public void testDownloadExistingLogFiles() throws Exception - { - byte[] bytes = getRestTestHelper().getBytes("/service/logfile?l=" + DEFAULT_FILE_APPENDER_NAME + "%2F" + _expectedLogFileName); - - ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(bytes)); - try - { - ZipEntry entry = zis.getNextEntry(); - assertEquals("Unexpected broker log file name", DEFAULT_FILE_APPENDER_NAME + "/" + _expectedLogFileName, entry.getName()); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] buffer = new byte[1024]; - int len; - while ((len = zis.read(buffer)) > 0) - { - baos.write(buffer, 0, len); - } - baos.close(); - assertTrue("Unexpected broker log file content", new String(baos.toByteArray()).contains("BRK-1004")); - assertNull("Unexpepected log file entry", zis.getNextEntry()); - } - finally - { - zis.close(); - } - } - - public void testDownloadNonExistingLogFiles() throws Exception - { - int responseCode = getRestTestHelper().submitRequest("/service/logfile?l=" + DEFAULT_FILE_APPENDER_NAME + "%2F" - + _expectedLogFileName + "_" + System.currentTimeMillis(), "GET"); - - assertEquals("Unexpected response code", 404, responseCode); - } - - public void testDownloadNonLogFiles() throws Exception - { - int responseCode = getRestTestHelper().submitRequest("/service/logfile?l=config.json", "GET"); - assertEquals("Unexpected response code", 400, responseCode); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/MessagesRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/MessagesRestTest.java deleted file mode 100644 index efa4776afd..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/MessagesRestTest.java +++ /dev/null @@ -1,355 +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.systest.rest; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import javax.jms.BytesMessage; -import javax.jms.Connection; -import javax.jms.DeliveryMode; -import javax.jms.Destination; -import javax.jms.Message; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.servlet.http.HttpServletResponse; - -import org.codehaus.jackson.map.JsonMappingException; - -public class MessagesRestTest extends QpidRestTestCase -{ - - /** - * Message number to publish into queue - */ - private static final int MESSAGE_NUMBER = 12; - - private Connection _connection; - private Session _session; - private MessageProducer _producer; - private long _startTime; - private long _ttl; - - public void setUp() throws Exception - { - super.setUp(); - _startTime = System.currentTimeMillis(); - _connection = getConnection(); - _session = _connection.createSession(true, Session.SESSION_TRANSACTED); - String queueName = getTestQueueName(); - Destination queue = _session.createQueue(queueName); - _session.createConsumer(queue).close(); - _producer = _session.createProducer(queue); - - _ttl = TimeUnit.DAYS.toMillis(1); - for (int i = 0; i < MESSAGE_NUMBER; i++) - { - Message m = _session.createTextMessage("Test-" + i); - m.setIntProperty("index", i); - if (i % 2 == 0) - { - _producer.send(m); - } - else - { - _producer.send(m, DeliveryMode.NON_PERSISTENT, 5, _ttl); - } - } - _session.commit(); - } - - public void testGet() throws Exception - { - String queueName = getTestQueueName(); - List> messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName); - assertNotNull("Messages are not found", messages); - assertEquals("Unexpected number of messages", MESSAGE_NUMBER, messages.size()); - int position = 0; - for (Map message : messages) - { - assertMessage(position, message); - position++; - } - } - - public void testGetMessageContent() throws Exception - { - String queueName = getTestQueueName(); - - // add bytes message - BytesMessage byteMessage = _session.createBytesMessage(); - byte[] messageBytes = "Test".getBytes(); - byteMessage.writeBytes(messageBytes); - byteMessage.setStringProperty("test", "value"); - _producer.send(byteMessage); - _session.commit(); - - // get message IDs - List ids = getMesssageIds(queueName); - - Map message = getRestTestHelper().getJsonAsMap("/service/message/test/" + queueName + "/" + ids.get(0)); - assertMessageAttributes(message); - assertMessageAttributeValues(message, true); - - @SuppressWarnings("unchecked") - Map headers = (Map) message.get("headers"); - assertNotNull("Message headers are not found", headers); - assertEquals("Unexpected message header", 0, headers.get("index")); - - Long lastMessageId = ids.get(ids.size() - 1); - message = getRestTestHelper().getJsonAsMap("/service/message/test/" + queueName + "/" + lastMessageId); - assertMessageAttributes(message); - assertEquals("Unexpected message attribute mimeType", "application/octet-stream", message.get("mimeType")); - assertEquals("Unexpected message attribute size", 4, message.get("size")); - - @SuppressWarnings("unchecked") - Map bytesMessageHeader = (Map) message.get("headers"); - assertNotNull("Message headers are not found", bytesMessageHeader); - assertEquals("Unexpected message header", "value", bytesMessageHeader.get("test")); - - // get content - byte[] data = getRestTestHelper().getBytes("/service/message-content/test/" + queueName + "/" + lastMessageId); - assertTrue("Unexpected message", Arrays.equals(messageBytes, data)); - - } - - public void testPostMoveMessages() throws Exception - { - String queueName = getTestQueueName(); - String queueName2 = queueName + "_2"; - Destination queue2 = _session.createQueue(queueName2); - _session.createConsumer(queue2); - - // get message IDs - List ids = getMesssageIds(queueName); - - // move half of the messages - int movedNumber = ids.size() / 2; - List movedMessageIds = new ArrayList(); - for (int i = 0; i < movedNumber; i++) - { - movedMessageIds.add(ids.remove(i)); - } - - // move messages - - Map messagesData = new HashMap(); - messagesData.put("messages", movedMessageIds); - messagesData.put("destinationQueue", queueName2); - messagesData.put("move", Boolean.TRUE); - - getRestTestHelper().submitRequest("/service/message/test/" + queueName, "POST", messagesData, HttpServletResponse.SC_OK); - - // check messages on target queue - List> messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName2); - assertNotNull("Messages are not found", messages); - assertEquals("Unexpected number of messages", movedMessageIds.size(), messages.size()); - for (Long id : movedMessageIds) - { - Map message = getRestTestHelper().find("id", id.intValue(), messages); - assertMessageAttributes(message); - } - - // check messages on original queue - messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName); - assertNotNull("Messages are not found", messages); - assertEquals("Unexpected number of messages", ids.size(), messages.size()); - for (Long id : ids) - { - Map message = getRestTestHelper().find("id", id.intValue(), messages); - assertMessageAttributes(message); - } - for (Long id : movedMessageIds) - { - Map message = getRestTestHelper().find("id", id.intValue(), messages); - assertNull("Moved message " + id + " is found on original queue", message); - } - } - - public void testPostCopyMessages() throws Exception - { - String queueName = getTestQueueName(); - String queueName2 = queueName + "_2"; - Destination queue2 = _session.createQueue(queueName2); - _session.createConsumer(queue2); - - // get message IDs - List ids = getMesssageIds(queueName); - - // copy half of the messages - int copyNumber = ids.size() / 2; - List copyMessageIds = new ArrayList(); - for (int i = 0; i < copyNumber; i++) - { - copyMessageIds.add(ids.remove(i)); - } - - // copy messages - Map messagesData = new HashMap(); - messagesData.put("messages", copyMessageIds); - messagesData.put("destinationQueue", queueName2); - - getRestTestHelper().submitRequest("/service/message/test/" + queueName, "POST", messagesData, HttpServletResponse.SC_OK); - - // check messages on target queue - List> messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName2); - assertNotNull("Messages are not found", messages); - assertEquals("Unexpected number of messages", copyMessageIds.size(), messages.size()); - for (Long id : copyMessageIds) - { - Map message = getRestTestHelper().find("id", id.intValue(), messages); - assertMessageAttributes(message); - } - - // check messages on original queue - messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName); - assertNotNull("Messages are not found", messages); - assertEquals("Unexpected number of messages", MESSAGE_NUMBER, messages.size()); - for (Long id : ids) - { - Map message = getRestTestHelper().find("id", id.intValue(), messages); - assertMessageAttributes(message); - } - for (Long id : copyMessageIds) - { - Map message = getRestTestHelper().find("id", id.intValue(), messages); - assertMessageAttributes(message); - } - } - - public void testDeleteMessages() throws Exception - { - String queueName = getTestQueueName(); - - // get message IDs - List ids = getMesssageIds(queueName); - - // delete half of the messages - int deleteNumber = ids.size() / 2; - StringBuilder queryString = new StringBuilder(); - List deleteMessageIds = new ArrayList<>(); - for (int i = 0; i < deleteNumber; i++) - { - Long id = ids.remove(i); - deleteMessageIds.add(id); - if (queryString.length() > 0) - { - queryString.append("&"); - } - queryString.append("id=").append(id); - } - - // delete messages - getRestTestHelper().submitRequest("/service/message/test/" + queueName + "?" + queryString.toString(), "DELETE", HttpServletResponse.SC_OK); - - // check messages on queue - List> messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName); - assertNotNull("Messages are not found", messages); - assertEquals("Unexpected number of messages", ids.size(), messages.size()); - for (Long id : ids) - { - Map message = getRestTestHelper().find("id", id.intValue(), messages); - assertMessageAttributes(message); - } - for (Long id : deleteMessageIds) - { - Map message = getRestTestHelper().find("id", id.intValue(), messages); - assertNull("Message with id " + id + " was not deleted", message); - } - } - - public void testClearQueue() throws Exception - { - String queueName = getTestQueueName(); - - // clear queue - getRestTestHelper().submitRequest("/service/message/test/" + queueName + "?clear=true", "DELETE", HttpServletResponse.SC_OK); - - // check messages on queue - List> messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName); - assertNotNull("Messages are not found", messages); - assertEquals("Unexpected number of messages", 0, messages.size()); - } - - - private List getMesssageIds(String queueName) throws IOException, JsonMappingException - { - List> messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName); - List ids = new ArrayList(); - for (Map message : messages) - { - ids.add(((Number) message.get("id")).longValue()); - } - return ids; - } - - private void assertMessage(int position, Map message) - { - assertMessageAttributes(message); - - assertEquals("Unexpected message attribute position", position, message.get("position")); - assertEquals("Unexpected message attribute size", position < 10 ? 6 : 7, message.get("size")); - boolean even = position % 2 == 0; - assertMessageAttributeValues(message, even); - } - - private void assertMessageAttributeValues(Map message, boolean even) - { - if (even) - { - assertNull("Unexpected message attribute expirationTime", message.get("expirationTime")); - assertEquals("Unexpected message attribute priority", 4, message.get("priority")); - assertEquals("Unexpected message attribute persistent", Boolean.TRUE, message.get("persistent")); - } - else - { - assertEquals("Unexpected message attribute expirationTime", ((Number) message.get("timestamp")).longValue() - + _ttl, message.get("expirationTime")); - assertEquals("Unexpected message attribute priority", 5, message.get("priority")); - assertEquals("Unexpected message attribute persistent", Boolean.FALSE, message.get("persistent")); - } - assertEquals("Unexpected message attribute mimeType", "text/plain", message.get("mimeType")); - assertEquals("Unexpected message attribute userId", "guest", message.get("userId")); - assertEquals("Unexpected message attribute deliveryCount", 0, message.get("deliveryCount")); - assertEquals("Unexpected message attribute state", "Available", message.get("state")); - } - - private void assertMessageAttributes(Map message) - { - assertNotNull("Message map cannot be null", message); - assertNotNull("Unexpected message attribute deliveryCount", message.get("deliveryCount")); - assertNotNull("Unexpected message attribute state", message.get("state")); - assertNotNull("Unexpected message attribute id", message.get("id")); - assertNotNull("Message arrivalTime cannot be null", message.get("arrivalTime")); - assertNotNull("Message timestamp cannot be null", message.get("timestamp")); - assertTrue("Message arrivalTime cannot be null", ((Number) message.get("arrivalTime")).longValue() > _startTime); - assertNotNull("Message messageId cannot be null", message.get("messageId")); - assertNotNull("Unexpected message attribute mimeType", message.get("mimeType")); - assertNotNull("Unexpected message attribute userId", message.get("userId")); - assertNotNull("Message priority cannot be null", message.get("priority")); - assertNotNull("Message persistent cannot be null", message.get("persistent")); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PortRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PortRestTest.java deleted file mode 100644 index 8b86163aa6..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PortRestTest.java +++ /dev/null @@ -1,366 +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.systest.rest; - -import java.net.ServerSocket; -import java.net.URLDecoder; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; - -import org.apache.qpid.server.BrokerOptions; -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.model.Plugin; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.Protocol; -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.model.Transport; -import org.apache.qpid.server.model.port.JmxPort; -import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager; -import org.apache.qpid.test.utils.PortHelper; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class PortRestTest extends QpidRestTestCase -{ - - public void testGet() throws Exception - { - List> ports = getRestTestHelper().getJsonAsList("port/"); - assertNotNull("Port data cannot be null", ports); - assertEquals("Unexpected number of ports", 2, ports.size()); - - String httpPortName = TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT; - Map portData = getRestTestHelper().find(Port.NAME, httpPortName, ports); - assertNotNull("Http port " + httpPortName + " is not found", portData); - Asserts.assertPortAttributes(portData); - - String amqpPortName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; - Map amqpPortData = getRestTestHelper().find(Port.NAME, amqpPortName, ports); - assertNotNull("Amqp port " + amqpPortName + " is not found", amqpPortData); - Asserts.assertPortAttributes(amqpPortData); - } - - public void testGetPort() throws Exception - { - List> ports = getRestTestHelper().getJsonAsList("port/"); - assertNotNull("Ports data cannot be null", ports); - assertEquals("Unexpected number of ports", 2, ports.size()); - for (Map portMap : ports) - { - String portName = (String) portMap.get(Port.NAME); - assertNotNull("Port name attribute is not found", portName); - Map portData = getRestTestHelper().getJsonAsSingletonList("port/" + URLDecoder.decode(portName, "UTF-8")); - assertNotNull("Port " + portName + " is not found", portData); - Asserts.assertPortAttributes(portData); - } - } - - public void testPutAmqpPortWithMinimumAttributes() throws Exception - { - String portName = "test-port"; - Map attributes = new HashMap(); - attributes.put(Port.NAME, portName); - attributes.put(Port.PORT, findFreePort()); - attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); - - int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); - assertEquals("Unexpected response code", 201, responseCode); - - List> portDetails = getRestTestHelper().getJsonAsList("port/" + portName); - assertNotNull("Port details cannot be null", portDetails); - assertEquals("Unexpected number of ports with name " + portName, 1, portDetails.size()); - Map port = portDetails.get(0); - Asserts.assertPortAttributes(port); - - // make sure that port is there after broker restart - restartBroker(); - - portDetails = getRestTestHelper().getJsonAsList("port/" + portName); - assertNotNull("Port details cannot be null", portDetails); - assertEquals("Unexpected number of ports with name " + portName, 1, portDetails.size()); - } - - public void testPutRmiPortWithMinimumAttributes() throws Exception - { - String portNameRMI = "test-port-rmi"; - Map attributes = new HashMap(); - attributes.put(Port.NAME, portNameRMI); - int rmiPort = findFreePort(); - attributes.put(Port.PORT, rmiPort); - attributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.RMI)); - - int responseCode = getRestTestHelper().submitRequest("port/" + portNameRMI, "PUT", attributes); - assertEquals("Unexpected response code", 201, responseCode); - - - List> portDetails = getRestTestHelper().getJsonAsList("port/" + portNameRMI); - assertNotNull("Port details cannot be null", portDetails); - assertEquals("Unexpected number of ports with name " + portNameRMI, 1, portDetails.size()); - Map port = portDetails.get(0); - Asserts.assertPortAttributes(port, State.QUIESCED); - - String portNameJMX = "test-port-jmx"; - attributes = new HashMap(); - attributes.put(Port.NAME, portNameJMX); - int jmxPort = getNextAvailable(rmiPort + 1); - attributes.put(Port.PORT, jmxPort); - attributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.JMX_RMI)); - attributes.put(JmxPort.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); - - responseCode = getRestTestHelper().submitRequest("port/" + portNameJMX, "PUT", attributes); - assertEquals("Unexpected response code", 201, responseCode); - - - portDetails = getRestTestHelper().getJsonAsList("port/" + portNameJMX); - assertNotNull("Port details cannot be null", portDetails); - assertEquals("Unexpected number of ports with name " + portNameRMI, 1, portDetails.size()); - port = portDetails.get(0); - Asserts.assertPortAttributes(port, State.QUIESCED); - - - attributes.put(Plugin.TYPE, "MANAGEMENT-JMX"); - attributes.put(Plugin.NAME, "JmxPlugin"); - responseCode = getRestTestHelper().submitRequest("plugin/JmxPlugin", "PUT", attributes); - assertEquals("Unexpected response code", 201, responseCode); - - - // make sure that port is there after broker restart - stopBroker(); - - // We shouldn't need to await the ports to be free, but it seems sometimes an RMI TCP Accept - // thread is seen to close the socket *after* the broker has finished stopping. - new PortHelper().waitUntilPortsAreFree(new HashSet(Arrays.asList(jmxPort, rmiPort))); - - startBroker(); - - portDetails = getRestTestHelper().getJsonAsList("port/" + portNameRMI); - assertNotNull("Port details cannot be null", portDetails); - assertEquals("Unexpected number of ports with name " + portNameRMI, 1, portDetails.size()); - port = portDetails.get(0); - Asserts.assertPortAttributes(port, State.ACTIVE); - - // try to add a second RMI port - portNameRMI = portNameRMI + "2"; - attributes = new HashMap(); - attributes.put(Port.NAME, portNameRMI); - attributes.put(Port.PORT, findFreePort()); - attributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.RMI)); - - responseCode = getRestTestHelper().submitRequest("port/" + portNameRMI, "PUT", attributes); - assertEquals("Adding of a second RMI port should fail", 409, responseCode); - } - - public void testPutCreateAndUpdateAmqpPort() throws Exception - { - String portName = "test-port"; - Map attributes = new HashMap(); - attributes.put(Port.NAME, portName); - attributes.put(Port.PORT, findFreePort()); - attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); - - int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); - assertEquals("Unexpected response code for port creation", 201, responseCode); - - List> portDetails = getRestTestHelper().getJsonAsList("port/" + portName); - assertNotNull("Port details cannot be null", portDetails); - assertEquals("Unexpected number of ports with name " + portName, 1, portDetails.size()); - Map port = portDetails.get(0); - Asserts.assertPortAttributes(port); - - Map authProviderAttributes = new HashMap(); - authProviderAttributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); - authProviderAttributes.put(AuthenticationProvider.NAME, TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER); - - responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER, "PUT", authProviderAttributes); - assertEquals("Unexpected response code for authentication provider creation", 201, responseCode); - - attributes = new HashMap(port); - attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER); - attributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.AMQP_0_9_1)); - - responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); - assertEquals("Unexpected response code for port update", 200, responseCode); - } - - public void testUpdatePortTransportFromTCPToSSLWhenKeystoreIsConfigured() throws Exception - { - String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; - Map attributes = new HashMap(); - attributes.put(Port.NAME, portName); - attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); - attributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); - - int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); - assertEquals("Transport has not been changed to SSL " , 200, responseCode); - - Map port = getRestTestHelper().getJsonAsSingletonList("port/" + portName); - - @SuppressWarnings("unchecked") - Collection transports = (Collection) port.get(Port.TRANSPORTS); - assertEquals("Unexpected auth provider", new HashSet(Arrays.asList(Transport.SSL.name())), - new HashSet(transports)); - - String keyStore = (String) port.get(Port.KEY_STORE); - assertEquals("Unexpected auth provider", TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE, keyStore); - } - - public void testUpdateTransportFromTCPToSSLWithoutKeystoreConfiguredFails() throws Exception - { - String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; - Map attributes = new HashMap(); - attributes.put(Port.NAME, portName); - attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); - - int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); - assertEquals("Creation of SSL port without keystore should fail", 409, responseCode); - } - - public void testUpdateWantNeedClientAuth() throws Exception - { - String portName = TestBrokerConfiguration.ENTRY_NAME_SSL_PORT; - Map attributes = new HashMap(); - attributes.put(Port.NAME, portName); - attributes.put(Port.PORT, DEFAULT_SSL_PORT); - attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); - attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); - attributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); - attributes.put(Port.TRUST_STORES, Collections.singleton(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE)); - - int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); - assertEquals("SSL port was not added", 201, responseCode); - - attributes.put(Port.NEED_CLIENT_AUTH, true); - attributes.put(Port.WANT_CLIENT_AUTH, true); - - responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); - assertEquals("Attributes for need/want client auth are not set", 200, responseCode); - - Map port = getRestTestHelper().getJsonAsSingletonList("port/" + portName); - assertEquals("Unexpected " + Port.NEED_CLIENT_AUTH, true, port.get(Port.NEED_CLIENT_AUTH)); - assertEquals("Unexpected " + Port.WANT_CLIENT_AUTH, true, port.get(Port.WANT_CLIENT_AUTH)); - assertEquals("Unexpected " + Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE, port.get(Port.KEY_STORE)); - @SuppressWarnings("unchecked") - Collection trustStores = (Collection) port.get(Port.TRUST_STORES); - assertEquals("Unexpected auth provider", new HashSet(Arrays.asList(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE)), - new HashSet(trustStores)); - - attributes = new HashMap(); - attributes.put(Port.NAME, portName); - attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.TCP)); - - responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); - assertEquals("Should not be able to change transport to TCP without reseting of attributes for need/want client auth", 409, responseCode); - - attributes = new HashMap(); - attributes.put(Port.NAME, portName); - attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.TCP)); - attributes.put(Port.NEED_CLIENT_AUTH, false); - attributes.put(Port.WANT_CLIENT_AUTH, false); - - responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); - assertEquals("Should be able to change transport to TCP ", 200, responseCode); - - port = getRestTestHelper().getJsonAsSingletonList("port/" + portName); - assertEquals("Unexpected " + Port.NEED_CLIENT_AUTH, false, port.get(Port.NEED_CLIENT_AUTH)); - assertEquals("Unexpected " + Port.WANT_CLIENT_AUTH, false, port.get(Port.WANT_CLIENT_AUTH)); - - @SuppressWarnings("unchecked") - Collection transports = (Collection) port.get(Port.TRANSPORTS); - assertEquals("Unexpected auth provider", new HashSet(Arrays.asList(Transport.TCP.name())), - new HashSet(transports)); - } - - public void testUpdateSettingWantNeedCertificateFailsForNonSSLPort() throws Exception - { - String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; - Map attributes = new HashMap(); - attributes.put(Port.NAME, portName); - attributes.put(Port.NEED_CLIENT_AUTH, true); - int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); - assertEquals("Unexpected response when trying to set 'needClientAuth' on non-SSL port", 409, responseCode); - - attributes = new HashMap(); - attributes.put(Port.NAME, portName); - attributes.put(Port.WANT_CLIENT_AUTH, true); - responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); - assertEquals("Unexpected response when trying to set 'wantClientAuth' on non-SSL port", 409, responseCode); - } - - public void testUpdatePortAuthenticationProvider() throws Exception - { - String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; - Map attributes = new HashMap(); - attributes.put(Port.NAME, portName); - attributes.put(Port.AUTHENTICATION_PROVIDER, "non-existing"); - int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); - assertEquals("Unexpected response when trying to change auth provider to non-existing one", 409, responseCode); - - attributes = new HashMap(); - attributes.put(Port.NAME, portName); - attributes.put(Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER); - responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); - assertEquals("Unexpected response when trying to change auth provider to existing one", 200, responseCode); - - Map port = getRestTestHelper().getJsonAsSingletonList("port/" + portName); - assertEquals("Unexpected auth provider", ANONYMOUS_AUTHENTICATION_PROVIDER, port.get(Port.AUTHENTICATION_PROVIDER)); - } - - public void testDefaultAmqpPortIsQuiescedWhenInManagementMode() throws Exception - { - // restart Broker in management port - stopBroker(); - startBroker(0, true); - getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD); - - String ampqPortName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; - Map portData = getRestTestHelper().getJsonAsSingletonList("port/" + URLDecoder.decode(ampqPortName, "UTF-8")); - Asserts.assertPortAttributes(portData, State.QUIESCED); - } - - public void testNewPortErroredIfPortNumberInUse() throws Exception - { - String ampqPortName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; - Map portData = getRestTestHelper().getJsonAsSingletonList("port/" + URLDecoder.decode(ampqPortName, "UTF-8")); - int amqpPort = (Integer)portData.get(Port.PORT); - - ServerSocket socket = new ServerSocket(0); - int occupiedPort = socket.getLocalPort(); - - int deleteResponseCode = getRestTestHelper().submitRequest("port/" + ampqPortName, "DELETE"); - assertEquals("Port deletion should be allowed", 200, deleteResponseCode); - - String newPortName = "reused-port"; - Map attributes = new HashMap(); - attributes.put(Port.NAME, newPortName); - attributes.put(Port.PORT, occupiedPort); // port in use - attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); - - int responseCode = getRestTestHelper().submitRequest("port/" + newPortName, "PUT", attributes); - assertEquals("Unexpected response code for port creation", 201, responseCode); - - portData = getRestTestHelper().getJsonAsSingletonList("port/" + URLDecoder.decode(newPortName, "UTF-8")); - Asserts.assertPortAttributes(portData, State.ERRORED); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PreferencesProviderRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PreferencesProviderRestTest.java deleted file mode 100644 index 6db204b9ca..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PreferencesProviderRestTest.java +++ /dev/null @@ -1,199 +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.systest.rest; - -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.model.BrokerModel; -import org.apache.qpid.server.model.ConfiguredObject; -import org.apache.qpid.server.model.ExternalFileBasedAuthenticationManager; -import org.apache.qpid.server.model.LifetimePolicy; -import org.apache.qpid.server.model.PreferencesProvider; -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.model.adapter.FileSystemPreferencesProvider; -import org.apache.qpid.server.security.auth.manager.PlainPasswordDatabaseAuthenticationManager; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.test.utils.TestFileUtils; - -public class PreferencesProviderRestTest extends QpidRestTestCase -{ - private Map _preferencesProviderFiles; - private File _authenticationProviderFile; - - public void setUp() throws Exception - { - _authenticationProviderFile = TestFileUtils.createTempFile(this, ".test.prefs.txt", "test:test"); - _preferencesProviderFiles = new HashMap(); - super.setUp(); - } - - public void tearDown() throws Exception - { - try - { - super.tearDown(); - } - finally - { - if (_authenticationProviderFile != null) - { - _authenticationProviderFile.delete(); - } - for (File file : _preferencesProviderFiles.values()) - { - file.delete(); - } - } - } - - @Override - protected void customizeConfiguration() throws IOException - { - super.customizeConfiguration(); - Map anonymousAuthProviderAttributes = new HashMap(); - anonymousAuthProviderAttributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE); - anonymousAuthProviderAttributes.put(AuthenticationProvider.NAME, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "-2"); - anonymousAuthProviderAttributes.put(ExternalFileBasedAuthenticationManager.PATH, _authenticationProviderFile.getAbsolutePath()); - getBrokerConfiguration().addObjectConfiguration(AuthenticationProvider.class,anonymousAuthProviderAttributes); - } - - public void testCreateAndGetProvider() throws Exception - { - List> providerDetails = getRestTestHelper().getJsonAsList("preferencesprovider"); - assertEquals("Unexpected number of providers", 0, providerDetails.size()); - - createPreferencesProvider(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, "test1"); - createPreferencesProvider(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "-2", "test2"); - - providerDetails = getRestTestHelper().getJsonAsList("preferencesprovider"); - assertEquals("Unexpected number of providers", 2, providerDetails.size()); - - for (Map provider : providerDetails) - { - assertProvider(provider); - } - - Map provider = getRestTestHelper().getJsonAsSingletonList( - "preferencesprovider/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/test1"); - assertProvider(provider); - assertEquals("Unexpected provider name ", "test1", provider.get(PreferencesProvider.NAME)); - - Map provider2 = getRestTestHelper().getJsonAsSingletonList( - "preferencesprovider/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "-2/test2"); - assertProvider(provider); - assertEquals("Unexpected provider name ", "test2", provider2.get(PreferencesProvider.NAME)); - } - - public void testDeleteProvider() throws Exception - { - createPreferencesProvider(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, "test1"); - String providerUrl = "preferencesprovider/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/test1"; - Map provider = getRestTestHelper().getJsonAsSingletonList(providerUrl); - assertProvider(provider); - assertEquals("Unexpected provider name ", "test1", provider.get(PreferencesProvider.NAME)); - - int responseCode = getRestTestHelper().submitRequest(providerUrl, "DELETE"); - assertEquals("Failed to delete preferences provider", 200, responseCode); - - List> providerDetails = getRestTestHelper().getJsonAsList(providerUrl); - assertEquals("Unexpected number of providers", 0, providerDetails.size()); - } - - public void testUpdateProvider() throws Exception - { - createPreferencesProvider(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, "test1"); - String providerUrl = "preferencesprovider/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/test1"; - Map provider = getRestTestHelper().getJsonAsSingletonList(providerUrl); - assertProvider(provider); - assertEquals("Unexpected provider name ", "test1", provider.get(PreferencesProvider.NAME)); - - File file = TestFileUtils.createTempFile(this, ".prefs.json", "{\"admin\":{\"something\": \"somethingValue\"}}"); - _preferencesProviderFiles.put("new-test1", file); - Map newAttributes = new HashMap(); - newAttributes.put(FileSystemPreferencesProvider.PATH, file.getAbsolutePath()); - - int responseCode = getRestTestHelper().submitRequest(providerUrl, "PUT", newAttributes); - assertEquals("Failed to update preferences provider", 200, responseCode); - - List> providerDetails = getRestTestHelper().getJsonAsList(providerUrl); - assertEquals("Unexpected number of providers", 1, providerDetails.size()); - - provider = providerDetails.get(0); - assertProviderCommonAttributes(provider); - String name = (String) provider.get(PreferencesProvider.NAME); - assertEquals("Unexpected name", "test1", name); - assertEquals("Unexpected path for provider " + name, (String) provider.get(FileSystemPreferencesProvider.PATH), - file.getAbsolutePath()); - } - - private void assertProvider(Map provider) - { - assertProviderCommonAttributes(provider); - - String name = (String) provider.get(PreferencesProvider.NAME); - assertNotNull("Name cannot be null", name); - assertEquals("Unexpected path for provider " + name, (String) provider.get(FileSystemPreferencesProvider.PATH), - _preferencesProviderFiles.get(name).getAbsolutePath()); - } - - public void assertProviderCommonAttributes(Map provider) - { - Asserts.assertAttributesPresent(provider, - BrokerModel.getInstance().getTypeRegistry().getAttributeNames( - PreferencesProvider.class), - ConfiguredObject.CREATED_BY, - ConfiguredObject.CREATED_TIME, - ConfiguredObject.LAST_UPDATED_BY, - ConfiguredObject.LAST_UPDATED_TIME, - ConfiguredObject.DESCRIPTION, - ConfiguredObject.CONTEXT, - ConfiguredObject.DESIRED_STATE); - assertEquals("Unexpected value of provider attribute " + PreferencesProvider.STATE, State.ACTIVE.name(), - provider.get(PreferencesProvider.STATE)); - assertEquals("Unexpected value of provider attribute " + PreferencesProvider.LIFETIME_POLICY, - LifetimePolicy.PERMANENT.name(), provider.get(PreferencesProvider.LIFETIME_POLICY)); - assertEquals("Unexpected value of provider attribute " + PreferencesProvider.DURABLE, Boolean.TRUE, - provider.get(PreferencesProvider.DURABLE)); - assertEquals("Unexpected value of provider attribute " + PreferencesProvider.TYPE, - FileSystemPreferencesProvider.PROVIDER_TYPE, provider.get(PreferencesProvider.TYPE)); - } - - private void createPreferencesProvider(String authenticationProvider, String providerName) throws Exception - { - Map attributes = new HashMap(); - attributes.put(PreferencesProvider.NAME, providerName); - attributes.put(PreferencesProvider.TYPE, FileSystemPreferencesProvider.PROVIDER_TYPE); - File file = TestFileUtils.createTempFile(this, ".prefs.json", "{\"admin\":{\"language\": \"en\"}}"); - _preferencesProviderFiles.put(providerName, file); - attributes.put(FileSystemPreferencesProvider.PATH, file.getAbsolutePath()); - - int responseCode = getRestTestHelper().submitRequest( - "preferencesprovider/" + authenticationProvider + "/" + providerName, "PUT", attributes); - assertEquals("Unexpected response code", 201, responseCode); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PreferencesRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PreferencesRestTest.java deleted file mode 100644 index bd72391522..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PreferencesRestTest.java +++ /dev/null @@ -1,114 +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.systest.rest; - -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import org.apache.qpid.server.model.PreferencesProvider; -import org.apache.qpid.server.model.adapter.FileSystemPreferencesProvider; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.test.utils.TestFileUtils; - -public class PreferencesRestTest extends QpidRestTestCase -{ - private File _preferencesProviderFile; - - public void setUp() throws Exception - { - _preferencesProviderFile = TestFileUtils.createTempFile(this, ".prefs.json", - "{\"webadmin\":{\"language\": \"en\", \"saveTabs\":true}}"); - super.setUp(); - } - - public void tearDown() throws Exception - { - try - { - super.tearDown(); - } - finally - { - if (_preferencesProviderFile != null) - { - _preferencesProviderFile.delete(); - } - } - } - - @Override - protected void customizeConfiguration() throws IOException - { - super.customizeConfiguration(); - - TestBrokerConfiguration brokerConfiguration = getBrokerConfiguration(); - Map attributes = new HashMap(); - attributes.put(PreferencesProvider.NAME, "test"); - attributes.put(PreferencesProvider.TYPE, FileSystemPreferencesProvider.PROVIDER_TYPE); - attributes.put(FileSystemPreferencesProvider.PATH, _preferencesProviderFile.getAbsolutePath()); - brokerConfiguration.addPreferencesProviderConfiguration(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, - attributes); - - } - - public void testGetPreferences() throws Exception - { - Map preferences = getRestTestHelper().getJsonAsMap("/service/preferences"); - assertEquals("Unexpected number of preferences", 2, preferences.size()); - assertEquals("Unexpected language preference", "en", preferences.get("language")); - assertEquals("Unexpected saveTabs preference", true, preferences.get("saveTabs")); - } - - public void testUpdatePreferences() throws Exception - { - Map additionalPreferences = new HashMap(); - additionalPreferences.put("timezone", "Europe/London"); - additionalPreferences.put("test", 1); - - int status = getRestTestHelper().submitRequest("/service/preferences", "POST", additionalPreferences); - assertEquals("Unexpected response code", 200, status); - - Map preferences = getRestTestHelper().getJsonAsMap("/service/preferences"); - assertEquals("Unexpected number of preferences", 4, preferences.size()); - assertEquals("Unexpected language preference", "en", preferences.get("language")); - assertEquals("Unexpected saveTabs preference", true, preferences.get("saveTabs")); - assertEquals("Unexpected timezone preference", "Europe/London", preferences.get("timezone")); - assertEquals("Unexpected test preference", 1, preferences.get("test")); - } - - public void testReplacePreferences() throws Exception - { - Map additionalPreferences = new HashMap(); - additionalPreferences.put("timezone", "Europe/London"); - additionalPreferences.put("test", 1); - - int status = getRestTestHelper().submitRequest("/service/preferences", "PUT", additionalPreferences); - assertEquals("Unexpected response code", 200, status); - - Map preferences = getRestTestHelper().getJsonAsMap("/service/preferences"); - assertEquals("Unexpected number of preferences", 2, preferences.size()); - assertEquals("Unexpected timezone preference", "Europe/London", preferences.get("timezone")); - assertEquals("Unexpected test preference", 1, preferences.get("test")); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QueueRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QueueRestTest.java deleted file mode 100644 index baebc9a28e..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QueueRestTest.java +++ /dev/null @@ -1,262 +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.systest.rest; - -import java.io.IOException; -import java.net.URLDecoder; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; - -import org.apache.qpid.server.model.Binding; -import org.apache.qpid.server.model.BrokerModel; -import org.apache.qpid.server.model.ConfiguredObject; -import org.apache.qpid.server.model.Consumer; -import org.apache.qpid.server.model.LifetimePolicy; -import org.apache.qpid.server.model.Queue; - -public class QueueRestTest extends QpidRestTestCase -{ - private static final String QUEUE_ATTRIBUTE_CONSUMERS = "consumers"; - private static final String QUEUE_ATTRIBUTE_BINDINGS = "bindings"; - - /** - * Message number to publish into queue - */ - private static final int MESSAGE_NUMBER = 2; - private static final int MESSAGE_PAYLOAD_SIZE = 6; - private static final int ENQUEUED_MESSAGES = 1; - private static final int DEQUEUED_MESSAGES = 1; - private static final int ENQUEUED_BYTES = MESSAGE_PAYLOAD_SIZE; - private static final int DEQUEUED_BYTES = MESSAGE_PAYLOAD_SIZE; - - private Connection _connection; - - public void setUp() throws Exception - { - super.setUp(); - _connection = getConnection(); - Session session = _connection.createSession(true, Session.SESSION_TRANSACTED); - String queueName = getTestQueueName(); - Destination queue = session.createQueue(queueName); - MessageConsumer consumer = session.createConsumer(queue); - MessageProducer producer = session.createProducer(queue); - - for (int i = 0; i < MESSAGE_NUMBER; i++) - { - producer.send(session.createTextMessage("Test-" + i)); - } - session.commit(); - _connection.start(); - Message m = consumer.receive(1000l); - assertNotNull("Message is not received", m); - session.commit(); - } - - public void testGetVirtualHostQueues() throws Exception - { - String queueName = getTestQueueName(); - List> queues = getRestTestHelper().getJsonAsList("queue/test"); - assertEquals("Unexpected number of queues", 1, queues.size()); - String[] expectedQueues = new String[]{queueName}; - - for (String name : expectedQueues) - { - Map queueDetails = getRestTestHelper().find(Queue.NAME, name, queues); - Asserts.assertQueue(name, "standard", queueDetails); - - @SuppressWarnings("unchecked") - List> bindings = (List>) queueDetails.get(QUEUE_ATTRIBUTE_BINDINGS); - assertNotNull("Queue bindings are not found", bindings); - assertEquals("Unexpected number of bindings", 1, bindings.size()); - - Map directExchangeBinding = getRestTestHelper().find(Binding.EXCHANGE, "amq.direct", bindings); - Asserts.assertBinding(name, "amq.direct", directExchangeBinding); - } - } - - public void testGetByName() throws Exception - { - String queueName = getTestQueueName(); - Map queueDetails = getRestTestHelper().getJsonAsSingletonList("queue/test/test/" + queueName); - Asserts.assertQueue(queueName, "standard", queueDetails); - assertStatistics(queueDetails); - - @SuppressWarnings("unchecked") - List> bindings = (List>) queueDetails.get(QUEUE_ATTRIBUTE_BINDINGS); - assertNotNull("Queue bindings are not found", bindings); - assertEquals("Unexpected number of bindings", 1, bindings.size()); - - Map directExchangeBinding = getRestTestHelper().find(Binding.EXCHANGE, "amq.direct", bindings); - Asserts.assertBinding(queueName, "amq.direct", directExchangeBinding); - - @SuppressWarnings("unchecked") - List> consumers = (List>) queueDetails.get(QUEUE_ATTRIBUTE_CONSUMERS); - assertNotNull("Queue consumers are not found", consumers); - assertEquals("Unexpected number of consumers", 1, consumers.size()); - assertConsumer(consumers.get(0)); - } - - public void testUpdateQueue() throws Exception - { - String queueName = getTestName(); - - Map attributes = new HashMap(); - attributes.put(Queue.NAME, queueName); - - String queueUrl = "queue/test/test/" + queueName; - int responseCode = getRestTestHelper().submitRequest(queueUrl, "PUT", attributes); - assertEquals("Queue was not created", 201, responseCode); - - Map queueDetails = getRestTestHelper().getJsonAsSingletonList(queueUrl); - Asserts.assertQueue(queueName, "standard", queueDetails); - - attributes = new HashMap(); - attributes.put(Queue.NAME, queueName); - attributes.put(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 100000); - attributes.put(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 80000); - attributes.put(Queue.ALERT_REPEAT_GAP, 10000); - attributes.put(Queue.ALERT_THRESHOLD_MESSAGE_AGE, 20000); - attributes.put(Queue.ALERT_THRESHOLD_MESSAGE_SIZE, 30000); - attributes.put(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_BYTES, 40000); - attributes.put(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, 50000); - attributes.put(Queue.MAXIMUM_DELIVERY_ATTEMPTS, 10); - - responseCode = getRestTestHelper().submitRequest(queueUrl, "PUT", attributes); - assertEquals("Setting of queue attributes should be allowed", 200, responseCode); - - Map queueData = getRestTestHelper().getJsonAsSingletonList(queueUrl); - assertEquals("Unexpected " + Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 100000, queueData.get(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES) ); - assertEquals("Unexpected " + Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 80000, queueData.get(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES) ); - assertEquals("Unexpected " + Queue.ALERT_REPEAT_GAP, 10000, queueData.get(Queue.ALERT_REPEAT_GAP) ); - assertEquals("Unexpected " + Queue.ALERT_THRESHOLD_MESSAGE_AGE, 20000, queueData.get(Queue.ALERT_THRESHOLD_MESSAGE_AGE) ); - assertEquals("Unexpected " + Queue.ALERT_THRESHOLD_MESSAGE_SIZE, 30000, queueData.get(Queue.ALERT_THRESHOLD_MESSAGE_SIZE) ); - assertEquals("Unexpected " + Queue.ALERT_THRESHOLD_QUEUE_DEPTH_BYTES, 40000, queueData.get(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_BYTES) ); - assertEquals("Unexpected " + Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, 50000, queueData.get(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES) ); - } - - public void testPutCreateBinding() throws Exception - { - String queueName = getTestQueueName(); - String bindingName = queueName + 2; - String[] exchanges = { "amq.direct", "amq.fanout", "amq.topic", "amq.match" }; - - for (int i = 0; i < exchanges.length; i++) - { - createBinding(bindingName, exchanges[i], queueName); - } - - Map queueDetails = getRestTestHelper().getJsonAsSingletonList("queue/test/test/" + queueName); - Asserts.assertQueue(queueName, "standard", queueDetails); - - @SuppressWarnings("unchecked") - List> bindings = (List>) queueDetails.get(QUEUE_ATTRIBUTE_BINDINGS); - assertNotNull("Queue bindings are not found", bindings); - assertEquals("Unexpected number of bindings", exchanges.length + 1, bindings.size()); - - Map searchAttributes = new HashMap(); - searchAttributes.put(Binding.NAME, bindingName); - - for (int i = 0; i < exchanges.length; i++) - { - searchAttributes.put(Binding.EXCHANGE, exchanges[i]); - Map binding = getRestTestHelper().find(searchAttributes, bindings); - Asserts.assertBinding(bindingName, queueName, exchanges[i], binding); - } - } - - private void createBinding(String bindingName, String exchangeName, String queueName) throws IOException - { - Map bindingData = new HashMap(); - bindingData.put(Binding.NAME, bindingName); - bindingData.put(Binding.EXCHANGE, exchangeName); - bindingData.put(Binding.QUEUE, queueName); - - String url = "binding/test/test/" + URLDecoder.decode(exchangeName, "UTF-8") + "/" + queueName + "/" + bindingName; - int responseCode = getRestTestHelper().submitRequest(url, "PUT", bindingData); - assertEquals("Unexpected response code", 201, responseCode); - } - - private void assertConsumer(Map consumer) - { - assertNotNull("Consumer map should not be null", consumer); - Asserts.assertAttributesPresent(consumer, - BrokerModel.getInstance().getTypeRegistry().getAttributeNames(Consumer.class), Consumer.STATE, - Consumer.SETTLEMENT_MODE, Consumer.EXCLUSIVE, Consumer.SELECTOR, - Consumer.NO_LOCAL, - ConfiguredObject.TYPE, - ConfiguredObject.CREATED_BY, - ConfiguredObject.CREATED_TIME, - ConfiguredObject.LAST_UPDATED_BY, - ConfiguredObject.LAST_UPDATED_TIME, - ConfiguredObject.DESCRIPTION, - ConfiguredObject.CONTEXT, - ConfiguredObject.DESIRED_STATE); - - assertEquals("Unexpected binding attribute " + Consumer.NAME, "1", consumer.get(Consumer.NAME)); - assertEquals("Unexpected binding attribute " + Consumer.DURABLE, Boolean.FALSE, consumer.get(Consumer.DURABLE)); - assertEquals("Unexpected binding attribute " + Consumer.LIFETIME_POLICY, LifetimePolicy.DELETE_ON_SESSION_END.name(), - consumer.get(Consumer.LIFETIME_POLICY)); - assertEquals("Unexpected binding attribute " + Consumer.DISTRIBUTION_MODE, "MOVE", - consumer.get(Consumer.DISTRIBUTION_MODE)); - - @SuppressWarnings("unchecked") - Map statistics = (Map) consumer.get(Asserts.STATISTICS_ATTRIBUTE); - assertNotNull("Consumer statistics is not present", statistics); - Asserts.assertAttributesPresent(statistics, "bytesOut", "messagesOut", "unacknowledgedBytes", "unacknowledgedMessages"); - } - - private void assertStatistics(Map queueDetails) - { - @SuppressWarnings("unchecked") - Map statistics = (Map) queueDetails.get(Asserts.STATISTICS_ATTRIBUTE); - assertEquals("Unexpected queue statistics attribute " + "persistentDequeuedMessages", DEQUEUED_MESSAGES, - statistics.get("persistentDequeuedMessages")); - assertEquals("Unexpected queue statistics attribute " + "queueDepthMessages", ENQUEUED_MESSAGES, - statistics.get("queueDepthMessages")); - assertEquals("Unexpected queue statistics attribute " + "consumerCount", 1, - statistics.get("consumerCount")); - assertEquals("Unexpected queue statistics attribute " + "consumerCountWithCredit", 1, - statistics.get("consumerCountWithCredit")); - assertEquals("Unexpected queue statistics attribute " + "bindingCount", 1, statistics.get("bindingCount")); - assertEquals("Unexpected queue statistics attribute " + "persistentDequeuedMessages", DEQUEUED_MESSAGES, - statistics.get("persistentDequeuedMessages")); - assertEquals("Unexpected queue statistics attribute " + "totalDequeuedMessages", DEQUEUED_MESSAGES, - statistics.get("totalDequeuedMessages")); - assertEquals("Unexpected queue statistics attribute " + "totalDequeuedBytes", DEQUEUED_BYTES, - statistics.get("totalDequeuedBytes")); - assertEquals("Unexpected queue statistics attribute " + "persistentDequeuedBytes", DEQUEUED_BYTES, - statistics.get("totalDequeuedBytes")); - assertEquals("Unexpected queue statistics attribute " + "persistentEnqueuedBytes", ENQUEUED_BYTES - + DEQUEUED_BYTES, statistics.get("persistentEnqueuedBytes")); - assertEquals("Unexpected queue statistics attribute " + "totalEnqueuedBytes", ENQUEUED_BYTES + DEQUEUED_BYTES, - statistics.get("totalEnqueuedBytes")); - assertEquals("Unexpected queue statistics attribute " + "queueDepthBytes", ENQUEUED_BYTES, - statistics.get("queueDepthBytes")); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/SaslRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/SaslRestTest.java deleted file mode 100644 index 547b7b1b00..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/SaslRestTest.java +++ /dev/null @@ -1,384 +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.systest.rest; - -import static org.apache.qpid.server.security.auth.sasl.SaslUtil.generateCramMD5ClientResponse; -import static org.apache.qpid.server.security.auth.sasl.SaslUtil.generateCramMD5HexClientResponse; -import static org.apache.qpid.server.security.auth.sasl.SaslUtil.generatePlainClientResponse; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.codec.binary.Base64; -import org.codehaus.jackson.JsonParseException; -import org.codehaus.jackson.map.JsonMappingException; - -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.security.auth.manager.Base64MD5PasswordDatabaseAuthenticationManager; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.tools.security.Passwd; - -public class SaslRestTest extends QpidRestTestCase -{ - @Override - public void startBroker() - { - // prevent broker from starting in setUp - } - - public void startBrokerNow() throws Exception - { - super.startBroker(); - - getRestTestHelper().setUsernameAndPassword(null,null); - } - - public void testGetMechanismsWithBrokerPlainPasswordPrincipalDatabase() throws Exception - { - startBrokerNow(); - - Map saslData = getRestTestHelper().getJsonAsMap("/service/sasl"); - assertNotNull("mechanisms attribute is not found", saslData.get("mechanisms")); - - @SuppressWarnings("unchecked") - List mechanisms = (List) saslData.get("mechanisms"); - String[] expectedMechanisms = { "CRAM-MD5" }; - for (String mechanism : expectedMechanisms) - { - assertTrue("Mechanism " + mechanism + " is not found", mechanisms.contains(mechanism)); - } - assertNull("Unexpected user was returned: " + saslData.get("user"), saslData.get("user")); - } - - public void testGetMechanismsWithBrokerBase64MD5FilePrincipalDatabase() throws Exception - { - configureBase64MD5FilePrincipalDatabase(); - startBrokerNow(); - - Map saslData = getRestTestHelper().getJsonAsMap("/service/sasl"); - assertNotNull("mechanisms attribute is not found", saslData.get("mechanisms")); - - @SuppressWarnings("unchecked") - List mechanisms = (List) saslData.get("mechanisms"); - String[] expectedMechanisms = { "CRAM-MD5-HEX", "CRAM-MD5-HASHED" }; - for (String mechanism : expectedMechanisms) - { - assertTrue("Mechanism " + mechanism + " is not found", mechanisms.contains(mechanism)); - } - - assertNull("Unexpected user was returned: " + saslData.get("user"), saslData.get("user")); - } - - public void testPlainSaslAuthenticationForValidCredentials() throws Exception - { - startBrokerNow(); - - byte[] responseBytes = generatePlainClientResponse("admin", "admin"); - String responseData = Base64.encodeBase64String(responseBytes); - String parameters= "mechanism=PLAIN&response=" + responseData; - - HttpURLConnection connection = getRestTestHelper().openManagementConnection("/service/sasl", "POST"); - OutputStream os = connection.getOutputStream(); - os.write(parameters.getBytes()); - os.flush(); - - int code = getRestTestHelper().submitRequest("/service/sasl", "POST", parameters.getBytes()); - assertEquals("Unexpected response code", 200, code); - - List cookies = connection.getHeaderFields().get("Set-Cookie"); - - // request authenticated user details - connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET"); - applyCookiesToConnection(cookies, connection); - Map response2 = getRestTestHelper().readJsonResponseAsMap(connection); - assertEquals("Unexpected user", "admin", response2.get("user")); - } - - public void testPlainSaslAuthenticationForIncorrectPassword() throws Exception - { - startBrokerNow(); - - byte[] responseBytes = generatePlainClientResponse("admin", "incorrect"); - String responseData = Base64.encodeBase64String(responseBytes); - String parameters= "mechanism=PLAIN&response=" + responseData; - - HttpURLConnection connection = getRestTestHelper().openManagementConnection("/service/sasl", "POST"); - OutputStream os = connection.getOutputStream(); - os.write(parameters.getBytes()); - os.flush(); - - int code = connection.getResponseCode(); - assertEquals("Unexpected response code", 401, code); - - List cookies = connection.getHeaderFields().get("Set-Cookie"); - - // request authenticated user details - connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET"); - applyCookiesToConnection(cookies, connection); - Map response2 = getRestTestHelper().readJsonResponseAsMap(connection); - assertNull("Unexpected user", response2.get("user")); - } - - public void testPlainSaslAuthenticationForNonExistingUser() throws Exception - { - startBrokerNow(); - - byte[] responseBytes = generatePlainClientResponse("nonexisting", "admin"); - String responseData = Base64.encodeBase64String(responseBytes); - String parameters= "mechanism=PLAIN&response=" + responseData; - - HttpURLConnection connection = getRestTestHelper().openManagementConnection("/service/sasl", "POST"); - OutputStream os = connection.getOutputStream(); - os.write(parameters.getBytes()); - os.flush(); - - int code = connection.getResponseCode(); - assertEquals("Unexpected response code", 401, code); - - List cookies = connection.getHeaderFields().get("Set-Cookie"); - - // request authenticated user details - connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET"); - applyCookiesToConnection(cookies, connection); - Map response2 = getRestTestHelper().readJsonResponseAsMap(connection); - assertNull("Unexpected user", response2.get("user")); - } - - public void testCramMD5SaslAuthenticationForValidCredentials() throws Exception - { - startBrokerNow(); - - // request the challenge for CRAM-MD5 - HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5"); - List cookies = connection.getHeaderFields().get("Set-Cookie"); - - // authenticate user with correct credentials - int code = authenticateUser(connection, "admin", "admin", "CRAM-MD5"); - assertEquals("Unexpected response code", 200, code); - - // request authenticated user details - connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET"); - applyCookiesToConnection(cookies, connection); - Map response2 = getRestTestHelper().readJsonResponseAsMap(connection); - assertEquals("Unexpected user", "admin", response2.get("user")); - } - - public void testCramMD5SaslAuthenticationForIncorrectPassword() throws Exception - { - startBrokerNow(); - - // request the challenge for CRAM-MD5 - HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5"); - List cookies = connection.getHeaderFields().get("Set-Cookie"); - - // authenticate user with correct credentials - int code = authenticateUser(connection, "admin", "incorrect", "CRAM-MD5"); - assertEquals("Unexpected response code", 401, code); - - // request authenticated user details - connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET"); - applyCookiesToConnection(cookies, connection); - Map response2 = getRestTestHelper().readJsonResponseAsMap(connection); - assertNull("Unexpected user", response2.get("user")); - } - - public void testCramMD5SaslAuthenticationForNonExistingUser() throws Exception - { - startBrokerNow(); - - // request the challenge for CRAM-MD5 - HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5"); - List cookies = connection.getHeaderFields().get("Set-Cookie"); - - // authenticate user with correct credentials - int code = authenticateUser(connection, "nonexisting", "admin", "CRAM-MD5"); - assertEquals("Unexpected response code", 401, code); - - // request authenticated user details - connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET"); - applyCookiesToConnection(cookies, connection); - Map response2 = getRestTestHelper().readJsonResponseAsMap(connection); - assertNull("Unexpected user", response2.get("user")); - } - - public void testCramMD5HexSaslAuthenticationForValidCredentials() throws Exception - { - configureBase64MD5FilePrincipalDatabase(); - startBrokerNow(); - - // request the challenge for CRAM-MD5-HEX - HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5-HEX"); - List cookies = connection.getHeaderFields().get("Set-Cookie"); - - // authenticate user with correct credentials - int code = authenticateUser(connection, "admin", "admin", "CRAM-MD5-HEX"); - assertEquals("Unexpected response code", 200, code); - - // request authenticated user details - connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET"); - applyCookiesToConnection(cookies, connection); - Map response2 = getRestTestHelper().readJsonResponseAsMap(connection); - assertEquals("Unexpected user", "admin", response2.get("user")); - } - - public void testCramMD5HexSaslAuthenticationForIncorrectPassword() throws Exception - { - configureBase64MD5FilePrincipalDatabase(); - startBrokerNow(); - - HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5-HEX"); - List cookies = connection.getHeaderFields().get("Set-Cookie"); - - // try to authenticate user with incorrect passowrd - int code = authenticateUser(connection, "admin", "incorrect", "CRAM-MD5-HEX"); - assertEquals("Unexpected response code", 401, code); - - // request authenticated user details - connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET"); - applyCookiesToConnection(cookies, connection); - Map response2 = getRestTestHelper().readJsonResponseAsMap(connection); - assertNull("Unexpected user", response2.get("user")); - } - - public void testCramMD5HexSaslAuthenticationForNonExistingUser() throws Exception - { - configureBase64MD5FilePrincipalDatabase(); - startBrokerNow(); - - HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5-HEX"); - List cookies = connection.getHeaderFields().get("Set-Cookie"); - - // try to authenticate non-existing user - int code = authenticateUser(connection, "nonexisting", "admin", "CRAM-MD5-HEX"); - assertEquals("Unexpected response code", 401, code); - - // request authenticated user details - connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET"); - applyCookiesToConnection(cookies, connection); - Map response2 = getRestTestHelper().readJsonResponseAsMap(connection); - assertNull("Unexpected user", response2.get("user")); - } - - private HttpURLConnection requestSasServerChallenge(String mechanism) throws IOException - { - HttpURLConnection connection = getRestTestHelper().openManagementConnection("/service/sasl", "POST"); - OutputStream os = connection.getOutputStream(); - os.write(("mechanism=" + mechanism).getBytes()); - os.flush(); - return connection; - } - - public int authenticateUser(HttpURLConnection requestChallengeConnection, String userName, String userPassword, String mechanism) - throws IOException, JsonParseException, JsonMappingException, Exception - { - // get the response - Map response = getRestTestHelper().readJsonResponseAsMap(requestChallengeConnection); - String challenge = (String) response.get("challenge"); - assertNotNull("Challenge is not found", challenge); - - // preserve cookies to have the same server session - List cookies = requestChallengeConnection.getHeaderFields().get("Set-Cookie"); - - // generate the authentication response for the challenge received - byte[] challengeBytes = Base64.decodeBase64(challenge); - byte[] responseBytes = generateClientResponse(mechanism, userName, userPassword, challengeBytes); - String responseData = Base64.encodeBase64String(responseBytes); - String requestParameters = ("id=" + response.get("id") + "&response=" + responseData); - - // re-open connection - HttpURLConnection authenticateConnection = getRestTestHelper().openManagementConnection("/service/sasl", "POST"); - - // set cookies to use the same server session - applyCookiesToConnection(cookies, authenticateConnection); - OutputStream os = authenticateConnection.getOutputStream(); - os.write(requestParameters.getBytes()); - os.flush(); - return authenticateConnection.getResponseCode(); - } - - private byte[] generateClientResponse(String mechanism, String userName, String userPassword, byte[] challengeBytes) throws Exception - { - byte[] responseBytes = null; - if ("CRAM-MD5-HEX".equalsIgnoreCase(mechanism)) - { - responseBytes = generateCramMD5HexClientResponse(userName, userPassword, challengeBytes); - } - else if ("CRAM-MD5".equalsIgnoreCase(mechanism)) - { - responseBytes = generateCramMD5ClientResponse(userName, userPassword, challengeBytes); - } - else - { - throw new RuntimeException("Not implemented test mechanism " + mechanism); - } - return responseBytes; - } - - private void applyCookiesToConnection(List cookies, HttpURLConnection connection) - { - for (String cookie : cookies) - { - connection.addRequestProperty("Cookie", cookie.split(";", 2)[0]); - } - } - - private void configureBase64MD5FilePrincipalDatabase() throws IOException - { - // generate user password entry - String passwordFileEntry; - try - { - passwordFileEntry = new Passwd().getOutput("admin", "admin"); - } - catch (NoSuchAlgorithmException e) - { - throw new RuntimeException(e); - } - - // store the entry in the file - File passwordFile = File.createTempFile("passwd", "pwd"); - passwordFile.deleteOnExit(); - - FileWriter writer = null; - try - { - writer = new FileWriter(passwordFile); - writer.write(passwordFileEntry); - } - finally - { - writer.close(); - } - - // configure broker to use Base64MD5PasswordFilePrincipalDatabase - Map newAttributes = new HashMap(); - newAttributes.put("path", passwordFile.getAbsolutePath()); - newAttributes.put(AuthenticationProvider.TYPE, Base64MD5PasswordDatabaseAuthenticationManager.PROVIDER_TYPE); - getBrokerConfiguration().setObjectAttributes(AuthenticationProvider.class,TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, newAttributes); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/StructureRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/StructureRestTest.java deleted file mode 100644 index daefc05e2a..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/StructureRestTest.java +++ /dev/null @@ -1,129 +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.systest.rest; - -import java.util.List; -import java.util.Map; - -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class StructureRestTest extends QpidRestTestCase -{ - - @Override - public void setUp() throws Exception - { - super.setUp(); - getRestTestHelper().createTestQueues(); - } - - public void testGet() throws Exception - { - Map structure = getRestTestHelper().getJsonAsMap("/service/structure"); - assertNotNull("Structure data cannot be null", structure); - assertNode(structure, "Broker"); - - @SuppressWarnings("unchecked") - List> virtualhostnodes = (List>) structure.get("virtualhostnodes"); - assertEquals("Unexpected number of virtual hosts", 3, virtualhostnodes.size()); - - @SuppressWarnings("unchecked") - List> ports = (List>) structure.get("ports"); - assertEquals("Unexpected number of ports", 2, ports.size()); - - @SuppressWarnings("unchecked") - List> providers = (List>) structure.get("authenticationproviders"); - assertEquals("Unexpected number of authentication providers", 2, providers.size()); - - for (String nodeName : EXPECTED_VIRTUALHOSTS) - { - Map node = getRestTestHelper().find("name", nodeName, virtualhostnodes); - assertNotNull("Node " + nodeName + " is not found ", node); - assertNode(node, nodeName); - } - - String hostName = "test"; - Map node = getRestTestHelper().find("name", hostName, virtualhostnodes); - - @SuppressWarnings("unchecked") - List> virtualhosts = (List>) node.get("virtualhosts"); - - Map host = getRestTestHelper().find("name", hostName, virtualhosts); - @SuppressWarnings("unchecked") - List> queues = (List>) host.get("queues"); - assertNotNull("Host " + hostName + " queues are not found ", queues); - for (String queueName : RestTestHelper.EXPECTED_QUEUES) - { - Map queue = getRestTestHelper().find("name", queueName, queues); - assertNotNull(hostName + " queue " + queueName + " is not found ", queue); - assertNode(queue, queueName); - - @SuppressWarnings("unchecked") - List> bindings = (List>) queue.get("bindings"); - assertNotNull(hostName + " queue " + queueName + " bindings are not found ", queues); - for (Map binding : bindings) - { - assertNode(binding, queueName); - } - } - - @SuppressWarnings("unchecked") - List> exchanges = (List>) host.get("exchanges"); - assertNotNull("Host " + hostName + " exchanges are not found ", exchanges); - for (String exchangeName : EXPECTED_EXCHANGES) - { - Map exchange = getRestTestHelper().find("name", exchangeName, exchanges); - assertNotNull("Exchange " + exchangeName + " is not found ", exchange); - assertNode(exchange, exchangeName); - if (ExchangeDefaults.DIRECT_EXCHANGE_NAME.equalsIgnoreCase(exchangeName) || - ExchangeDefaults.DEFAULT_EXCHANGE_NAME.equalsIgnoreCase(exchangeName)) - { - @SuppressWarnings("unchecked") - List> bindings = (List>) exchange.get("bindings"); - assertNotNull(hostName + " exchange " + exchangeName + " bindings are not found ", bindings); - for (String queueName : RestTestHelper.EXPECTED_QUEUES) - { - Map binding = getRestTestHelper().find("name", queueName, bindings); - assertNotNull(hostName + " exchange " + exchangeName + " binding " + queueName + " is not found", binding); - assertNode(binding, queueName); - } - } - } - - String httpPortName = TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT; - Map portData = getRestTestHelper().find(Port.NAME, httpPortName, ports); - assertNotNull("Http Port " + httpPortName + " is not found", portData); - assertNode(portData, httpPortName); - - String amqpPortName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; - Map amqpPortData = getRestTestHelper().find(Port.NAME, amqpPortName, ports); - assertNotNull("Amqp port " + amqpPortName + " is not found", amqpPortData); - assertNode(amqpPortData, amqpPortName); - } - - private void assertNode(Map node, String name) - { - assertEquals("Unexpected name", name, node.get("name")); - assertNotNull("Unexpected id", node.get("id")); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/TrustStoreRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/TrustStoreRestTest.java deleted file mode 100644 index 5d2e9de3fa..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/TrustStoreRestTest.java +++ /dev/null @@ -1,263 +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.systest.rest; - -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.codehaus.jackson.JsonGenerationException; -import org.codehaus.jackson.JsonParseException; -import org.codehaus.jackson.map.JsonMappingException; - -import org.apache.qpid.server.model.AbstractConfiguredObject; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.Transport; -import org.apache.qpid.server.model.TrustStore; -import org.apache.qpid.server.security.FileTrustStore; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.test.utils.TestSSLConstants; - -public class TrustStoreRestTest extends QpidRestTestCase -{ - @Override - public void setUp() throws Exception - { - // not calling super.setUp() to avoid broker start-up until - // after any necessary configuration - } - - public void testGet() throws Exception - { - super.setUp(); - - //verify existence of the default trust store used by the systests - List> trustStores = assertNumberOfTrustStores(1); - - Map truststore = trustStores.get(0); - assertTrustStoreAttributes(truststore, TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE, - System.getProperty(QPID_HOME) + "/../" + TestSSLConstants.BROKER_TRUSTSTORE, false); - } - - public void testCreate() throws Exception - { - super.setUp(); - - String name = getTestName(); - - assertNumberOfTrustStores(1); - createTrustStore(name, true); - assertNumberOfTrustStores(2); - - List> trustStores = getRestTestHelper().getJsonAsList("truststore/" + name); - assertNotNull("details cannot be null", trustStores); - - assertTrustStoreAttributes(trustStores.get(0), name, TestSSLConstants.TRUSTSTORE, true); - } - - public void testDelete() throws Exception - { - super.setUp(); - - String name = getTestName(); - - assertNumberOfTrustStores(1); - createTrustStore(name, false); - assertNumberOfTrustStores(2); - - int responseCode = getRestTestHelper().submitRequest("truststore/" + name , "DELETE"); - assertEquals("Unexpected response code for provider deletion", 200, responseCode); - - List> trustStore = getRestTestHelper().getJsonAsList("truststore/" + name); - assertNotNull("details should not be null", trustStore); - assertTrue("details should be empty as the truststore no longer exists", trustStore.isEmpty()); - - //check only the default systests trust store remains - List> trustStores = assertNumberOfTrustStores(1); - Map truststore = trustStores.get(0); - assertTrustStoreAttributes(truststore, TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE, - System.getProperty(QPID_HOME) + "/../" + TestSSLConstants.BROKER_TRUSTSTORE, false); - } - - public void testDeleteFailsWhenTrustStoreInUse() throws Exception - { - String name = "testDeleteFailsWhenTrustStoreInUse"; - - //add a new trust store config to use - Map sslTrustStoreAttributes = new HashMap(); - sslTrustStoreAttributes.put(TrustStore.NAME, name); - sslTrustStoreAttributes.put(FileTrustStore.PATH, TestSSLConstants.TRUSTSTORE); - sslTrustStoreAttributes.put(FileTrustStore.PASSWORD, TestSSLConstants.TRUSTSTORE_PASSWORD); - getBrokerConfiguration().addObjectConfiguration(TrustStore.class,sslTrustStoreAttributes); - - //add the SSL port using it - Map sslPortAttributes = new HashMap(); - sslPortAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); - sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT); - sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT); - sslPortAttributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); - sslPortAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); - sslPortAttributes.put(Port.TRUST_STORES, Collections.singleton(name)); - getBrokerConfiguration().addObjectConfiguration(Port.class, sslPortAttributes); - - super.setUp(); - - //verify the truststore is there - assertNumberOfTrustStores(2); - - List> trustStore = getRestTestHelper().getJsonAsList("truststore/" + name); - assertNotNull("details should not be null", trustStore); - assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false); - - //try to delete it, which should fail as it is in use - int responseCode = getRestTestHelper().submitRequest("truststore/" + name , "DELETE"); - assertEquals("Unexpected response code for provider deletion", 409, responseCode); - - //check its still there - assertNumberOfTrustStores(2); - trustStore = getRestTestHelper().getJsonAsList("truststore/" + name); - assertNotNull("details should not be null", trustStore); - assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false); - } - - public void testUpdateWithGoodPathSucceeds() throws Exception - { - super.setUp(); - - String name = getTestName(); - - assertNumberOfTrustStores(1); - createTrustStore(name, false); - assertNumberOfTrustStores(2); - - Map attributes = new HashMap(); - attributes.put(TrustStore.NAME, name); - attributes.put(FileTrustStore.PATH, TestSSLConstants.TRUSTSTORE); - - int responseCode = getRestTestHelper().submitRequest("truststore/" + name , "PUT", attributes); - assertEquals("Unexpected response code for truststore update", 200, responseCode); - - List> trustStore = getRestTestHelper().getJsonAsList("truststore/" + name); - assertNotNull("details should not be null", trustStore); - - assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false); - } - - public void testUpdateWithNonExistentPathFails() throws Exception - { - super.setUp(); - - String name = getTestName(); - - assertNumberOfTrustStores(1); - createTrustStore(name, false); - assertNumberOfTrustStores(2); - - Map attributes = new HashMap(); - attributes.put(TrustStore.NAME, name); - attributes.put(FileTrustStore.PATH, "does.not.exist"); - - int responseCode = getRestTestHelper().submitRequest("truststore/" + name , "PUT", attributes); - assertEquals("Unexpected response code for trust store update", 409, responseCode); - - List> trustStore = getRestTestHelper().getJsonAsList("truststore/" + name); - assertNotNull("details should not be null", trustStore); - - //verify the details remain unchanged - assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false); - } - - public void testUpdatePeersOnly() throws Exception - { - super.setUp(); - - String name = getTestName(); - - assertNumberOfTrustStores(1); - createTrustStore(name, false); - assertNumberOfTrustStores(2); - - //update the peersOnly attribute from false to true - Map attributes = new HashMap(); - attributes.put(TrustStore.NAME, name); - attributes.put(FileTrustStore.PEERS_ONLY, true); - - int responseCode = getRestTestHelper().submitRequest("truststore/" + name , "PUT", attributes); - assertEquals("Unexpected response code for trust store update", 200, responseCode); - - List> trustStore = getRestTestHelper().getJsonAsList("truststore/" + name); - assertNotNull("details should not be null", trustStore); - - assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, true); - - //Update peersOnly to clear it (i.e go from from true to null, which will default to false) - attributes = new HashMap(); - attributes.put(TrustStore.NAME, name); - attributes.put(FileTrustStore.PEERS_ONLY, null); - - responseCode = getRestTestHelper().submitRequest("truststore/" + name , "PUT", attributes); - assertEquals("Unexpected response code for trust store update", 200, responseCode); - - trustStore = getRestTestHelper().getJsonAsList("truststore/" + name); - assertNotNull("details should not be null", trustStore); - - assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false); - } - - private List> assertNumberOfTrustStores(int numberOfTrustStores) throws IOException, - JsonParseException, JsonMappingException - { - List> trustStores = getRestTestHelper().getJsonAsList("truststore"); - assertNotNull("trust stores should not be null", trustStores); - assertEquals("Unexpected number of trust stores", numberOfTrustStores, trustStores.size()); - - return trustStores; - } - - private void createTrustStore(String name, boolean peersOnly) throws IOException, JsonGenerationException, JsonMappingException - { - Map trustStoreAttributes = new HashMap(); - trustStoreAttributes.put(TrustStore.NAME, name); - //deliberately using the client trust store to differentiate from the one we are already for broker - trustStoreAttributes.put(FileTrustStore.PATH, TestSSLConstants.TRUSTSTORE); - trustStoreAttributes.put(FileTrustStore.PASSWORD, TestSSLConstants.TRUSTSTORE_PASSWORD); - trustStoreAttributes.put(FileTrustStore.PEERS_ONLY, peersOnly); - - int responseCode = getRestTestHelper().submitRequest("truststore/" + name, "PUT", trustStoreAttributes); - assertEquals("Unexpected response code", 201, responseCode); - } - - private void assertTrustStoreAttributes(Map truststore, String name, String path, boolean peersOnly) - { - assertEquals("default systests trust store is missing", - name, truststore.get(TrustStore.NAME)); - assertEquals("unexpected path to trust store", - path, truststore.get(FileTrustStore.PATH)); - assertEquals("unexpected (dummy) password of default systests trust store", - AbstractConfiguredObject.SECURED_STRING_VALUE, truststore.get(FileTrustStore.PASSWORD)); - assertEquals("unexpected type of default systests trust store", - java.security.KeyStore.getDefaultType(), truststore.get(FileTrustStore.TRUST_STORE_TYPE)); - assertEquals("unexpected peersOnly value", - peersOnly, truststore.get(FileTrustStore.PEERS_ONLY)); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/UserPreferencesRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/UserPreferencesRestTest.java deleted file mode 100644 index a0902912ce..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/UserPreferencesRestTest.java +++ /dev/null @@ -1,150 +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.systest.rest; - -import java.io.File; -import java.io.IOException; -import java.net.URLEncoder; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.qpid.server.model.PreferencesProvider; -import org.apache.qpid.server.model.User; -import org.apache.qpid.server.model.adapter.FileSystemPreferencesProvider; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.test.utils.TestFileUtils; - -public class UserPreferencesRestTest extends QpidRestTestCase -{ - private File _preferencesProviderFile; - - public void setUp() throws Exception - { - _preferencesProviderFile = TestFileUtils.createTempFile(this, ".prefs.json", - "{\"webadmin\":{\"language\": \"en\", \"saveTabs\":true}," - + " \"admin\":{\"language\": \"fr\", \"saveTabs\":false}" + "}"); - super.setUp(); - } - - public void tearDown() throws Exception - { - try - { - super.tearDown(); - } - finally - { - if (_preferencesProviderFile != null) - { - _preferencesProviderFile.delete(); - } - } - } - - @Override - protected void customizeConfiguration() throws IOException - { - super.customizeConfiguration(); - - TestBrokerConfiguration brokerConfiguration = getBrokerConfiguration(); - Map attributes = new HashMap(); - attributes.put(PreferencesProvider.NAME, "test"); - attributes.put(PreferencesProvider.TYPE, FileSystemPreferencesProvider.PROVIDER_TYPE); - attributes.put(FileSystemPreferencesProvider.PATH, _preferencesProviderFile.getAbsolutePath()); - brokerConfiguration.addPreferencesProviderConfiguration(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, - attributes); - - } - - public void testGetUserPreferences() throws Exception - { - Map preferences = getRestTestHelper().getJsonAsMap( - "/service/userpreferences/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/webadmin"); - assertEquals("Unexpected number of preferences", 2, preferences.size()); - assertEquals("Unexpected language preference", "en", preferences.get("language")); - assertEquals("Unexpected saveTabs preference", true, preferences.get("saveTabs")); - } - - public void testGetUserListForAuthenticationProvider() throws Exception - { - List> users = getRestTestHelper().getJsonAsList( - "/service/userpreferences/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); - assertEquals("Unexpected number of users", 2, users.size()); - String[] expectedUsers = { "webadmin", "admin" }; - for (int i = 0; i < expectedUsers.length; i++) - { - Map user = findUser(expectedUsers[i], users); - assertNotNull(String.format("User %s is not found", expectedUsers[i]), user); - } - } - - public void testGetUserList() throws Exception - { - List> users = getRestTestHelper().getJsonAsList("/service/userpreferences"); - assertEquals("Unexpected number of users", 2, users.size()); - String[] expectedUsers = { "webadmin", "admin" }; - for (int i = 0; i < expectedUsers.length; i++) - { - Map user = findUser(expectedUsers[i], users); - assertNotNull(String.format("User %s is not found", expectedUsers[i]), user); - } - } - - public void testDeleteUser() throws Exception - { - int status = getRestTestHelper().submitRequest( - "/service/userpreferences?user=" - + URLEncoder.encode(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/webadmin", - "UTF-8"), "DELETE"); - assertEquals("Unexpected status ", 200, status); - List> users = getRestTestHelper().getJsonAsList("/service/userpreferences"); - assertEquals("Unexpected number of users", 1, users.size()); - Map user = findUser("admin", users); - assertNotNull("User admin is not found", user); - assertNull("User webadmin is found", findUser("webadmin", users)); - } - - public void testDeleteMultipleUser() throws Exception - { - int status = getRestTestHelper().submitRequest("/service/userpreferences?user=" - + URLEncoder.encode(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/webadmin", "UTF-8") - + "&user=" + URLEncoder.encode(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/admin", "UTF-8"), - "DELETE"); - assertEquals("Unexpected status ", 200, status); - List> users = getRestTestHelper().getJsonAsList("/service/userpreferences"); - assertEquals("Unexpected number of users", 0, users.size()); - } - - private Map findUser(String userName, List> users) - { - for (Map map : users) - { - if (userName.equals(map.get(User.NAME))) - { - return map; - } - } - return null; - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/UserRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/UserRestTest.java deleted file mode 100644 index 5df8a4ed9a..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/UserRestTest.java +++ /dev/null @@ -1,100 +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.systest.rest; - -import java.util.List; -import java.util.Map; - -import org.apache.qpid.server.model.User; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class UserRestTest extends QpidRestTestCase -{ - @Override - public void setUp() throws Exception - { - getRestTestHelper().configureTemporaryPasswordFile(this, "user1", "user2"); - - super.setUp(); // do this last because it starts the broker, using the modified config - getRestTestHelper().setUsernameAndPassword("user1", "user1"); - } - - public void testGet() throws Exception - { - List> users = getRestTestHelper().getJsonAsList("user"); - assertNotNull("Users cannot be null", users); - assertTrue("Unexpected number of users", users.size() > 1); - for (Map user : users) - { - assertUser(user); - } - } - - public void testGetUserByName() throws Exception - { - List> users = getRestTestHelper().getJsonAsList("user"); - assertNotNull("Users cannot be null", users); - assertTrue("Unexpected number of users", users.size() > 1); - for (Map user : users) - { - assertNotNull("Attribute " + User.ID, user.get(User.ID)); - String userName = (String) user.get(User.NAME); - assertNotNull("Attribute " + User.NAME, userName); - Map userDetails = getRestTestHelper().getJsonAsSingletonList("user/" - + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + userName); - assertUser(userDetails); - assertEquals("Unexpected user name", userName, userDetails.get(User.NAME)); - } - } - - public void testPut() throws Exception - { - String userName = getTestName(); - getRestTestHelper().createOrUpdateUser(userName, "newPassword"); - - Map userDetails = getRestTestHelper().getJsonAsSingletonList("user/" - + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + userName); - assertUser(userDetails); - assertEquals("Unexpected user name", userName, userDetails.get(User.NAME)); - } - - public void testDelete() throws Exception - { - String userName = getTestName(); - getRestTestHelper().createOrUpdateUser(userName, "newPassword"); - - Map userDetails = getRestTestHelper().getJsonAsSingletonList("user/" - + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + userName); - String id = (String) userDetails.get(User.ID); - - getRestTestHelper().removeUserById(id); - - List> users = getRestTestHelper().getJsonAsList("user/" - + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + userName); - assertEquals("User should be deleted", 0, users.size()); - } - - private void assertUser(Map user) - { - assertNotNull("Attribute " + User.ID, user.get(User.ID)); - assertNotNull("Attribute " + User.NAME, user.get(User.NAME)); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/VirtualHostNodeRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/VirtualHostNodeRestTest.java deleted file mode 100644 index 3e49f63cff..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/VirtualHostNodeRestTest.java +++ /dev/null @@ -1,164 +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.systest.rest; - - -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.servlet.http.HttpServletResponse; - -import org.apache.qpid.server.model.ConfiguredObject; -import org.apache.qpid.server.model.VirtualHostNode; -import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNode; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -/** - * - * TODO: Add test to test the mutation of the storePath. If the store path is mutated - * whilst active then the store should be deleted next time we stop or close. - */ -public class VirtualHostNodeRestTest extends QpidRestTestCase -{ - public void testGet() throws Exception - { - List> virtualhostNodes = getRestTestHelper().getJsonAsList("virtualhostnode"); - assertNotNull("Virtualhostnodes data cannot be null", virtualhostNodes); - assertEquals("Unexpected number of hosts", EXPECTED_VIRTUALHOSTS.length, virtualhostNodes.size()); - for (String nodeName : EXPECTED_VIRTUALHOSTS) - { - Map node = getRestTestHelper().find("name", nodeName, virtualhostNodes); - Asserts.assertVirtualHostNode(nodeName, node); - } - } - - public void testCreateAndDeleteVirtualHostNode() throws Exception - { - String storeType = getTestProfileVirtualHostNodeType(); - String nodeName = "virtualhostnode-" + getTestName(); - File storePathAsFile = new File(getStoreLocation(nodeName)); - - createAndDeleteVirtualHostNode(storeType, nodeName, storePathAsFile); - assertFalse("Store should not exist after deletion", storePathAsFile.exists()); - } - - public void testRecoverVirtualHostNodeWithDesiredStateStopped() throws Exception - { - stopBroker(); - - TestBrokerConfiguration config = getBrokerConfiguration(); - config.setObjectAttribute(VirtualHostNode.class, TEST3_VIRTUALHOST, ConfiguredObject.DESIRED_STATE, "STOPPED"); - config.setSaved(false); - - startBroker(); - - String restUrl = "virtualhostnode/" + TEST3_VIRTUALHOST; - assertActualAndDesireStates(restUrl, "STOPPED", "STOPPED"); - } - - public void testMutateState() throws Exception - { - String restUrl = "virtualhostnode/" + TEST3_VIRTUALHOST; - - assertActualAndDesireStates(restUrl, "ACTIVE", "ACTIVE"); - - mutateVirtualHostNodeDesiredState(restUrl, "STOPPED"); - assertActualAndDesireStates(restUrl, "STOPPED", "STOPPED"); - - mutateVirtualHostNodeDesiredState(restUrl, "ACTIVE"); - assertActualAndDesireStates(restUrl, "ACTIVE", "ACTIVE"); - } - - public void testMutateAttributes() throws Exception - { - String restUrl = "virtualhostnode/" + TEST3_VIRTUALHOST; - - Map virtualhostNode = getRestTestHelper().getJsonAsSingletonList(restUrl); - assertNull(virtualhostNode.get(VirtualHostNode.DESCRIPTION)); - - String newDescription = "My virtualhost node"; - Map newAttributes = new HashMap(); - newAttributes.put(VirtualHostNode.DESCRIPTION, newDescription); - - getRestTestHelper().submitRequest(restUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); - - virtualhostNode = getRestTestHelper().getJsonAsSingletonList(restUrl); - assertEquals(newDescription, virtualhostNode.get(VirtualHostNode.DESCRIPTION)); - } - - private void createAndDeleteVirtualHostNode(final String virtualhostNodeType, - final String nodeName, - final File storePathAsFile) throws Exception - { - assertFalse("Store should not exist", storePathAsFile.exists()); - - createVirtualHostNode(nodeName, storePathAsFile.getAbsolutePath(), virtualhostNodeType); - assertTrue("Store should exist after creation of node", storePathAsFile.exists()); - - String restUrl = "virtualhostnode/" + nodeName; - Map virtualhostNode = getRestTestHelper().getJsonAsSingletonList(restUrl); - Asserts.assertVirtualHostNode(nodeName, virtualhostNode); - assertNull("Virtualhostnode should not automatically get a virtualhost child", - virtualhostNode.get("virtualhosts")); - - getRestTestHelper().submitRequest(restUrl, "DELETE", HttpServletResponse.SC_OK); - - List> virtualHostNodes = getRestTestHelper().getJsonAsList(restUrl); - assertEquals("Host should be deleted", 0, virtualHostNodes.size()); - } - - private void assertActualAndDesireStates(final String restUrl, - final String expectedDesiredState, - final String expectedActualState) throws IOException - { - Map virtualhostNode = getRestTestHelper().getJsonAsSingletonList(restUrl); - Asserts.assertActualAndDesiredState(expectedDesiredState, expectedActualState, virtualhostNode); - } - - private void mutateVirtualHostNodeDesiredState(final String restUrl, final String newState) throws IOException - { - Map newAttributes = new HashMap(); - newAttributes.put(VirtualHostNode.DESIRED_STATE, newState); - - getRestTestHelper().submitRequest(restUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); - } - - private void createVirtualHostNode(String nodeName, String configStorePath, final String storeType) throws Exception - { - Map nodeData = new HashMap(); - nodeData.put(VirtualHostNode.NAME, nodeName); - nodeData.put(VirtualHostNode.TYPE, storeType); - nodeData.put(JsonVirtualHostNode.STORE_PATH, configStorePath); - - getRestTestHelper().submitRequest("virtualhostnode/" + nodeName, - "PUT", - nodeData, - HttpServletResponse.SC_CREATED); - } - - private String getStoreLocation(String hostName) - { - return new File(TMP_FOLDER, "store-" + hostName + "-" + System.currentTimeMillis()).getAbsolutePath(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java deleted file mode 100644 index 243b93e798..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java +++ /dev/null @@ -1,635 +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.systest.rest; - -import java.io.File; -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.Session; -import javax.servlet.http.HttpServletResponse; - -import org.apache.qpid.server.virtualhost.ProvidedStoreVirtualHostImpl; -import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNode; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.server.model.Exchange; -import org.apache.qpid.server.model.Queue; -import org.apache.qpid.server.model.VirtualHost; -import org.apache.qpid.server.model.VirtualHostNode; -import org.apache.qpid.server.queue.LastValueQueue; -import org.apache.qpid.server.queue.PriorityQueue; -import org.apache.qpid.server.queue.SortedQueue; -import org.apache.qpid.server.virtualhost.AbstractVirtualHost; - -import org.apache.qpid.util.FileUtils; - -public class VirtualHostRestTest extends QpidRestTestCase -{ - private static final String VIRTUALHOST_EXCHANGES_ATTRIBUTE = "exchanges"; - public static final String VIRTUALHOST_QUEUES_ATTRIBUTE = "queues"; - public static final String VIRTUALHOST_CONNECTIONS_ATTRIBUTE = "connections"; - - private AMQConnection _connection; - - public void testGet() throws Exception - { - List> hosts = getRestTestHelper().getJsonAsList("virtualhost"); - assertNotNull("Hosts data cannot be null", hosts); - assertEquals("Unexpected number of hosts", EXPECTED_VIRTUALHOSTS.length, hosts.size()); - for (String hostName : EXPECTED_VIRTUALHOSTS) - { - Map host = getRestTestHelper().find("name", hostName, hosts); - Asserts.assertVirtualHost(hostName, host); - } - } - - public void testGetHost() throws Exception - { - // create AMQP connection to get connection JSON details - _connection = (AMQConnection) getConnection(); - Session session = _connection.createSession(true, Session.SESSION_TRANSACTED); - session.createConsumer(getTestQueue()); - - Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); - Asserts.assertVirtualHost("test", hostDetails); - - @SuppressWarnings("unchecked") - Map statistics = (Map) hostDetails.get(Asserts.STATISTICS_ATTRIBUTE); - - assertEquals("Unexpected number of exchanges in statistics", EXPECTED_EXCHANGES.length, statistics.get( - "exchangeCount")); - assertEquals("Unexpected number of queues in statistics", 1, statistics.get("queueCount")); - assertEquals("Unexpected number of connections in statistics", 1, statistics.get("connectionCount")); - - @SuppressWarnings("unchecked") - List> exchanges = (List>) hostDetails.get(VIRTUALHOST_EXCHANGES_ATTRIBUTE); - assertEquals("Unexpected number of exchanges", EXPECTED_EXCHANGES.length, exchanges.size()); - Asserts.assertDurableExchange("amq.fanout", "fanout", getRestTestHelper().find(Exchange.NAME, "amq.fanout", exchanges)); - Asserts.assertDurableExchange("amq.topic", "topic", getRestTestHelper().find(Exchange.NAME, "amq.topic", exchanges)); - Asserts.assertDurableExchange("amq.direct", "direct", getRestTestHelper().find(Exchange.NAME, "amq.direct", exchanges)); - Asserts.assertDurableExchange("amq.match", "headers", getRestTestHelper().find(Exchange.NAME, "amq.match", exchanges)); - - @SuppressWarnings("unchecked") - List> queues = (List>) hostDetails.get(VIRTUALHOST_QUEUES_ATTRIBUTE); - assertEquals("Unexpected number of queues", 1, queues.size()); - Map queue = getRestTestHelper().find(Queue.NAME, getTestQueueName(), queues); - Asserts.assertQueue(getTestQueueName(), "standard", queue); - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, queue.get(Queue.DURABLE)); - - @SuppressWarnings("unchecked") - List> connections = (List>) hostDetails - .get(VIRTUALHOST_CONNECTIONS_ATTRIBUTE); - assertEquals("Unexpected number of connections", 1, connections.size()); - Asserts.assertConnection(connections.get(0), _connection); - } - - public void testPutCreateVirtualHostUsingProfileNodeType() throws Exception - { - String hostName = getTestName(); - String virtualhostNodeType = getTestProfileVirtualHostNodeType(); - String storeLocation = createVirtualHostNodeAndVirtualHost(hostName, virtualhostNodeType); - try - { - // make sure that the host is saved in the broker store - restartBroker(); - Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/" + hostName); - Asserts.assertVirtualHost(hostName, hostDetails); - - assertNewVirtualHost(hostDetails); - } - finally - { - if (storeLocation != null) - { - FileUtils.delete(new File(storeLocation), true); - } - } - } - - public void testDeleteHost() throws Exception - { - getRestTestHelper().submitRequest("virtualhost/" + TEST3_VIRTUALHOST + "/" + TEST3_VIRTUALHOST, - "DELETE", - HttpServletResponse.SC_OK); - - List> hosts = getRestTestHelper().getJsonAsList("virtualhost/" + TEST3_VIRTUALHOST); - assertEquals("Host should be deleted", 0, hosts.size()); - } - - public void testDeleteDefaultHostFails() throws Exception - { - getRestTestHelper().submitRequest("virtualhost/" + TEST1_VIRTUALHOST, "DELETE", HttpServletResponse.SC_CONFLICT); - } - - public void testMutateAttributes() throws Exception - { - String hostToUpdate = TEST3_VIRTUALHOST; - String restHostUrl = "virtualhost/" + hostToUpdate + "/" + hostToUpdate; - - Map hostDetails = getRestTestHelper().getJsonAsSingletonList(restHostUrl); - Asserts.assertVirtualHost(hostToUpdate, hostDetails); - - Map newAttributes = Collections.singletonMap(VirtualHost.DESCRIPTION, "This is a virtual host"); - getRestTestHelper().submitRequest(restHostUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); - - Map rereadHostDetails = getRestTestHelper().getJsonAsSingletonList(restHostUrl); - Asserts.assertVirtualHost(hostToUpdate, rereadHostDetails); - assertEquals("This is a virtual host", rereadHostDetails.get(VirtualHost.DESCRIPTION)); - } - - public void testMutateState() throws Exception - { - String restHostUrl = "virtualhost/" + TEST1_VIRTUALHOST + "/" + TEST1_VIRTUALHOST; - - waitForAttributeChanged(restHostUrl, VirtualHost.STATE, "ACTIVE"); - assertActualAndDesireStates(restHostUrl, "ACTIVE", "ACTIVE"); - - Map newAttributes = Collections.singletonMap(VirtualHost.DESIRED_STATE, "STOPPED"); - getRestTestHelper().submitRequest(restHostUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); - - waitForAttributeChanged(restHostUrl, VirtualHost.STATE, "STOPPED"); - assertActualAndDesireStates(restHostUrl, "STOPPED", "STOPPED"); - - newAttributes = Collections.singletonMap(VirtualHost.DESIRED_STATE, "ACTIVE"); - getRestTestHelper().submitRequest(restHostUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); - - waitForAttributeChanged(restHostUrl, VirtualHost.STATE, "ACTIVE"); - - assertActualAndDesireStates(restHostUrl, "ACTIVE", "ACTIVE"); - } - - public void testMutateStateOfVirtualHostWithQueuesAndMessages() throws Exception - { - String testQueueName = getTestQueueName(); - String restHostUrl = "virtualhost/" + TEST1_VIRTUALHOST + "/" + TEST1_VIRTUALHOST; - String restQueueUrl = "queue/" + TEST1_VIRTUALHOST + "/" + TEST1_VIRTUALHOST + "/" + testQueueName; - - waitForAttributeChanged(restHostUrl, VirtualHost.STATE, "ACTIVE"); - assertActualAndDesireStates(restHostUrl, "ACTIVE", "ACTIVE"); - - Connection connection = getConnection(); - Session session = connection.createSession(true, Session.SESSION_TRANSACTED); - Destination dest = session.createQueue(testQueueName); - session.createConsumer(dest).close(); - session.createProducer(dest).send(session.createTextMessage("My test message")); - session.commit(); - connection.close(); - - assertQueueDepth(restQueueUrl, "Unexpected number of messages before stopped", 1); - - Map newAttributes = Collections.singletonMap(VirtualHost.DESIRED_STATE, "STOPPED"); - getRestTestHelper().submitRequest(restHostUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); - - waitForAttributeChanged(restHostUrl, VirtualHost.STATE, "STOPPED"); - assertActualAndDesireStates(restHostUrl, "STOPPED", "STOPPED"); - - newAttributes = Collections.singletonMap(VirtualHost.DESIRED_STATE, "ACTIVE"); - getRestTestHelper().submitRequest(restHostUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); - - waitForAttributeChanged(restHostUrl, VirtualHost.STATE, "ACTIVE"); - - assertActualAndDesireStates(restHostUrl, "ACTIVE", "ACTIVE"); - - assertQueueDepth(restQueueUrl, "Unexpected number of messages after restart", 1); - } - - public void testRecoverVirtualHostInDesiredStateStoppedWithDescription() throws Exception - { - String hostToUpdate = TEST3_VIRTUALHOST; - String restUrl = "virtualhost/" + hostToUpdate + "/" + hostToUpdate; - - assertActualAndDesireStates(restUrl, "ACTIVE", "ACTIVE"); - - Map newAttributes = new HashMap<>(); - newAttributes.put(VirtualHost.DESIRED_STATE, "STOPPED"); - newAttributes.put(VirtualHost.DESCRIPTION, "My description"); - - getRestTestHelper().submitRequest(restUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); - - assertActualAndDesireStates(restUrl, "STOPPED", "STOPPED"); - - restartBroker(); - - Map rereadVirtualhost = getRestTestHelper().getJsonAsSingletonList(restUrl); - Asserts.assertActualAndDesiredState("STOPPED", "STOPPED", rereadVirtualhost); - - assertEquals("Unexpected description after restart", "My description", rereadVirtualhost.get(VirtualHost.DESCRIPTION)); - } - - public void testPutCreateQueue() throws Exception - { - String queueName = getTestQueueName(); - - createQueue(queueName + "-standard", "standard", null); - - Map sortedQueueAttributes = new HashMap(); - sortedQueueAttributes.put(SortedQueue.SORT_KEY, "sortme"); - createQueue(queueName + "-sorted", "sorted", sortedQueueAttributes); - - Map priorityQueueAttributes = new HashMap(); - priorityQueueAttributes.put(PriorityQueue.PRIORITIES, 10); - createQueue(queueName + "-priority", "priority", priorityQueueAttributes); - - Map lvqQueueAttributes = new HashMap(); - lvqQueueAttributes.put(LastValueQueue.LVQ_KEY, "LVQ"); - createQueue(queueName + "-lvq", "lvq", lvqQueueAttributes); - - Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); - - @SuppressWarnings("unchecked") - List> queues = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE); - Map standardQueue = getRestTestHelper().find(Queue.NAME, queueName + "-standard" , queues); - Map sortedQueue = getRestTestHelper().find(Queue.NAME, queueName + "-sorted" , queues); - Map priorityQueue = getRestTestHelper().find(Queue.NAME, queueName + "-priority" , queues); - Map lvqQueue = getRestTestHelper().find(Queue.NAME, queueName + "-lvq" , queues); - - Asserts.assertQueue(queueName + "-standard", "standard", standardQueue); - Asserts.assertQueue(queueName + "-sorted", "sorted", sortedQueue); - Asserts.assertQueue(queueName + "-priority", "priority", priorityQueue); - Asserts.assertQueue(queueName + "-lvq", "lvq", lvqQueue); - - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, standardQueue.get(Queue.DURABLE)); - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, sortedQueue.get(Queue.DURABLE)); - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, priorityQueue.get(Queue.DURABLE)); - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, lvqQueue.get(Queue.DURABLE)); - - assertEquals("Unexpected sorted key attribute", "sortme", sortedQueue.get(SortedQueue.SORT_KEY)); - assertEquals("Unexpected lvq key attribute", "LVQ", lvqQueue.get(LastValueQueue.LVQ_KEY)); - assertEquals("Unexpected priorities key attribute", 10, priorityQueue.get(PriorityQueue.PRIORITIES)); - } - - public void testPutCreateExchange() throws Exception - { - String exchangeName = getTestName(); - - createExchange(exchangeName + "-direct", "direct"); - createExchange(exchangeName + "-topic", "topic"); - createExchange(exchangeName + "-headers", "headers"); - createExchange(exchangeName + "-fanout", "fanout"); - - Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); - - @SuppressWarnings("unchecked") - List> exchanges = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_EXCHANGES_ATTRIBUTE); - Map directExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-direct" , exchanges); - Map topicExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-topic" , exchanges); - Map headersExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-headers" , exchanges); - Map fanoutExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-fanout" , exchanges); - - Asserts.assertDurableExchange(exchangeName + "-direct", "direct", directExchange); - Asserts.assertDurableExchange(exchangeName + "-topic", "topic", topicExchange); - Asserts.assertDurableExchange(exchangeName + "-headers", "headers", headersExchange); - Asserts.assertDurableExchange(exchangeName + "-fanout", "fanout", fanoutExchange); - - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, directExchange.get(Queue.DURABLE)); - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, topicExchange.get(Queue.DURABLE)); - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, headersExchange.get(Queue.DURABLE)); - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, fanoutExchange.get(Queue.DURABLE)); - - } - - public void testPutCreateLVQWithoutKey() throws Exception - { - String queueName = getTestQueueName()+ "-lvq"; - createQueue(queueName, "lvq", null); - - Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); - - @SuppressWarnings("unchecked") - List> queues = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE); - Map lvqQueue = getRestTestHelper().find(Queue.NAME, queueName , queues); - - Asserts.assertQueue(queueName , "lvq", lvqQueue); - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, lvqQueue.get(Queue.DURABLE)); - assertEquals("Unexpected lvq key attribute", LastValueQueue.DEFAULT_LVQ_KEY, lvqQueue.get(LastValueQueue.LVQ_KEY)); - } - - public void testPutCreateSortedQueueWithoutKey() throws Exception - { - String queueName = getTestQueueName() + "-sorted"; - int responseCode = tryCreateQueue(queueName, "sorted", null); - assertEquals("Unexpected response code", HttpServletResponse.SC_CONFLICT, responseCode); - - Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); - - @SuppressWarnings("unchecked") - List> queues = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE); - Map testQueue = getRestTestHelper().find(Queue.NAME, queueName , queues); - - assertNull("Sorted queue without a key was created ", testQueue); - } - - public void testPutCreatePriorityQueueWithoutKey() throws Exception - { - String queueName = getTestQueueName()+ "-priority"; - createQueue(queueName, "priority", null); - - Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); - - @SuppressWarnings("unchecked") - List> queues = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE); - Map priorityQueue = getRestTestHelper().find(Queue.NAME, queueName , queues); - - Asserts.assertQueue(queueName , "priority", priorityQueue); - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, priorityQueue.get(Queue.DURABLE)); - assertEquals("Unexpected number of priorities", 10, priorityQueue.get(PriorityQueue.PRIORITIES)); - } - - public void testPutCreateStandardQueueWithoutType() throws Exception - { - String queueName = getTestQueueName(); - createQueue(queueName, null, null); - - Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); - - @SuppressWarnings("unchecked") - List> queues = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE); - Map queue = getRestTestHelper().find(Queue.NAME, queueName , queues); - - Asserts.assertQueue(queueName , "standard", queue); - } - - public void testPutCreateQueueOfUnsupportedType() throws Exception - { - String queueName = getTestQueueName(); - int responseCode = tryCreateQueue(queueName, "unsupported", null); - assertEquals("Unexpected response code", HttpServletResponse.SC_CONFLICT, responseCode); - - Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); - - @SuppressWarnings("unchecked") - List> queues = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE); - Map queue = getRestTestHelper().find(Queue.NAME, queueName , queues); - - assertNull("Queue of unsupported type was created", queue); - } - - public void testDeleteQueue() throws Exception - { - String queueName = getTestQueueName(); - createQueue(queueName, null, null); - - String queueUrl = "queue/test/test/" + queueName; - List> queues = getRestTestHelper().getJsonAsList(queueUrl); - assertEquals("Queue should exist", 1, queues.size()); - - int statusCode = getRestTestHelper().submitRequest(queueUrl, "DELETE"); - assertEquals("Unexpected response code", 200, statusCode); - queues = getRestTestHelper().getJsonAsList(queueUrl); - assertEquals("Queue should be deleted", 0, queues.size()); - } - - public void testDeleteQueueById() throws Exception - { - String queueName = getTestQueueName(); - createQueue(queueName, null, null); - Map queueDetails = getRestTestHelper().getJsonAsSingletonList("queue/test/test/" + queueName); - int statusCode = getRestTestHelper().submitRequest("queue/test/test?id=" + queueDetails.get(Queue.ID), "DELETE"); - assertEquals("Unexpected response code", 200, statusCode); - List> queues = getRestTestHelper().getJsonAsList("queue/test/test/" + queueName); - assertEquals("Queue should be deleted", 0, queues.size()); - } - - public void testDeleteExchange() throws Exception - { - String exchangeName = getTestName(); - createExchange(exchangeName, "direct"); - - int statusCode = getRestTestHelper().submitRequest("exchange/test/test/" + exchangeName, "DELETE"); - - assertEquals("Unexpected response code", 200, statusCode); - List> queues = getRestTestHelper().getJsonAsList("exchange/test/test/" + exchangeName); - assertEquals("Exchange should be deleted", 0, queues.size()); - } - - public void testDeleteExchangeById() throws Exception - { - String exchangeName = getTestName(); - createExchange(exchangeName, "direct"); - Map echangeDetails = getRestTestHelper().getJsonAsSingletonList("exchange/test/test/" + exchangeName); - - int statusCode = getRestTestHelper().submitRequest("exchange/test/test?id=" + echangeDetails.get(Exchange.ID), "DELETE"); - - assertEquals("Unexpected response code", 200, statusCode); - List> queues = getRestTestHelper().getJsonAsList("exchange/test/test/" + exchangeName); - assertEquals("Exchange should be deleted", 0, queues.size()); - } - - public void testPutCreateQueueWithAttributes() throws Exception - { - String queueName = getTestQueueName(); - - Map attributes = new HashMap(); - attributes.put(Queue.ALERT_REPEAT_GAP, 1000); - attributes.put(Queue.ALERT_THRESHOLD_MESSAGE_AGE, 3600000); - attributes.put(Queue.ALERT_THRESHOLD_MESSAGE_SIZE, 1000000000); - attributes.put(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, 800); - attributes.put(Queue.MAXIMUM_DELIVERY_ATTEMPTS, 15); - attributes.put(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 2000000000); - attributes.put(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 1500000000); - - createQueue(queueName + "-standard", "standard", attributes); - - Map sortedQueueAttributes = new HashMap(); - sortedQueueAttributes.putAll(attributes); - sortedQueueAttributes.put(SortedQueue.SORT_KEY, "sortme"); - createQueue(queueName + "-sorted", "sorted", sortedQueueAttributes); - - Map priorityQueueAttributes = new HashMap(); - priorityQueueAttributes.putAll(attributes); - priorityQueueAttributes.put(PriorityQueue.PRIORITIES, 10); - createQueue(queueName + "-priority", "priority", priorityQueueAttributes); - - Map lvqQueueAttributes = new HashMap(); - lvqQueueAttributes.putAll(attributes); - lvqQueueAttributes.put(LastValueQueue.LVQ_KEY, "LVQ"); - createQueue(queueName + "-lvq", "lvq", lvqQueueAttributes); - - Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); - - @SuppressWarnings("unchecked") - List> queues = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE); - Map standardQueue = getRestTestHelper().find(Queue.NAME, queueName + "-standard" , queues); - Map sortedQueue = getRestTestHelper().find(Queue.NAME, queueName + "-sorted" , queues); - Map priorityQueue = getRestTestHelper().find(Queue.NAME, queueName + "-priority" , queues); - Map lvqQueue = getRestTestHelper().find(Queue.NAME, queueName + "-lvq" , queues); - - attributes.put(Queue.DURABLE, Boolean.TRUE); - Asserts.assertQueue(queueName + "-standard", "standard", standardQueue, attributes); - Asserts.assertQueue(queueName + "-sorted", "sorted", sortedQueue, attributes); - Asserts.assertQueue(queueName + "-priority", "priority", priorityQueue, attributes); - Asserts.assertQueue(queueName + "-lvq", "lvq", lvqQueue, attributes); - - assertEquals("Unexpected sorted key attribute", "sortme", sortedQueue.get(SortedQueue.SORT_KEY)); - assertEquals("Unexpected lvq key attribute", "LVQ", lvqQueue.get(LastValueQueue.LVQ_KEY)); - assertEquals("Unexpected priorities key attribute", 10, priorityQueue.get(PriorityQueue.PRIORITIES)); - } - - @SuppressWarnings("unchecked") - public void testCreateQueueWithDLQEnabled() throws Exception - { - String queueName = getTestQueueName(); - - Map attributes = new HashMap(); - attributes.put(AbstractVirtualHost.CREATE_DLQ_ON_CREATION, true); - - //verify the starting state - Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); - List> queues = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE); - List> exchanges = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_EXCHANGES_ATTRIBUTE); - - assertNull("queue "+ queueName + " should not have already been present", getRestTestHelper().find(Queue.NAME, queueName , queues)); - assertNull("queue "+ queueName + "_DLQ should not have already been present", getRestTestHelper().find(Queue.NAME, queueName + "_DLQ" , queues)); - assertNull("exchange should not have already been present", getRestTestHelper().find(Exchange.NAME, queueName + "_DLE" , exchanges)); - - //create the queue - createQueue(queueName, "standard", attributes); - - //verify the new queue, as well as the DLQueue and DLExchange have been created - hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); - queues = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE); - exchanges = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_EXCHANGES_ATTRIBUTE); - - Map queue = getRestTestHelper().find(Queue.NAME, queueName , queues); - Map dlqQueue = getRestTestHelper().find(Queue.NAME, queueName + "_DLQ" , queues); - Map dlExchange = getRestTestHelper().find(Exchange.NAME, queueName + "_DLE" , exchanges); - assertNotNull("queue should have been present", queue); - assertNotNull("queue should have been present", dlqQueue); - assertNotNull("exchange should have been present", dlExchange); - - //verify that the alternate exchange is set as expected on the new queue - Map queueAttributes = new HashMap(); - queueAttributes.put(Queue.ALTERNATE_EXCHANGE, queueName + "_DLE"); - - Asserts.assertQueue(queueName, "standard", queue, queueAttributes); - Asserts.assertQueue(queueName, "standard", queue, null); - } - - private void createExchange(String exchangeName, String exchangeType) throws IOException - { - Map queueData = new HashMap(); - queueData.put(Exchange.NAME, exchangeName); - queueData.put(Exchange.DURABLE, Boolean.TRUE); - queueData.put(Exchange.TYPE, exchangeType); - - int statusCode = getRestTestHelper().submitRequest("exchange/test/test/" + exchangeName, "PUT", queueData); - assertEquals("Unexpected response code", 201, statusCode); - } - - private void createQueue(String queueName, String queueType, Map attributes) throws Exception - { - int responseCode = tryCreateQueue(queueName, queueType, attributes); - assertEquals("Unexpected response code", 201, responseCode); - } - - private int tryCreateQueue(String queueName, String queueType, Map attributes) throws Exception - { - Map queueData = new HashMap(); - queueData.put(Queue.NAME, queueName); - queueData.put(Queue.DURABLE, Boolean.TRUE); - if (queueType != null) - { - queueData.put(Queue.TYPE, queueType); - } - if (attributes != null) - { - queueData.putAll(attributes); - } - - return getRestTestHelper().submitRequest("queue/test/test/" + queueName, "PUT", queueData); - } - - private String createVirtualHostNodeAndVirtualHost(String virtualHostName, - String virtualHostNodeType) throws Exception - { - String storePath = getStoreLocation(virtualHostName); - - Map nodeData = new HashMap<>(); - nodeData.put(VirtualHostNode.NAME, virtualHostName); - nodeData.put(VirtualHostNode.TYPE, virtualHostNodeType); - nodeData.put(JsonVirtualHostNode.STORE_PATH, storePath); - - getRestTestHelper().submitRequest("virtualhostnode/" + virtualHostName, "PUT", nodeData, HttpServletResponse.SC_CREATED); - - Map virtualhostData = new HashMap<>(); - virtualhostData.put(VirtualHost.NAME, virtualHostName); - virtualhostData.put(VirtualHost.TYPE, ProvidedStoreVirtualHostImpl.VIRTUAL_HOST_TYPE); - - getRestTestHelper().submitRequest("virtualhost/" + virtualHostName + "/" + virtualHostName, - "PUT", - virtualhostData, - HttpServletResponse.SC_CREATED); - - - return storePath; - } - - private String getStoreLocation(String hostName) - { - return new File(TMP_FOLDER, "store-" + hostName + "-" + System.currentTimeMillis()).getAbsolutePath(); - } - - private void assertNewVirtualHost(Map hostDetails) - { - @SuppressWarnings("unchecked") - Map statistics = (Map) hostDetails.get(Asserts.STATISTICS_ATTRIBUTE); - assertEquals("Unexpected number of exchanges in statistics", EXPECTED_EXCHANGES.length, - statistics.get("exchangeCount")); - assertEquals("Unexpected number of queues in statistics", 0, statistics.get("queueCount")); - assertEquals("Unexpected number of connections in statistics", 0, statistics.get("connectionCount")); - - @SuppressWarnings("unchecked") - List> exchanges = (List>) hostDetails.get(VIRTUALHOST_EXCHANGES_ATTRIBUTE); - assertEquals("Unexpected number of exchanges", EXPECTED_EXCHANGES.length, exchanges.size()); - RestTestHelper restTestHelper = getRestTestHelper(); - Asserts.assertDurableExchange("amq.fanout", "fanout", restTestHelper.find(Exchange.NAME, "amq.fanout", exchanges)); - Asserts.assertDurableExchange("amq.topic", "topic", restTestHelper.find(Exchange.NAME, "amq.topic", exchanges)); - Asserts.assertDurableExchange("amq.direct", "direct", restTestHelper.find(Exchange.NAME, "amq.direct", exchanges)); - Asserts.assertDurableExchange("amq.match", "headers", restTestHelper.find(Exchange.NAME, "amq.match", exchanges)); - - assertNull("Unexpected queues", hostDetails.get(VIRTUALHOST_QUEUES_ATTRIBUTE)); - assertNull("Unexpected connections", hostDetails.get(VIRTUALHOST_CONNECTIONS_ATTRIBUTE)); - } - - private void assertActualAndDesireStates(final String restUrl, - final String expectedDesiredState, - final String expectedActualState) throws IOException - { - Map virtualhost = getRestTestHelper().getJsonAsSingletonList(restUrl); - Asserts.assertActualAndDesiredState(expectedDesiredState, expectedActualState, virtualhost); - } - - private void assertQueueDepth(String restQueueUrl, String message, int expectedDepth) throws IOException - { - Map queueDetails = getRestTestHelper().getJsonAsSingletonList(restQueueUrl); - assertNotNull(queueDetails); - Map statistics = (Map) queueDetails.get(Asserts.STATISTICS_ATTRIBUTE); - assertNotNull(statistics); - - assertEquals(message, expectedDepth, statistics.get("queueDepthMessages")); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java deleted file mode 100644 index 8c4effd685..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java +++ /dev/null @@ -1,1009 +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.systest.rest.acl; - -import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.codehaus.jackson.JsonGenerationException; -import org.codehaus.jackson.map.JsonMappingException; -import org.apache.qpid.server.management.plugin.HttpManagement; -import org.apache.qpid.server.model.AccessControlProvider; -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.ExternalFileBasedAuthenticationManager; -import org.apache.qpid.server.model.GroupProvider; -import org.apache.qpid.server.model.KeyStore; -import org.apache.qpid.server.model.Plugin; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.Protocol; -import org.apache.qpid.server.model.TrustStore; -import org.apache.qpid.server.model.adapter.FileBasedGroupProvider; -import org.apache.qpid.server.model.adapter.FileBasedGroupProviderImpl; -import org.apache.qpid.server.security.FileKeyStore; -import org.apache.qpid.server.security.FileTrustStore; -import org.apache.qpid.server.security.access.FileAccessControlProviderConstants; -import org.apache.qpid.server.security.acl.AbstractACLTestCase; -import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager; -import org.apache.qpid.server.security.auth.manager.PlainPasswordDatabaseAuthenticationManager; -import org.apache.qpid.systest.rest.QpidRestTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.test.utils.TestFileUtils; -import org.apache.qpid.test.utils.TestSSLConstants; - -public class BrokerACLTest extends QpidRestTestCase -{ - private static final String ALLOWED_USER = "user1"; - private static final String DENIED_USER = "user2"; - private String _secondaryAclFileContent = ""; - - @Override - protected void customizeConfiguration() throws IOException - { - super.customizeConfiguration(); - getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER); - - AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", - "ACL ALLOW-LOG " + ALLOWED_USER + " CONFIGURE BROKER", - "ACL DENY-LOG " + DENIED_USER + " CONFIGURE BROKER", - "ACL DENY-LOG ALL ALL"); - - _secondaryAclFileContent = - "ACL ALLOW-LOG ALL ACCESS MANAGEMENT\n" + - "ACL ALLOW-LOG " + ALLOWED_USER + " CONFIGURE BROKER\n" + - "ACL DENY-LOG " + DENIED_USER + " CONFIGURE BROKER\n" + - "ACL DENY-LOG ALL ALL"; - - getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, - HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); - } - - /* === AuthenticationProvider === */ - - public void testCreateAuthenticationProviderAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String authenticationProviderName = getTestName(); - - int responseCode = createAuthenticationProvider(authenticationProviderName); - assertEquals("Provider creation should be allowed", 201, responseCode); - - assertAuthenticationProviderExists(authenticationProviderName); - } - - public void testCreateAuthenticationProviderDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - String authenticationProviderName = getTestName(); - - int responseCode = createAuthenticationProvider(authenticationProviderName); - assertEquals("Provider creation should be denied", 403, responseCode); - - assertAuthenticationProviderDoesNotExist(authenticationProviderName); - } - - public void testDeleteAuthenticationProviderAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String providerName = getTestName(); - - int responseCode = createAuthenticationProvider(providerName); - assertEquals("Provider creation should be allowed", 201, responseCode); - - assertAuthenticationProviderExists(providerName); - - responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "DELETE"); - assertEquals("Provider deletion should be allowed", 200, responseCode); - - assertAuthenticationProviderDoesNotExist(TEST2_VIRTUALHOST); - } - - public void testDeleteAuthenticationProviderDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String providerName = getTestName(); - - int responseCode = createAuthenticationProvider(providerName); - assertEquals("Provider creation should be allowed", 201, responseCode); - - assertAuthenticationProviderExists(providerName); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "DELETE"); - assertEquals("Provider deletion should be denied", 403, responseCode); - - assertAuthenticationProviderExists(providerName); - } - - public void testSetAuthenticationProviderAttributesAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String providerName = TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER; - - assertAuthenticationProviderExists(providerName); - - File file = TestFileUtils.createTempFile(this, ".users", "guest:guest\n" + ALLOWED_USER + ":" + ALLOWED_USER + "\n" - + DENIED_USER + ":" + DENIED_USER); - - Map attributes = new HashMap(); - attributes.put(AuthenticationProvider.NAME, providerName); - attributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE); - attributes.put(ExternalFileBasedAuthenticationManager.PATH, file.getAbsolutePath()); - - int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); - assertEquals("Setting of provider attribites should be allowed", 200, responseCode); - } - - public void testSetAuthenticationProviderAttributesDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String providerName = TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER; - - Map providerData = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + providerName); - - File file = TestFileUtils.createTempFile(this, ".users", "guest:guest\n" + ALLOWED_USER + ":" + ALLOWED_USER + "\n" - + DENIED_USER + ":" + DENIED_USER); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - Map attributes = new HashMap(); - attributes.put(AuthenticationProvider.NAME, providerName); - attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); - attributes.put(ExternalFileBasedAuthenticationManager.PATH, file.getAbsolutePath()); - - int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); - assertEquals("Setting of provider attribites should be allowed", 403, responseCode); - - Map provider = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + providerName); - assertEquals("Unexpected PATH attribute value", - providerData.get(ExternalFileBasedAuthenticationManager.PATH), - provider.get(ExternalFileBasedAuthenticationManager.PATH)); - } - - /* === Port === */ - - public void testCreatePortAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String portName = getTestName(); - - int responseCode = createPort(portName); - assertEquals("Port creation should be allowed", 201, responseCode); - - assertPortExists(portName); - } - - public void testCreatePortDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - String portName = getTestName(); - - int responseCode = createPort(portName); - assertEquals("Port creation should be denied", 403, responseCode); - - assertPortDoesNotExist(portName); - } - - public void testDeletePortDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; - assertPortExists(portName); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - int responseCode = getRestTestHelper().submitRequest("port/" + portName, "DELETE"); - assertEquals("Port deletion should be denied", 403, responseCode); - - assertPortExists(portName); - } - - public void testDeletePortAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; - assertPortExists(portName); - - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - int responseCode = getRestTestHelper().submitRequest("port/" + portName, "DELETE"); - assertEquals("Port deletion should be allowed", 200, responseCode); - - assertPortDoesNotExist(portName); - } - - // TODO: test disabled until allowing the updating of active ports outside management mode - public void DISABLED_testSetPortAttributesAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String portName = getTestName(); - - int responseCode = createPort(portName); - assertEquals("Port creation should be allowed", 201, responseCode); - - assertPortExists(portName); - - - Map attributes = new HashMap(); - attributes.put(Port.NAME, portName); - attributes.put(Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER); - responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); - assertEquals("Setting of port attribites should be allowed", 200, responseCode); - - Map port = getRestTestHelper().getJsonAsSingletonList("port/" + portName); - assertEquals("Unexpected authentication provider attribute value", ANONYMOUS_AUTHENTICATION_PROVIDER, - port.get(Port.AUTHENTICATION_PROVIDER)); - } - - public void testSetPortAttributesDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String portName = getTestName(); - - int responseCode = createPort(portName); - assertEquals("Port creation should be allowed", 201, responseCode); - - assertPortExists(portName); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - Map attributes = new HashMap(); - attributes.put(Port.NAME, portName); - attributes.put(Port.PROTOCOLS, Arrays.asList(Protocol.AMQP_0_9)); - attributes.put(Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER); - responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); - assertEquals("Setting of port attribites should be denied", 403, responseCode); - - Map port = getRestTestHelper().getJsonAsSingletonList("port/" + portName); - assertEquals("Unexpected authentication provider attribute value", - TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, port.get(Port.AUTHENTICATION_PROVIDER)); - } - - /* === KeyStore === */ - - public void testCreateKeyStoreAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String keyStoreName = getTestName(); - - assertKeyStoreExistence(keyStoreName, false); - - int responseCode = createKeyStore(keyStoreName, "app1"); - assertEquals("keyStore creation should be allowed", 201, responseCode); - - assertKeyStoreExistence(keyStoreName, true); - } - - public void testCreateKeyStoreDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - String keyStoreName = getTestName(); - - assertKeyStoreExistence(keyStoreName, false); - - int responseCode = createKeyStore(keyStoreName, "app1"); - assertEquals("keyStore creation should be allowed", 403, responseCode); - - assertKeyStoreExistence(keyStoreName, false); - } - - public void testDeleteKeyStoreDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String keyStoreName = getTestName(); - - assertKeyStoreExistence(keyStoreName, false); - - int responseCode = createKeyStore(keyStoreName, "app1"); - assertEquals("keyStore creation should be allowed", 201, responseCode); - - assertKeyStoreExistence(keyStoreName, true); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - responseCode = getRestTestHelper().submitRequest("keystore/" + keyStoreName, "DELETE"); - assertEquals("keystore deletion should be denied", 403, responseCode); - - assertKeyStoreExistence(keyStoreName, true); - } - - public void testDeleteKeyStoreAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String keyStoreName = getTestName(); - - assertKeyStoreExistence(keyStoreName, false); - - int responseCode = createKeyStore(keyStoreName, "app1"); - assertEquals("keyStore creation should be allowed", 201, responseCode); - - assertKeyStoreExistence(keyStoreName, true); - - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - responseCode = getRestTestHelper().submitRequest("keystore/" + keyStoreName, "DELETE"); - assertEquals("keystore deletion should be allowed", 200, responseCode); - - assertKeyStoreExistence(keyStoreName, false); - } - - public void testSetKeyStoreAttributesAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String keyStoreName = getTestName(); - String initialCertAlias = "app1"; - String updatedCertAlias = "app2"; - - assertKeyStoreExistence(keyStoreName, false); - - int responseCode = createKeyStore(keyStoreName, initialCertAlias); - assertEquals("keyStore creation should be allowed", 201, responseCode); - - assertKeyStoreExistence(keyStoreName, true); - Map keyStore = getRestTestHelper().getJsonAsSingletonList("keystore/" + keyStoreName); - assertEquals("Unexpected certificateAlias attribute value", initialCertAlias, keyStore.get(FileKeyStore.CERTIFICATE_ALIAS)); - - Map attributes = new HashMap(); - attributes.put(KeyStore.NAME, keyStoreName); - attributes.put(FileKeyStore.CERTIFICATE_ALIAS, updatedCertAlias); - responseCode = getRestTestHelper().submitRequest("keystore/" + keyStoreName, "PUT", attributes); - assertEquals("Setting of keystore attributes should be allowed", 200, responseCode); - - keyStore = getRestTestHelper().getJsonAsSingletonList("keystore/" + keyStoreName); - assertEquals("Unexpected certificateAlias attribute value", updatedCertAlias, keyStore.get(FileKeyStore.CERTIFICATE_ALIAS)); - } - - public void testSetKeyStoreAttributesDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String keyStoreName = getTestName(); - String initialCertAlias = "app1"; - String updatedCertAlias = "app2"; - - assertKeyStoreExistence(keyStoreName, false); - - int responseCode = createKeyStore(keyStoreName, initialCertAlias); - assertEquals("keyStore creation should be allowed", 201, responseCode); - - assertKeyStoreExistence(keyStoreName, true); - Map keyStore = getRestTestHelper().getJsonAsSingletonList("keystore/" + keyStoreName); - assertEquals("Unexpected certificateAlias attribute value", initialCertAlias, keyStore.get(FileKeyStore.CERTIFICATE_ALIAS)); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - Map attributes = new HashMap(); - attributes.put(KeyStore.NAME, keyStoreName); - attributes.put(FileKeyStore.CERTIFICATE_ALIAS, updatedCertAlias); - responseCode = getRestTestHelper().submitRequest("keystore/" + keyStoreName, "PUT", attributes); - assertEquals("Setting of keystore attributes should be denied", 403, responseCode); - - keyStore = getRestTestHelper().getJsonAsSingletonList("keystore/" + keyStoreName); - assertEquals("Unexpected certificateAlias attribute value", initialCertAlias, keyStore.get(FileKeyStore.CERTIFICATE_ALIAS)); - } - - /* === TrustStore === */ - - public void testCreateTrustStoreAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String trustStoreName = getTestName(); - - assertTrustStoreExistence(trustStoreName, false); - - int responseCode = createTrustStore(trustStoreName, false); - assertEquals("trustStore creation should be allowed", 201, responseCode); - - assertTrustStoreExistence(trustStoreName, true); - } - - public void testCreateTrustStoreDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - String trustStoreName = getTestName(); - - assertTrustStoreExistence(trustStoreName, false); - - int responseCode = createTrustStore(trustStoreName, false); - assertEquals("trustStore creation should be allowed", 403, responseCode); - - assertTrustStoreExistence(trustStoreName, false); - } - - public void testDeleteTrustStoreDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String trustStoreName = getTestName(); - - assertTrustStoreExistence(trustStoreName, false); - - int responseCode = createTrustStore(trustStoreName, false); - assertEquals("trustStore creation should be allowed", 201, responseCode); - - assertTrustStoreExistence(trustStoreName, true); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - responseCode = getRestTestHelper().submitRequest("truststore/" + trustStoreName, "DELETE"); - assertEquals("truststore deletion should be denied", 403, responseCode); - - assertTrustStoreExistence(trustStoreName, true); - } - - public void testDeleteTrustStoreAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String trustStoreName = getTestName(); - - assertTrustStoreExistence(trustStoreName, false); - - int responseCode = createTrustStore(trustStoreName, false); - assertEquals("trustStore creation should be allowed", 201, responseCode); - - assertTrustStoreExistence(trustStoreName, true); - - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - responseCode = getRestTestHelper().submitRequest("truststore/" + trustStoreName, "DELETE"); - assertEquals("truststore deletion should be allowed", 200, responseCode); - - assertTrustStoreExistence(trustStoreName, false); - } - - public void testSetTrustStoreAttributesAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String trustStoreName = getTestName(); - boolean initialPeersOnly = false; - boolean updatedPeersOnly = true; - - assertTrustStoreExistence(trustStoreName, false); - - int responseCode = createTrustStore(trustStoreName, initialPeersOnly); - assertEquals("trustStore creation should be allowed", 201, responseCode); - - assertTrustStoreExistence(trustStoreName, true); - Map trustStore = getRestTestHelper().getJsonAsSingletonList("truststore/" + trustStoreName); - assertEquals("Unexpected peersOnly attribute value", initialPeersOnly, trustStore.get(FileTrustStore.PEERS_ONLY)); - - Map attributes = new HashMap(); - attributes.put(TrustStore.NAME, trustStoreName); - attributes.put(FileTrustStore.PEERS_ONLY, updatedPeersOnly); - responseCode = getRestTestHelper().submitRequest("truststore/" + trustStoreName, "PUT", attributes); - assertEquals("Setting of truststore attributes should be allowed", 200, responseCode); - - trustStore = getRestTestHelper().getJsonAsSingletonList("truststore/" + trustStoreName); - assertEquals("Unexpected peersOnly attribute value", updatedPeersOnly, trustStore.get(FileTrustStore.PEERS_ONLY)); - } - - public void testSetTrustStoreAttributesDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String trustStoreName = getTestName(); - boolean initialPeersOnly = false; - boolean updatedPeersOnly = true; - - assertTrustStoreExistence(trustStoreName, false); - - int responseCode = createTrustStore(trustStoreName, initialPeersOnly); - assertEquals("trustStore creation should be allowed", 201, responseCode); - - assertTrustStoreExistence(trustStoreName, true); - Map trustStore = getRestTestHelper().getJsonAsSingletonList("truststore/" + trustStoreName); - assertEquals("Unexpected peersOnly attribute value", initialPeersOnly, trustStore.get(FileTrustStore.PEERS_ONLY)); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - Map attributes = new HashMap(); - attributes.put(TrustStore.NAME, trustStoreName); - attributes.put(FileTrustStore.PEERS_ONLY, updatedPeersOnly); - responseCode = getRestTestHelper().submitRequest("truststore/" + trustStoreName, "PUT", attributes); - assertEquals("Setting of truststore attributes should be denied", 403, responseCode); - - trustStore = getRestTestHelper().getJsonAsSingletonList("truststore/" + trustStoreName); - assertEquals("Unexpected peersOnly attribute value", initialPeersOnly, trustStore.get(FileTrustStore.PEERS_ONLY)); - } - - /* === Broker === */ - - public void testSetBrokerAttributesAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - int initialSessionCountLimit = 256; - int updatedSessionCountLimit = 299; - - Map brokerAttributes = getRestTestHelper().getJsonAsSingletonList("broker"); - assertEquals("Unexpected alert repeat gap", initialSessionCountLimit, - brokerAttributes.get(Broker.CONNECTION_SESSION_COUNT_LIMIT)); - - Map newAttributes = new HashMap(); - newAttributes.put(Broker.CONNECTION_SESSION_COUNT_LIMIT, updatedSessionCountLimit); - - int responseCode = getRestTestHelper().submitRequest("broker", "PUT", newAttributes); - assertEquals("Setting of port attribites should be allowed", 200, responseCode); - - brokerAttributes = getRestTestHelper().getJsonAsSingletonList("broker"); - assertEquals("Unexpected default alert repeat gap", updatedSessionCountLimit, - brokerAttributes.get(Broker.CONNECTION_SESSION_COUNT_LIMIT)); - } - - public void testSetBrokerAttributesDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - int initialSessionCountLimit = 256; - int updatedSessionCountLimit = 299; - - Map brokerAttributes = getRestTestHelper().getJsonAsSingletonList("broker"); - assertEquals("Unexpected alert repeat gap", initialSessionCountLimit, - brokerAttributes.get(Broker.CONNECTION_SESSION_COUNT_LIMIT)); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - Map newAttributes = new HashMap(); - newAttributes.put(Broker.CONNECTION_SESSION_COUNT_LIMIT, updatedSessionCountLimit); - - int responseCode = getRestTestHelper().submitRequest("broker", "PUT", newAttributes); - assertEquals("Setting of port attribites should be allowed", 403, responseCode); - - brokerAttributes = getRestTestHelper().getJsonAsSingletonList("broker"); - assertEquals("Unexpected default alert repeat gap", initialSessionCountLimit, - brokerAttributes.get(Broker.CONNECTION_SESSION_COUNT_LIMIT)); - } - - /* === GroupProvider === */ - - public void testCreateGroupProviderAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String groupProviderName = getTestName(); - - assertGroupProviderExistence(groupProviderName, false); - - int responseCode = createGroupProvider(groupProviderName); - assertEquals("Group provider creation should be allowed", 201, responseCode); - - assertGroupProviderExistence(groupProviderName, true); - } - - public void testCreateGroupProviderDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - String groupProviderName = getTestName(); - - assertGroupProviderExistence(groupProviderName, false); - - int responseCode = createGroupProvider(groupProviderName); - assertEquals("Group provider creation should be denied", 403, responseCode); - - assertGroupProviderExistence(groupProviderName, false); - } - - public void testDeleteGroupProviderDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String groupProviderName = getTestName(); - - assertGroupProviderExistence(groupProviderName, false); - - int responseCode = createGroupProvider(groupProviderName); - assertEquals("Group provider creation should be allowed", 201, responseCode); - - assertGroupProviderExistence(groupProviderName, true); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - responseCode = getRestTestHelper().submitRequest("groupprovider/" + groupProviderName, "DELETE"); - assertEquals("Group provider deletion should be denied", 403, responseCode); - - assertGroupProviderExistence(groupProviderName, true); - } - - public void testDeleteGroupProviderAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String groupProviderName = getTestName(); - - assertGroupProviderExistence(groupProviderName, false); - - int responseCode = createGroupProvider(groupProviderName); - assertEquals("Group provider creation should be allowed", 201, responseCode); - - assertGroupProviderExistence(groupProviderName, true); - - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - responseCode = getRestTestHelper().submitRequest("groupprovider/" + groupProviderName, "DELETE"); - assertEquals("Group provider deletion should be allowed", 200, responseCode); - - assertGroupProviderExistence(groupProviderName, false); - } - - public void testSetGroupProviderAttributesAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String groupProviderName = getTestName(); - - assertGroupProviderExistence(groupProviderName, false); - - int responseCode = createGroupProvider(groupProviderName); - assertEquals("Group provider creation should be allowed", 201, responseCode); - - assertGroupProviderExistence(groupProviderName, true); - - Map attributes = new HashMap(); - attributes.put(GroupProvider.NAME, groupProviderName); - attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); - attributes.put(FileBasedGroupProvider.PATH, "/path/to/file"); - responseCode = getRestTestHelper().submitRequest("groupprovider/" + groupProviderName, "PUT", attributes); - assertEquals("Setting of group provider attributes should be allowed but not supported", 409, responseCode); - } - - public void testSetGroupProviderAttributesDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String groupProviderName = getTestName(); - - assertGroupProviderExistence(groupProviderName, false); - - int responseCode = createGroupProvider(groupProviderName); - assertEquals("Group provider creation should be allowed", 201, responseCode); - - assertGroupProviderExistence(groupProviderName, true); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - Map attributes = new HashMap(); - attributes.put(GroupProvider.NAME, groupProviderName); - attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); - attributes.put(FileBasedGroupProvider.PATH, "/path/to/file"); - responseCode = getRestTestHelper().submitRequest("groupprovider/" + groupProviderName, "PUT", attributes); - assertEquals("Setting of group provider attributes should be denied", 403, responseCode); - } - - /* === AccessControlProvider === */ - - public void testCreateAccessControlProviderAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String accessControlProviderName = getTestName(); - - assertAccessControlProviderExistence(accessControlProviderName, false); - - int responseCode = createAccessControlProvider(accessControlProviderName); - assertEquals("Access control provider creation should be allowed", 201, responseCode); - - assertAccessControlProviderExistence(accessControlProviderName, true); - } - - public void testCreateAccessControlProviderDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - String accessControlProviderName = getTestName(); - - assertAccessControlProviderExistence(accessControlProviderName, false); - - int responseCode = createAccessControlProvider(accessControlProviderName); - assertEquals("Access control provider creation should be denied", 403, responseCode); - - assertAccessControlProviderExistence(accessControlProviderName, false); - } - - public void testDeleteAccessControlProviderDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String accessControlProviderName = getTestName(); - - assertAccessControlProviderExistence(accessControlProviderName, false); - - int responseCode = createAccessControlProvider(accessControlProviderName); - assertEquals("Access control provider creation should be allowed", 201, responseCode); - - assertAccessControlProviderExistence(accessControlProviderName, true); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "DELETE"); - assertEquals("Access control provider deletion should be denied", 403, responseCode); - - assertAccessControlProviderExistence(accessControlProviderName, true); - } - - public void testDeleteAccessControlProviderAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String accessControlProviderName = getTestName(); - - assertAccessControlProviderExistence(accessControlProviderName, false); - - int responseCode = createAccessControlProvider(accessControlProviderName); - assertEquals("Access control provider creation should be allowed", 201, responseCode); - - assertAccessControlProviderExistence(accessControlProviderName, true); - - responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "DELETE"); - assertEquals("Access control provider deletion should be allowed", 200, responseCode); - - assertAccessControlProviderExistence(accessControlProviderName, false); - } - - public void testSetAccessControlProviderAttributesAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String accessControlProviderName = getTestName(); - - assertAccessControlProviderExistence(accessControlProviderName, false); - - int responseCode = createAccessControlProvider(accessControlProviderName); - assertEquals("Access control provider creation should be allowed", 201, responseCode); - - assertAccessControlProviderExistence(accessControlProviderName, true); - - Map attributes = new HashMap(); - attributes.put(GroupProvider.NAME, accessControlProviderName); - attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); - attributes.put(FileBasedGroupProvider.PATH, "/path/to/file"); - responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "PUT", attributes); - assertEquals("Setting of access control provider attributes should be allowed", 200, responseCode); - } - - public void testSetAccessControlProviderAttributesDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String accessControlProviderName = getTestName(); - - assertAccessControlProviderExistence(accessControlProviderName, false); - - int responseCode = createAccessControlProvider(accessControlProviderName); - assertEquals("Access control provider creation should be allowed", 201, responseCode); - - assertAccessControlProviderExistence(accessControlProviderName, true); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - Map attributes = new HashMap(); - attributes.put(GroupProvider.NAME, accessControlProviderName); - attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); - attributes.put(FileBasedGroupProvider.PATH, "/path/to/file"); - responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "PUT", attributes); - assertEquals("Setting of access control provider attributes should be denied", 403, responseCode); - } - - /* === HTTP management === */ - - public void testSetHttpManagementAttributesAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - Map attributes = new HashMap(); - attributes.put(HttpManagement.NAME, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT); - attributes.put(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED, false); - attributes.put(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED, false); - attributes.put(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED, false); - attributes.put(HttpManagement.TIME_OUT, 10000); - - int responseCode = getRestTestHelper().submitRequest( - "plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, "PUT", attributes); - assertEquals("Setting of http management should be allowed", 200, responseCode); - - Map details = getRestTestHelper().getJsonAsSingletonList( - "plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT); - - assertEquals("Unexpected session timeout", 10000, details.get(HttpManagement.TIME_OUT)); - assertEquals("Unexpected http basic auth enabled", true, details.get(HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED)); - assertEquals("Unexpected https basic auth enabled", false, details.get(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED)); - assertEquals("Unexpected http sasl auth enabled", false, details.get(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED)); - assertEquals("Unexpected https sasl auth enabled", false, details.get(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED)); - } - - public void testSetHttpManagementAttributesDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - Map attributes = new HashMap(); - attributes.put(HttpManagement.NAME, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT); - attributes.put(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED, false); - attributes.put(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED, false); - attributes.put(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED, false); - attributes.put(HttpManagement.TIME_OUT, 10000); - - int responseCode = getRestTestHelper().submitRequest( - "plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, "PUT", attributes); - assertEquals("Setting of http management should be denied", 403, responseCode); - - Map details = getRestTestHelper().getJsonAsSingletonList( - "plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT); - - assertEquals("Unexpected session timeout", HttpManagement.DEFAULT_TIMEOUT_IN_SECONDS, - details.get(HttpManagement.TIME_OUT)); - assertEquals("Unexpected http basic auth enabled", true, - details.get(HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED)); - assertEquals("Unexpected https basic auth enabled", true, - details.get(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED)); - assertEquals("Unexpected http sasl auth enabled", true, - details.get(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED)); - assertEquals("Unexpected https sasl auth enabled", true, - details.get(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED)); - } - - /* === Utility Methods === */ - - private int createPort(String portName) throws Exception - { - Map attributes = new HashMap(); - attributes.put(Port.NAME, portName); - attributes.put(Port.PORT, findFreePort()); - attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); - - return getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); - } - - private void assertPortExists(String portName) throws Exception - { - assertPortExistence(portName, true); - } - - private void assertPortDoesNotExist(String portName) throws Exception - { - assertPortExistence(portName, false); - } - - private void assertPortExistence(String portName, boolean exists) throws Exception - { - List> hosts = getRestTestHelper().getJsonAsList("port/" + portName); - assertEquals("Unexpected result", exists, !hosts.isEmpty()); - } - - private void assertKeyStoreExistence(String keyStoreName, boolean exists) throws Exception - { - List> keyStores = getRestTestHelper().getJsonAsList("keystore/" + keyStoreName); - assertEquals("Unexpected result", exists, !keyStores.isEmpty()); - } - - private void assertTrustStoreExistence(String trustStoreName, boolean exists) throws Exception - { - List> trustStores = getRestTestHelper().getJsonAsList("truststore/" + trustStoreName); - assertEquals("Unexpected result", exists, !trustStores.isEmpty()); - } - - private int createAuthenticationProvider(String authenticationProviderName) throws Exception - { - Map attributes = new HashMap(); - attributes.put(AuthenticationProvider.NAME, authenticationProviderName); - attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); - - return getRestTestHelper().submitRequest("authenticationprovider/" + authenticationProviderName, "PUT", attributes); - } - - private void assertAuthenticationProviderDoesNotExist(String authenticationProviderName) throws Exception - { - assertAuthenticationProviderExistence(authenticationProviderName, false); - } - - private void assertAuthenticationProviderExists(String authenticationProviderName) throws Exception - { - assertAuthenticationProviderExistence(authenticationProviderName, true); - } - - private void assertAuthenticationProviderExistence(String authenticationProviderName, boolean exists) throws Exception - { - String path = "authenticationprovider/" + authenticationProviderName; - List> providers = getRestTestHelper().getJsonAsList(path); - assertEquals("Unexpected result", exists, !providers.isEmpty()); - } - - private int createKeyStore(String name, String certAlias) throws IOException, JsonGenerationException, JsonMappingException - { - Map keyStoreAttributes = new HashMap(); - keyStoreAttributes.put(KeyStore.NAME, name); - keyStoreAttributes.put(FileKeyStore.PATH, TestSSLConstants.KEYSTORE); - keyStoreAttributes.put(FileKeyStore.PASSWORD, TestSSLConstants.KEYSTORE_PASSWORD); - keyStoreAttributes.put(FileKeyStore.CERTIFICATE_ALIAS, certAlias); - - return getRestTestHelper().submitRequest("keystore/" + name, "PUT", keyStoreAttributes); - } - - private int createTrustStore(String name, boolean peersOnly) throws IOException, JsonGenerationException, JsonMappingException - { - Map trustStoreAttributes = new HashMap(); - trustStoreAttributes.put(TrustStore.NAME, name); - trustStoreAttributes.put(FileTrustStore.PATH, TestSSLConstants.KEYSTORE); - trustStoreAttributes.put(FileTrustStore.PASSWORD, TestSSLConstants.KEYSTORE_PASSWORD); - trustStoreAttributes.put(FileTrustStore.PEERS_ONLY, peersOnly); - - return getRestTestHelper().submitRequest("truststore/" + name, "PUT", trustStoreAttributes); - } - - private void assertGroupProviderExistence(String groupProviderName, boolean exists) throws Exception - { - String path = "groupprovider/" + groupProviderName; - List> providers = getRestTestHelper().getJsonAsList(path); - assertEquals("Unexpected result", exists, !providers.isEmpty()); - } - - private int createGroupProvider(String groupProviderName) throws Exception - { - File file = TestFileUtils.createTempFile(this, ".groups"); - Map attributes = new HashMap(); - attributes.put(GroupProvider.NAME, groupProviderName); - attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); - attributes.put(FileBasedGroupProvider.PATH, file.getAbsoluteFile()); - - return getRestTestHelper().submitRequest("groupprovider/" + groupProviderName, "PUT", attributes); - } - - private void assertAccessControlProviderExistence(String accessControlProviderName, boolean exists) throws Exception - { - String path = "accesscontrolprovider/" + accessControlProviderName; - List> providers = getRestTestHelper().getJsonAsList(path); - assertEquals("Unexpected result", exists, !providers.isEmpty()); - } - - private int createAccessControlProvider(String accessControlProviderName) throws Exception - { - File file = TestFileUtils.createTempFile(this, ".acl", _secondaryAclFileContent); - Map attributes = new HashMap(); - attributes.put(AccessControlProvider.NAME, accessControlProviderName); - attributes.put(AccessControlProvider.TYPE, FileAccessControlProviderConstants.ACL_FILE_PROVIDER_TYPE); - attributes.put(FileAccessControlProviderConstants.PATH, file.getAbsoluteFile()); - - return getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "PUT", attributes); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/ExchangeRestACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/ExchangeRestACLTest.java deleted file mode 100644 index b0c66cb3af..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/ExchangeRestACLTest.java +++ /dev/null @@ -1,244 +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.systest.rest.acl; - -import org.apache.qpid.server.management.plugin.HttpManagement; -import org.apache.qpid.server.model.Binding; -import org.apache.qpid.server.model.Exchange; -import org.apache.qpid.server.model.Plugin; -import org.apache.qpid.server.model.Queue; -import org.apache.qpid.server.security.acl.AbstractACLTestCase; -import org.apache.qpid.systest.rest.QpidRestTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.codehaus.jackson.JsonGenerationException; -import org.codehaus.jackson.map.JsonMappingException; - -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class ExchangeRestACLTest extends QpidRestTestCase -{ - private static final String ALLOWED_USER = "user1"; - private static final String DENIED_USER = "user2"; - private String _queueName; - private String _exchangeName; - private String _exchangeUrl; - - @Override - protected void customizeConfiguration() throws IOException - { - super.customizeConfiguration(); - getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER); - - AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", - "ACL ALLOW-LOG " + ALLOWED_USER + " CREATE QUEUE", - "ACL ALLOW-LOG " + ALLOWED_USER + " CREATE EXCHANGE", - "ACL DENY-LOG " + DENIED_USER + " CREATE EXCHANGE", - "ACL ALLOW-LOG " + ALLOWED_USER + " UPDATE EXCHANGE", - "ACL DENY-LOG " + DENIED_USER + " UPDATE EXCHANGE", - "ACL ALLOW-LOG " + ALLOWED_USER + " DELETE EXCHANGE", - "ACL DENY-LOG " + DENIED_USER + " DELETE EXCHANGE", - "ACL ALLOW-LOG " + ALLOWED_USER + " BIND EXCHANGE", - "ACL DENY-LOG " + DENIED_USER + " BIND EXCHANGE", - "ACL ALLOW-LOG " + ALLOWED_USER + " UNBIND EXCHANGE", - "ACL DENY-LOG " + DENIED_USER + " UNBIND EXCHANGE", - "ACL DENY-LOG ALL ALL"); - - getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, - HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); - } - - @Override - public void setUp() throws Exception - { - super.setUp(); - _queueName = getTestQueueName(); - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - Map queueData = new HashMap(); - queueData.put(Queue.NAME, _queueName); - queueData.put(Queue.DURABLE, Boolean.TRUE); - int status = getRestTestHelper().submitRequest("queue/test/test/" + _queueName, "PUT", queueData); - assertEquals("Unexpected status", 201, status); - - _exchangeName = getTestName(); - _exchangeUrl = "exchange/test/test/" + _exchangeName; - } - - public void testCreateExchangeAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - int responseCode = createExchange(); - assertEquals("Exchange creation should be allowed", 201, responseCode); - - assertExchangeExists(); - } - - public void testCreateExchangeDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - int responseCode = createExchange(); - assertEquals("Exchange creation should be denied", 403, responseCode); - - assertExchangeDoesNotExist(); - } - - public void testDeleteExchangeAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - int responseCode = createExchange(); - assertEquals("Exchange creation should be allowed", 201, responseCode); - - assertExchangeExists(); - - - responseCode = getRestTestHelper().submitRequest(_exchangeUrl, "DELETE"); - assertEquals("Exchange deletion should be allowed", 200, responseCode); - - assertExchangeDoesNotExist(); - } - - public void testDeleteExchangeDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - int responseCode = createExchange(); - assertEquals("Exchange creation should be allowed", 201, responseCode); - - assertExchangeExists(); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - responseCode = getRestTestHelper().submitRequest(_exchangeUrl, "DELETE"); - assertEquals("Exchange deletion should be denied", 403, responseCode); - - assertExchangeExists(); - } - - public void testSetExchangeAttributesAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - int responseCode = createExchange(); - - assertExchangeExists(); - - Map attributes = new HashMap(); - attributes.put(Exchange.NAME, _exchangeName); - attributes.put(Exchange.ALTERNATE_EXCHANGE, "my-alternate-exchange"); - - responseCode = getRestTestHelper().submitRequest(_exchangeUrl, "PUT", attributes); - assertEquals("Setting of exchange attribites should be allowed but it is currently unsupported", 409, responseCode); - } - - public void testSetExchangeAttributesDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - int responseCode = createExchange(); - assertExchangeExists(); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - Map attributes = new HashMap(); - attributes.put(Exchange.NAME, _exchangeName); - attributes.put(Exchange.ALTERNATE_EXCHANGE, "my-alternate-exchange"); - - responseCode = getRestTestHelper().submitRequest(_exchangeUrl, "PUT", attributes); - assertEquals("Setting of exchange attribites should be allowed", 403, responseCode); - } - - public void testBindToExchangeAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String bindingName = getTestName(); - int responseCode = createBinding(bindingName); - assertEquals("Binding creation should be allowed", 201, responseCode); - - assertBindingExists(bindingName); - } - - public void testBindToExchangeDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - String bindingName = getTestName(); - int responseCode = createBinding(bindingName); - assertEquals("Binding creation should be denied", 403, responseCode); - - assertBindingDoesNotExist(bindingName); - } - - private int createExchange() throws Exception - { - Map attributes = new HashMap(); - attributes.put(Exchange.NAME, _exchangeName); - attributes.put(Exchange.TYPE, "direct"); - return getRestTestHelper().submitRequest(_exchangeUrl, "PUT", attributes); - } - - private void assertExchangeDoesNotExist() throws Exception - { - assertExchangeExistence(false); - } - - private void assertExchangeExists() throws Exception - { - assertExchangeExistence(true); - } - - private void assertExchangeExistence(boolean exists) throws Exception - { - List> exchanges = getRestTestHelper().getJsonAsList(_exchangeUrl); - assertEquals("Unexpected result", exists, !exchanges.isEmpty()); - } - - private int createBinding(String bindingName) throws IOException, JsonGenerationException, JsonMappingException - { - Map attributes = new HashMap(); - attributes.put(Binding.NAME, bindingName); - attributes.put(Binding.QUEUE, _queueName); - attributes.put(Binding.EXCHANGE, "amq.direct"); - - int responseCode = getRestTestHelper().submitRequest("binding/test/test/amq.direct/" + _queueName + "/" + bindingName, "PUT", attributes); - return responseCode; - } - - private void assertBindingDoesNotExist(String bindingName) throws Exception - { - assertBindingExistence(bindingName, false); - } - - private void assertBindingExists(String bindingName) throws Exception - { - assertBindingExistence(bindingName, true); - } - - private void assertBindingExistence(String bindingName, boolean exists) throws Exception - { - List> bindings = getRestTestHelper().getJsonAsList("binding/test/test/amq.direct/" + _queueName + "/" + bindingName); - assertEquals("Unexpected result", exists, !bindings.isEmpty()); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java deleted file mode 100644 index 3ebfafb8da..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java +++ /dev/null @@ -1,193 +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.systest.rest.acl; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.Map; -import java.util.Properties; - -import javax.servlet.http.HttpServletResponse; - -import org.apache.qpid.server.management.plugin.HttpManagement; -import org.apache.qpid.server.model.Plugin; -import org.apache.qpid.server.security.acl.AbstractACLTestCase; -import org.apache.qpid.systest.rest.QpidRestTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class GroupRestACLTest extends QpidRestTestCase -{ - private static final String FILE_GROUP_MANAGER = TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE; - - private static final String ALLOWED_GROUP = "allowedGroup"; - private static final String DENIED_GROUP = "deniedGroup"; - private static final String OTHER_GROUP = "otherGroup"; - - private static final String ALLOWED_USER = "webadmin"; - private static final String DENIED_USER = "admin"; - private static final String OTHER_USER = "admin"; - - private File _groupFile; - - @Override - public void setUp() throws Exception - { - _groupFile = createTemporaryGroupFile(); - getBrokerConfiguration().addGroupFileConfiguration(_groupFile.getAbsolutePath()); - - //DONT call super.setUp(), the tests will start the broker after configuring it - } - - @Override - protected void customizeConfiguration() throws IOException - { - super.customizeConfiguration(); - getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); - } - - @Override - public void tearDown() throws Exception - { - super.tearDown(); - - if (_groupFile != null) - { - if (_groupFile.exists()) - { - _groupFile.delete(); - } - } - } - - private File createTemporaryGroupFile() throws Exception - { - File groupFile = File.createTempFile("group", "grp"); - groupFile.deleteOnExit(); - - Properties props = new Properties(); - props.put(ALLOWED_GROUP + ".users", ALLOWED_USER); - props.put(DENIED_GROUP + ".users", DENIED_USER); - props.put(OTHER_GROUP + ".users", OTHER_USER); - - props.store(new FileOutputStream(groupFile), "test group file"); - - return groupFile; - } - - public void testCreateGroup() throws Exception - { - AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", - "ACL ALLOW-LOG " + ALLOWED_GROUP + " CREATE GROUP", - "ACL DENY-LOG " + DENIED_GROUP + " CREATE GROUP"); - - //Start the broker with the custom config - super.setUp(); - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - Map data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); - getRestTestHelper().assertNumberOfGroups(data, 3); - - getRestTestHelper().createGroup("newGroup", FILE_GROUP_MANAGER); - - data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); - getRestTestHelper().assertNumberOfGroups(data, 4); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - getRestTestHelper().createGroup("anotherNewGroup", FILE_GROUP_MANAGER, HttpServletResponse.SC_FORBIDDEN); - - data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); - getRestTestHelper().assertNumberOfGroups(data, 4); - } - - public void testDeleteGroup() throws Exception - { - AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", - "ACL ALLOW-LOG " + ALLOWED_GROUP + " DELETE GROUP", - "ACL DENY-LOG " + DENIED_GROUP + " DELETE GROUP"); - - //Start the broker with the custom config - super.setUp(); - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - Map data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); - getRestTestHelper().assertNumberOfGroups(data, 3); - - getRestTestHelper().removeGroup(OTHER_GROUP, FILE_GROUP_MANAGER, HttpServletResponse.SC_FORBIDDEN); - - data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); - getRestTestHelper().assertNumberOfGroups(data, 3); - - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - getRestTestHelper().removeGroup(OTHER_GROUP, FILE_GROUP_MANAGER); - - data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); - getRestTestHelper().assertNumberOfGroups(data, 2); - } - - public void testUpdateGroupAddMember() throws Exception - { - AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", - "ACL ALLOW-LOG " + ALLOWED_GROUP + " UPDATE GROUP", - "ACL DENY-LOG " + DENIED_GROUP + " UPDATE GROUP"); - - //Start the broker with the custom config - super.setUp(); - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - assertNumberOfGroupMembers(OTHER_GROUP, 1); - - getRestTestHelper().createNewGroupMember(FILE_GROUP_MANAGER, OTHER_GROUP, "newGroupMember", HttpServletResponse.SC_FORBIDDEN); - assertNumberOfGroupMembers(OTHER_GROUP, 1); - - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - getRestTestHelper().createNewGroupMember(FILE_GROUP_MANAGER, OTHER_GROUP, "newGroupMember"); - assertNumberOfGroupMembers(OTHER_GROUP, 2); - } - - public void testUpdateGroupDeleteMember() throws Exception - { - AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", - "ACL ALLOW-LOG " + ALLOWED_GROUP + " UPDATE GROUP", - "ACL DENY-LOG " + DENIED_GROUP + " UPDATE GROUP"); - - //Start the broker with the custom config - super.setUp(); - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - assertNumberOfGroupMembers(OTHER_GROUP, 1); - - getRestTestHelper().removeMemberFromGroup(FILE_GROUP_MANAGER, OTHER_GROUP, OTHER_USER, HttpServletResponse.SC_FORBIDDEN); - assertNumberOfGroupMembers(OTHER_GROUP, 1); - - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - getRestTestHelper().removeMemberFromGroup(FILE_GROUP_MANAGER, OTHER_GROUP, OTHER_USER); - assertNumberOfGroupMembers(OTHER_GROUP, 0); - } - - private void assertNumberOfGroupMembers(String groupName, int expectedNumberOfMembers) throws IOException - { - Map group = getRestTestHelper().getJsonAsSingletonList("group/" + FILE_GROUP_MANAGER + "/" + groupName); - getRestTestHelper().assertNumberOfGroupMembers(group, expectedNumberOfMembers); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/LogViewerACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/LogViewerACLTest.java deleted file mode 100644 index 1b14e3b10e..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/LogViewerACLTest.java +++ /dev/null @@ -1,99 +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.systest.rest.acl; - -import java.io.IOException; - -import org.apache.qpid.server.management.plugin.HttpManagement; -import org.apache.qpid.server.model.Plugin; -import org.apache.qpid.server.security.acl.AbstractACLTestCase; -import org.apache.qpid.systest.rest.QpidRestTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class LogViewerACLTest extends QpidRestTestCase -{ - private static final String ALLOWED_USER = "user1"; - private static final String DENIED_USER = "user2"; - - @Override - protected void customizeConfiguration() throws IOException - { - super.customizeConfiguration(); - getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER); - - AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", - "ACL ALLOW-LOG " + ALLOWED_USER + " ACCESS_LOGS BROKER", - "ACL DENY-LOG " + DENIED_USER + " ACCESS_LOGS BROKER", - "ACL DENY-LOG ALL ALL"); - - getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, - HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); - } - - public void testGetLogRecordsAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - int responseCode = getRestTestHelper().submitRequest("/service/logrecords", "GET"); - assertEquals("Access to log records should be allowed", 200, responseCode); - } - - public void testGetLogRecordsDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - int responseCode = getRestTestHelper().submitRequest("/service/logrecords", "GET"); - assertEquals("Access to log records should be denied", 403, responseCode); - } - - public void testGetLogFilesAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - int responseCode = getRestTestHelper().submitRequest("/service/logfilenames", "GET"); - assertEquals("Access to log files should be allowed", 200, responseCode); - } - - public void testGetLogFilesDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - int responseCode = getRestTestHelper().submitRequest("/service/logfilenames", "GET"); - assertEquals("Access to log files should be denied", 403, responseCode); - } - - public void testDownloadLogFileAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - int responseCode = getRestTestHelper().submitRequest("/service/logfile?l=appender%2fqpid.log", "GET"); - assertEquals("Access to log files should be allowed", 404, responseCode); - } - - public void testDownloadLogFileDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - int responseCode = getRestTestHelper().submitRequest("/service/logfile?l=appender%2fqpid.log", "GET"); - assertEquals("Access to log files should be denied", 403, responseCode); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/QueueRestACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/QueueRestACLTest.java deleted file mode 100644 index a123de2984..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/QueueRestACLTest.java +++ /dev/null @@ -1,188 +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.systest.rest.acl; - -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.qpid.server.management.plugin.HttpManagement; -import org.apache.qpid.server.model.Plugin; -import org.apache.qpid.server.model.Queue; -import org.apache.qpid.server.security.acl.AbstractACLTestCase; -import org.apache.qpid.systest.rest.QpidRestTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class QueueRestACLTest extends QpidRestTestCase -{ - private static final String ALLOWED_USER = "user1"; - private static final String DENIED_USER = "user2"; - private String _queueUrl; - private String _queueName; - - @Override - public void setUp() throws Exception - { - super.setUp(); - _queueName = getTestName(); - _queueUrl = "queue/test/test/" + _queueName; - } - - @Override - protected void customizeConfiguration() throws IOException - { - super.customizeConfiguration(); - getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER); - - AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", - "ACL ALLOW-LOG " + ALLOWED_USER + " CREATE QUEUE", - "ACL DENY-LOG " + DENIED_USER + " CREATE QUEUE", - "ACL ALLOW-LOG " + ALLOWED_USER + " UPDATE QUEUE", - "ACL DENY-LOG " + DENIED_USER + " UPDATE QUEUE", - "ACL ALLOW-LOG " + ALLOWED_USER + " DELETE QUEUE", - "ACL DENY-LOG " + DENIED_USER + " DELETE QUEUE", - "ACL DENY-LOG ALL ALL"); - - getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, - HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); - } - - public void testCreateQueueAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - int responseCode = createQueue(); - assertEquals("Queue creation should be allowed", 201, responseCode); - - assertQueueExists(); - } - - public void testCreateQueueDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - int responseCode = createQueue(); - assertEquals("Queue creation should be denied", 403, responseCode); - - assertQueueDoesNotExist(); - } - - public void testDeleteQueueAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - int responseCode = createQueue(); - assertEquals("Queue creation should be allowed", 201, responseCode); - - assertQueueExists(); - - responseCode = getRestTestHelper().submitRequest(_queueUrl, "DELETE"); - assertEquals("Queue deletion should be allowed", 200, responseCode); - - assertQueueDoesNotExist(); - } - - public void testDeleteQueueDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - int responseCode = createQueue(); - assertEquals("Queue creation should be allowed", 201, responseCode); - - assertQueueExists(); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - responseCode = getRestTestHelper().submitRequest(_queueUrl, "DELETE"); - assertEquals("Queue deletion should be denied", 403, responseCode); - - assertQueueExists(); - } - - - - public void testSetQueueAttributesAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - int responseCode = createQueue(); - - assertQueueExists(); - - Map attributes = new HashMap(); - attributes.put(Queue.NAME, _queueName); - attributes.put(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 100000); - attributes.put(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 80000); - - responseCode = getRestTestHelper().submitRequest(_queueUrl, "PUT", attributes); - assertEquals("Setting of queue attribites should be allowed", 200, responseCode); - - Map queueData = getRestTestHelper().getJsonAsSingletonList(_queueUrl); - assertEquals("Unexpected " + Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 100000, queueData.get(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES) ); - assertEquals("Unexpected " + Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 80000, queueData.get(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES) ); - } - - public void testSetQueueAttributesDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - int responseCode = createQueue(); - assertQueueExists(); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - Map attributes = new HashMap(); - attributes.put(Queue.NAME, _queueName); - attributes.put(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 100000); - attributes.put(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 80000); - - responseCode = getRestTestHelper().submitRequest(_queueUrl, "PUT", attributes); - assertEquals("Setting of queue attribites should be allowed", 403, responseCode); - - Map queueData = getRestTestHelper().getJsonAsSingletonList(_queueUrl); - assertEquals("Unexpected " + Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 0, queueData.get(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES) ); - assertEquals("Unexpected " + Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 0, queueData.get(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES) ); - } - - private int createQueue() throws Exception - { - Map attributes = new HashMap(); - attributes.put(Queue.NAME, _queueName); - - return getRestTestHelper().submitRequest(_queueUrl, "PUT", attributes); - } - - private void assertQueueDoesNotExist() throws Exception - { - assertQueueExistence(false); - } - - private void assertQueueExists() throws Exception - { - assertQueueExistence(true); - } - - private void assertQueueExistence(boolean exists) throws Exception - { - List> queues = getRestTestHelper().getJsonAsList(_queueUrl); - assertEquals("Unexpected result", exists, !queues.isEmpty()); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/UserPreferencesRestACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/UserPreferencesRestACLTest.java deleted file mode 100644 index b626b821c8..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/UserPreferencesRestACLTest.java +++ /dev/null @@ -1,197 +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.systest.rest.acl; - -import java.io.File; -import java.io.IOException; -import java.net.URLEncoder; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.qpid.server.management.plugin.HttpManagement; -import org.apache.qpid.server.model.Plugin; -import org.apache.qpid.server.model.PreferencesProvider; -import org.apache.qpid.server.model.adapter.FileSystemPreferencesProvider; -import org.apache.qpid.server.security.acl.AbstractACLTestCase; -import org.apache.qpid.systest.rest.QpidRestTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.test.utils.TestFileUtils; - -public class UserPreferencesRestACLTest extends QpidRestTestCase -{ - - private static final String REST_USER_PREFERENCES_BASE_URL = "/service/userpreferences"; - private static final String ALLOWED_USER = "webadmin"; - private static final String DENIED_USER = "admin"; - private static final String TEST_USER_PREFERENCES_GET_URL = REST_USER_PREFERENCES_BASE_URL + "/" - + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/%s"; - - private File _preferencesProviderFile; - - public void setUp() throws Exception - { - _preferencesProviderFile = TestFileUtils.createTempFile(this, ".prefs.json", - "{\"webadmin\":{\"language\": \"en\", \"saveTabs\":true}," + " \"admin\":{\"language\": \"fr\", \"saveTabs\":false}" - + "}"); - super.setUp(); - } - - public void tearDown() throws Exception - { - try - { - super.tearDown(); - } - finally - { - if (_preferencesProviderFile != null) - { - _preferencesProviderFile.delete(); - } - } - } - - @Override - protected void customizeConfiguration() throws IOException - { - super.customizeConfiguration(); - getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER); - - AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", "ACL ALLOW-LOG " + ALLOWED_USER - + " UPDATE USER", "ACL DENY-LOG " + DENIED_USER + " UPDATE USER", "ACL DENY-LOG ALL ALL"); - - TestBrokerConfiguration brokerConfiguration = getBrokerConfiguration(); - brokerConfiguration.setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, - HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); - - Map attributes = new HashMap(); - attributes.put(PreferencesProvider.NAME, "test"); - attributes.put(PreferencesProvider.TYPE, FileSystemPreferencesProvider.PROVIDER_TYPE); - attributes.put(FileSystemPreferencesProvider.PATH, _preferencesProviderFile.getAbsolutePath()); - brokerConfiguration - .addPreferencesProviderConfiguration(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, attributes); - } - - public void testListUsersWithPreferencesAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - List> users = getRestTestHelper().getJsonAsList(REST_USER_PREFERENCES_BASE_URL); - assertUsers(users); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - users = getRestTestHelper().getJsonAsList(REST_USER_PREFERENCES_BASE_URL); - assertUsers(users); - } - - public void testViewOtherUserPreferencesAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String userPreferencesUrl = String.format(TEST_USER_PREFERENCES_GET_URL, DENIED_USER); - Map preferences = getRestTestHelper().getJsonAsMap(userPreferencesUrl); - assertEquals("Unexpected number of preferences", 2, preferences.size()); - assertEquals("Unexpected language preference", "fr", preferences.get("language")); - assertEquals("Unexpected saveTabs preference", false, preferences.get("saveTabs")); - } - - public void testViewOtherUserPreferencesDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - int responseCode = getRestTestHelper().submitRequest( - "/service/userpreferences?user=" - + URLEncoder.encode(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + ALLOWED_USER, "UTF-8"), - "DELETE"); - assertEquals("Preferences deletion should be denied", 403, responseCode); - } - - public void testDeleteOtherUserPreferencesAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String userPreferencesUrl = String.format(TEST_USER_PREFERENCES_GET_URL, DENIED_USER); - Map preferences = getRestTestHelper().getJsonAsMap(userPreferencesUrl); - assertEquals("Unexpected number of preferences", 2, preferences.size()); - assertEquals("Unexpected language preference", "fr", preferences.get("language")); - assertEquals("Unexpected saveTabs preference", false, preferences.get("saveTabs")); - - int responseCode = getRestTestHelper().submitRequest( - "/service/userpreferences?user=" - + URLEncoder.encode(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + DENIED_USER, "UTF-8"), - "DELETE"); - assertEquals("Preferences deletion should be allowed", 200, responseCode); - - preferences = getRestTestHelper().getJsonAsMap(userPreferencesUrl); - assertEquals("Unexpected number of preferences after deletion", 0, preferences.size()); - } - - public void testDeleteOtherUserPreferencesDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String userPreferencesUrl = String.format(TEST_USER_PREFERENCES_GET_URL, ALLOWED_USER); - Map preferences = getRestTestHelper().getJsonAsMap(userPreferencesUrl); - assertEquals("Unexpected number of preferences", 2, preferences.size()); - assertEquals("Unexpected language preference", "en", preferences.get("language")); - assertEquals("Unexpected saveTabs preference", true, preferences.get("saveTabs")); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - int responseCode = getRestTestHelper().submitRequest( - "/service/userpreferences?user=" - + URLEncoder.encode(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + ALLOWED_USER, "UTF-8"), - "DELETE"); - assertEquals("Preferences deletion should be denied", 403, responseCode); - - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - preferences = getRestTestHelper().getJsonAsMap(userPreferencesUrl); - assertEquals("Unexpected number of preferences after deletion", 2, preferences.size()); - } - - - private void assertUsers(List> users) - { - assertEquals("Unexpected number of users", 2, users.size()); - Map webadmin = findUser("webadmin", users); - assertEquals("Unexpected name", "webadmin", webadmin.get("name")); - assertEquals("Unexpected authentication provider", TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, webadmin.get("authenticationProvider")); - Map admin = findUser("admin", users); - assertEquals("Unexpected name", "admin", admin.get("name")); - assertEquals("Unexpected authentication provider", TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, admin.get("authenticationProvider")); - } - - private Map findUser(String name, List> users) - { - for (Map user : users) - { - if (name.equals(user.get("name"))) - { - return user; - } - } - return null; - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java deleted file mode 100644 index d80c8e14b2..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java +++ /dev/null @@ -1,195 +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.systest.rest.acl; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import javax.servlet.http.HttpServletResponse; - -import org.codehaus.jackson.JsonParseException; -import org.codehaus.jackson.map.JsonMappingException; - -import org.apache.qpid.server.management.plugin.HttpManagement; -import org.apache.qpid.server.model.Plugin; -import org.apache.qpid.server.security.acl.AbstractACLTestCase; -import org.apache.qpid.systest.rest.QpidRestTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class UserRestACLTest extends QpidRestTestCase -{ - private static final String ALLOWED_GROUP = "allowedGroup"; - private static final String DENIED_GROUP = "deniedGroup"; - private static final String OTHER_GROUP = "otherGroup"; - - private static final String ALLOWED_USER = "webadmin"; - private static final String DENIED_USER = "admin"; - private static final String OTHER_USER = "other"; - - private File _groupFile; - - @Override - public void setUp() throws Exception - { - _groupFile = createTemporaryGroupFile(); - getBrokerConfiguration().addGroupFileConfiguration(_groupFile.getAbsolutePath()); - - getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER, OTHER_USER); - - //DONT call super.setUp(), the tests will start the broker after configuring it - } - - @Override - protected void customizeConfiguration() throws IOException - { - super.customizeConfiguration(); - getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); - } - - @Override - public void tearDown() throws Exception - { - super.tearDown(); - - if (_groupFile != null) - { - if (_groupFile.exists()) - { - _groupFile.delete(); - } - } - } - - private File createTemporaryGroupFile() throws Exception - { - File groupFile = File.createTempFile("group", "grp"); - groupFile.deleteOnExit(); - - Properties props = new Properties(); - props.put(ALLOWED_GROUP + ".users", ALLOWED_USER); - props.put(DENIED_GROUP + ".users", DENIED_USER); - props.put(OTHER_GROUP + ".users", OTHER_USER); - - props.store(new FileOutputStream(groupFile), "test group file"); - - return groupFile; - } - - public void testAddUser() throws Exception - { - AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", - "ACL ALLOW-LOG " + ALLOWED_GROUP + " CREATE USER", - "ACL DENY-LOG " + DENIED_GROUP + " CREATE USER"); - - //Start the broker with the custom config - super.setUp(); - - String newUser = "newUser"; - String password = "password"; - - assertUserDoesNotExist(newUser); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - getRestTestHelper().createOrUpdateUser(newUser, password, HttpServletResponse.SC_FORBIDDEN); - assertUserDoesNotExist(newUser); - - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - getRestTestHelper().createOrUpdateUser(newUser, password); - assertUserExists(newUser); - } - - public void testDeleteUser() throws Exception - { - AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", - "ACL ALLOW-LOG " + ALLOWED_GROUP + " DELETE USER", - "ACL DENY-LOG " + DENIED_GROUP + " DELETE USER"); - - //Start the broker with the custom config - super.setUp(); - - assertUserExists(OTHER_USER); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - getRestTestHelper().removeUser(OTHER_USER, HttpServletResponse.SC_FORBIDDEN); - assertUserExists(OTHER_USER); - - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - getRestTestHelper().removeUser(OTHER_USER); - assertUserDoesNotExist(OTHER_USER); - } - - public void testUpdateUser() throws Exception - { - AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", - "ACL ALLOW-LOG " + ALLOWED_GROUP + " UPDATE USER", - "ACL DENY-LOG " + DENIED_GROUP + " UPDATE USER"); - - //Start the broker with the custom config - super.setUp(); - - String newPassword = "newPassword"; - - checkPassword(OTHER_USER, OTHER_USER, true); - - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - getRestTestHelper().createOrUpdateUser(OTHER_USER, newPassword, HttpServletResponse.SC_FORBIDDEN); - - checkPassword(OTHER_USER, newPassword, false); - - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - getRestTestHelper().createOrUpdateUser(OTHER_USER, newPassword, HttpServletResponse.SC_OK); // expect SC_OK rather than the default SC_CREATED - - checkPassword(OTHER_USER, newPassword, true); - checkPassword(OTHER_USER, OTHER_USER, false); - } - - private void checkPassword(String username, String password, boolean passwordExpectedToBeCorrect) throws IOException - { - getRestTestHelper().setUsernameAndPassword(username, password); - - int responseCode = getRestTestHelper().submitRequest("user/" - + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/", "GET", (byte[])null); - boolean passwordIsCorrect = responseCode == HttpServletResponse.SC_OK; - - assertEquals(passwordExpectedToBeCorrect, passwordIsCorrect); - } - - private void assertUserDoesNotExist(String newUser) throws JsonParseException, JsonMappingException, IOException - { - String path = "user/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + newUser; - List> userDetailsList = getRestTestHelper().getJsonAsList(path); - assertTrue(userDetailsList.isEmpty()); - } - - private void assertUserExists(String username) throws IOException - { - String path = "user/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + username; - Map userDetails = getRestTestHelper().getJsonAsSingletonList(path); - - assertEquals( - "User returned by " + path + " should have name=" + username + ". The returned JSON was: " + userDetails, - username, - userDetails.get("name")); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/VirtualHostACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/VirtualHostACLTest.java deleted file mode 100644 index 45123325e3..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/VirtualHostACLTest.java +++ /dev/null @@ -1,145 +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.systest.rest.acl; - -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.servlet.http.HttpServletResponse; - -import org.apache.qpid.server.management.plugin.HttpManagement; -import org.apache.qpid.server.model.Plugin; -import org.apache.qpid.server.model.VirtualHost; -import org.apache.qpid.server.model.VirtualHostNode; -import org.apache.qpid.server.security.acl.AbstractACLTestCase; -import org.apache.qpid.server.virtualhost.ProvidedStoreVirtualHostImpl; -import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNode; -import org.apache.qpid.systest.rest.QpidRestTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class VirtualHostACLTest extends QpidRestTestCase -{ - private static final String VHN_WITHOUT_VH = "myVhnWithoutVh"; - - private static final String ALLOWED_USER = "user1"; - private static final String DENIED_USER = "user2"; - - @Override - protected void customizeConfiguration() throws IOException - { - super.customizeConfiguration(); - getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER); - - AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", - "ACL ALLOW-LOG " + ALLOWED_USER + " ALL VIRTUALHOST", - "ACL DENY-LOG " + DENIED_USER + " ALL VIRTUALHOST", - "ACL DENY-LOG ALL ALL"); - - getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, - HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); - - Map virtualHostNodeAttributes = new HashMap<>(); - virtualHostNodeAttributes.put(VirtualHostNode.NAME, VHN_WITHOUT_VH); - virtualHostNodeAttributes.put(VirtualHostNode.TYPE, getTestProfileVirtualHostNodeType()); - // TODO need better way to determine the VHN's optional attributes - virtualHostNodeAttributes.put(JsonVirtualHostNode.STORE_PATH, getStoreLocation(VHN_WITHOUT_VH)); - - getBrokerConfiguration().addObjectConfiguration(VirtualHostNode.class, virtualHostNodeAttributes); - } - - public void testCreateVirtualHostAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String hostName = getTestName(); - - int responseCode = createVirtualHost(VHN_WITHOUT_VH, hostName); - assertEquals("Virtual host creation should be allowed", HttpServletResponse.SC_CREATED, responseCode); - - assertVirtualHostExists(VHN_WITHOUT_VH, hostName); - } - - public void testCreateVirtualHostDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - String hostName = getTestName(); - - int responseCode = createVirtualHost(VHN_WITHOUT_VH, hostName); - assertEquals("Virtual host creation should be denied", HttpServletResponse.SC_FORBIDDEN, responseCode); - - assertVirtualHostDoesNotExist(VHN_WITHOUT_VH, hostName); - } - - public void testDeleteVirtualHostDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - getRestTestHelper().submitRequest("virtualhost/" + TEST2_VIRTUALHOST + "/" + TEST2_VIRTUALHOST, "DELETE", HttpServletResponse.SC_FORBIDDEN); - - assertVirtualHostExists(TEST2_VIRTUALHOST, TEST2_VIRTUALHOST); - } - - public void testUpdateVirtualHostDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - Map attributes = new HashMap<>(); - attributes.put(VirtualHost.NAME, TEST2_VIRTUALHOST); - attributes.put(VirtualHost.DESCRIPTION, "new description"); - - getRestTestHelper().submitRequest("virtualhost/" + TEST2_VIRTUALHOST + "/" + TEST2_VIRTUALHOST, "PUT", attributes, HttpServletResponse.SC_FORBIDDEN); - } - - /* === Utility Methods === */ - - private int createVirtualHost(final String testVirtualHostNode, String virtualHostName) throws Exception - { - Map data = new HashMap<>(); - data.put(VirtualHost.NAME, virtualHostName); - data.put(VirtualHost.TYPE, ProvidedStoreVirtualHostImpl.VIRTUAL_HOST_TYPE); - - return getRestTestHelper().submitRequest("virtualhost/" + testVirtualHostNode + "/" + virtualHostName, "PUT", data); - } - - private void assertVirtualHostDoesNotExist(final String virtualHostNodeName, String virtualHostName) throws Exception - { - assertVirtualHostExistence(virtualHostNodeName, virtualHostName, false); - } - - private void assertVirtualHostExists(final String virtualHostNodeName, String virtualHostName) throws Exception - { - assertVirtualHostExistence(virtualHostNodeName, virtualHostName, true); - } - - private void assertVirtualHostExistence(final String virtualHostNodeName, String virtualHostName, boolean exists) throws Exception - { - List> hosts = getRestTestHelper().getJsonAsList("virtualhost/" + virtualHostNodeName + "/" + virtualHostName); - assertEquals("Node " + virtualHostName + (exists ? " does not exist" : " exists"), exists, !hosts.isEmpty()); - } - - private String getStoreLocation(String hostName) - { - return new File(TMP_FOLDER, "store-" + hostName + "-" + System.currentTimeMillis()).getAbsolutePath(); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/VirtualHostNodeACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/VirtualHostNodeACLTest.java deleted file mode 100644 index 4809962f24..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/VirtualHostNodeACLTest.java +++ /dev/null @@ -1,155 +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.systest.rest.acl; - -import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.servlet.http.HttpServletResponse; - -import org.codehaus.jackson.JsonGenerationException; -import org.codehaus.jackson.map.JsonMappingException; - -import org.apache.qpid.server.management.plugin.HttpManagement; -import org.apache.qpid.server.model.AccessControlProvider; -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.ExternalFileBasedAuthenticationManager; -import org.apache.qpid.server.model.GroupProvider; -import org.apache.qpid.server.model.KeyStore; -import org.apache.qpid.server.model.Plugin; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.Protocol; -import org.apache.qpid.server.model.TrustStore; -import org.apache.qpid.server.model.VirtualHostNode; -import org.apache.qpid.server.model.adapter.FileBasedGroupProvider; -import org.apache.qpid.server.model.adapter.FileBasedGroupProviderImpl; -import org.apache.qpid.server.security.FileKeyStore; -import org.apache.qpid.server.security.FileTrustStore; -import org.apache.qpid.server.security.access.FileAccessControlProviderConstants; -import org.apache.qpid.server.security.acl.AbstractACLTestCase; -import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager; -import org.apache.qpid.server.security.auth.manager.PlainPasswordDatabaseAuthenticationManager; -import org.apache.qpid.server.virtualhost.memory.MemoryVirtualHost; -import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNode; -import org.apache.qpid.systest.rest.QpidRestTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; -import org.apache.qpid.test.utils.TestFileUtils; -import org.apache.qpid.test.utils.TestSSLConstants; - -public class VirtualHostNodeACLTest extends QpidRestTestCase -{ - private static final String TEST_VIRTUAL_HOST_NODE = "myTestVirtualHostNode"; - private static final String ALLOWED_USER = "user1"; - private static final String DENIED_USER = "user2"; - - @Override - protected void customizeConfiguration() throws IOException - { - super.customizeConfiguration(); - getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER); - - AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", - "ACL ALLOW-LOG " + ALLOWED_USER + " ALL VIRTUALHOSTNODE", - "ACL DENY-LOG " + DENIED_USER + " ALL VIRTUALHOSTNODE", - "ACL DENY-LOG ALL ALL"); - - getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, - HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); - - Map virtualHostNodeAttributes = new HashMap<>(); - virtualHostNodeAttributes.put(VirtualHostNode.NAME, TEST_VIRTUAL_HOST_NODE); - virtualHostNodeAttributes.put(VirtualHostNode.TYPE, getTestProfileVirtualHostNodeType()); - // TODO need better way to determine the VHN's optional attributes - virtualHostNodeAttributes.put(JsonVirtualHostNode.STORE_PATH, getStoreLocation(TEST_VIRTUAL_HOST_NODE)); - - - getBrokerConfiguration().addObjectConfiguration(VirtualHostNode.class, virtualHostNodeAttributes); - } - - public void testCreateVirtualHostNodeAllowed() throws Exception - { - getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); - - String hostName = getTestName(); - - int responseCode = createVirtualHostNode(hostName); - assertEquals("Virtual host node creation should be allowed", HttpServletResponse.SC_CREATED, responseCode); - - assertVirtualHostNodeExists(hostName); - } - - public void testCreateVirtualHostNodeDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - - String hostName = getTestName(); - - int responseCode = createVirtualHostNode(hostName); - assertEquals("Virtual host node creation should be denied", HttpServletResponse.SC_FORBIDDEN, responseCode); - - assertVirtualHostNodeDoesNotExist(hostName); - } - - public void testDeleteVirtualHostNodeDenied() throws Exception - { - getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); - getRestTestHelper().submitRequest("virtualhostnode/" + TEST_VIRTUAL_HOST_NODE, "DELETE", HttpServletResponse.SC_FORBIDDEN); - - assertVirtualHostNodeExists(TEST_VIRTUAL_HOST_NODE); - } - - /* === Utility Methods === */ - - private int createVirtualHostNode(String virtualHostNodeName) throws Exception - { - Map data = new HashMap<>(); - data.put(VirtualHostNode.NAME, virtualHostNodeName); - data.put(VirtualHostNode.TYPE, getTestProfileVirtualHostNodeType()); - data.put(JsonVirtualHostNode.STORE_PATH, getStoreLocation(virtualHostNodeName)); - - return getRestTestHelper().submitRequest("virtualhostnode/" + virtualHostNodeName, "PUT", data); - } - - private void assertVirtualHostNodeDoesNotExist(String name) throws Exception - { - assertVirtualHostNodeExistence(name, false); - } - - private void assertVirtualHostNodeExists(String name) throws Exception - { - assertVirtualHostNodeExistence(name, true); - } - - private void assertVirtualHostNodeExistence(String name, boolean exists) throws Exception - { - List> hosts = getRestTestHelper().getJsonAsList("virtualhostnode/" + name); - assertEquals("Node " + name + (exists ? " does not exist" : " exists"), exists, !hosts.isEmpty()); - } - - private String getStoreLocation(String hostName) - { - return new File(TMP_FOLDER, "store-" + hostName + "-" + System.currentTimeMillis()).getAbsolutePath(); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/CloseOnNoRouteForMandatoryMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/CloseOnNoRouteForMandatoryMessageTest.java deleted file mode 100644 index deb8e4f12b..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/CloseOnNoRouteForMandatoryMessageTest.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.test.client; - -import java.util.HashMap; -import java.util.Map; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.IllegalStateException; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.naming.NamingException; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.jms.ConnectionURL; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.url.URLSyntaxException; - -/** - * Tests the broker's connection-closing behaviour when it receives an unroutable message - * on a transactional session. - * - * @see ImmediateAndMandatoryPublishingTest for more general tests of mandatory and immediate publishing - */ -public class CloseOnNoRouteForMandatoryMessageTest extends QpidBrokerTestCase -{ - private static final Logger _logger = Logger.getLogger(CloseOnNoRouteForMandatoryMessageTest.class); - - private Connection _connection; - private UnroutableMessageTestExceptionListener _testExceptionListener = new UnroutableMessageTestExceptionListener(); - - @Override - public void setUp() throws Exception - { - super.setUp(); - } - - public void testNoRoute_brokerClosesConnection() throws Exception - { - createConnectionWithCloseWhenNoRoute(true); - - Session transactedSession = _connection.createSession(true, Session.SESSION_TRANSACTED); - String testQueueName = getTestQueueName(); - MessageProducer mandatoryProducer = ((AMQSession) transactedSession).createProducer( - transactedSession.createQueue(testQueueName), - true, // mandatory - false); // immediate - - Message message = transactedSession.createMessage(); - mandatoryProducer.send(message); - try - { - transactedSession.commit(); - fail("Expected exception not thrown"); - } - catch (IllegalStateException ise) - { - _logger.debug("Caught exception", ise); - //The session was marked closed even before we had a chance to call commit on it - assertTrue("ISE did not indicate closure", ise.getMessage().contains("closed")); - } - catch(JMSException e) - { - _logger.debug("Caught exception", e); - _testExceptionListener.assertNoRoute(e, testQueueName); - } - _testExceptionListener.assertReceivedNoRoute(testQueueName); - - forgetConnection(_connection); - } - - public void testCloseOnNoRouteWhenExceptionMessageLengthIsGreater255() throws Exception - { - createConnectionWithCloseWhenNoRoute(true); - - AMQSession transactedSession = (AMQSession) _connection.createSession(true, Session.SESSION_TRANSACTED); - - StringBuilder longExchangeName = getLongExchangeName(); - - AMQShortString exchangeName = new AMQShortString(longExchangeName.toString()); - transactedSession.declareExchange(exchangeName, new AMQShortString("direct"), false); - - Destination testQueue = new AMQQueue(exchangeName, getTestQueueName()); - MessageProducer mandatoryProducer = transactedSession.createProducer( - testQueue, - true, // mandatory - false); // immediate - - Message message = transactedSession.createMessage(); - mandatoryProducer.send(message); - try - { - transactedSession.commit(); - fail("Expected exception not thrown"); - } - catch (IllegalStateException ise) - { - _logger.debug("Caught exception", ise); - //The session was marked closed even before we had a chance to call commit on it - assertTrue("ISE did not indicate closure", ise.getMessage().contains("closed")); - } - catch (JMSException e) - { - _logger.debug("Caught exception", e); - AMQException noRouteException = (AMQException) e.getLinkedException(); - assertNotNull("AMQException should be linked to JMSException", noRouteException); - - assertEquals(AMQConstant.NO_ROUTE, noRouteException.getErrorCode()); - String expectedMessage = "Error: No route for message [Exchange: " + longExchangeName.substring(0, 220) + "..."; - assertEquals("Unexpected exception message: " + noRouteException.getMessage(), expectedMessage, - noRouteException.getMessage()); - } - finally - { - forgetConnection(_connection); - } - } - - public void testNoRouteMessageReurnedWhenExceptionMessageLengthIsGreater255() throws Exception - { - createConnectionWithCloseWhenNoRoute(false); - - AMQSession transactedSession = (AMQSession) _connection.createSession(true, Session.SESSION_TRANSACTED); - - StringBuilder longExchangeName = getLongExchangeName(); - - AMQShortString exchangeName = new AMQShortString(longExchangeName.toString()); - transactedSession.declareExchange(exchangeName, new AMQShortString("direct"), false); - - AMQQueue testQueue = new AMQQueue(exchangeName, getTestQueueName()); - MessageProducer mandatoryProducer = transactedSession.createProducer( - testQueue, - true, // mandatory - false); // immediate - - Message message = transactedSession.createMessage(); - mandatoryProducer.send(message); - transactedSession.commit(); - _testExceptionListener.assertReceivedReturnedMessageWithLongExceptionMessage(message, testQueue); - } - - private StringBuilder getLongExchangeName() - { - StringBuilder longExchangeName = new StringBuilder(); - for (int i = 0; i < 50; i++) - { - longExchangeName.append("abcde"); - } - return longExchangeName; - } - - public void testNoRouteForNonMandatoryMessage_brokerKeepsConnectionOpenAndCallsExceptionListener() throws Exception - { - createConnectionWithCloseWhenNoRoute(true); - - Session transactedSession = _connection.createSession(true, Session.SESSION_TRANSACTED); - String testQueueName = getTestQueueName(); - MessageProducer nonMandatoryProducer = ((AMQSession) transactedSession).createProducer( - transactedSession.createQueue(testQueueName), - false, // mandatory - false); // immediate - - Message message = transactedSession.createMessage(); - nonMandatoryProducer.send(message); - - // should succeed - the message is simply discarded - transactedSession.commit(); - - _testExceptionListener.assertNoException(); - } - - - public void testNoRouteOnNonTransactionalSession_brokerKeepsConnectionOpenAndCallsExceptionListener() throws Exception - { - createConnectionWithCloseWhenNoRoute(true); - - Session nonTransactedSession = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - String testQueueName = getTestQueueName(); - MessageProducer mandatoryProducer = ((AMQSession) nonTransactedSession).createProducer( - nonTransactedSession.createQueue(testQueueName), - true, // mandatory - false); // immediate - - Message message = nonTransactedSession.createMessage(); - mandatoryProducer.send(message); - - // should succeed - the message is asynchronously bounced back to the exception listener - message.acknowledge(); - - _testExceptionListener.assertReceivedNoRouteWithReturnedMessage(message, getTestQueueName()); - } - - public void testClientDisablesCloseOnNoRoute_brokerKeepsConnectionOpenAndCallsExceptionListener() throws Exception - { - createConnectionWithCloseWhenNoRoute(false); - - Session transactedSession = _connection.createSession(true, Session.SESSION_TRANSACTED); - String testQueueName = getTestQueueName(); - MessageProducer mandatoryProducer = ((AMQSession) transactedSession).createProducer( - transactedSession.createQueue(testQueueName), - true, // mandatory - false); // immediate - - Message message = transactedSession.createMessage(); - mandatoryProducer.send(message); - transactedSession.commit(); - _testExceptionListener.assertReceivedNoRouteWithReturnedMessage(message, getTestQueueName()); - } - - private void createConnectionWithCloseWhenNoRoute(boolean closeWhenNoRoute) throws URLSyntaxException, NamingException, JMSException - { - Map options = new HashMap(); - options.put(ConnectionURL.OPTIONS_CLOSE_WHEN_NO_ROUTE, Boolean.toString(closeWhenNoRoute)); - _connection = getConnectionWithOptions(options); - _connection.setExceptionListener(_testExceptionListener); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java deleted file mode 100644 index fa36d73283..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.client; - -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -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 java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - - -public class DupsOkTest extends QpidBrokerTestCase -{ - - private Queue _queue; - private static final int MSG_COUNT = 100; - private CountDownLatch _awaitCompletion = new CountDownLatch(1); - - public void setUp() throws Exception - { - super.setUp(); - - _queue = (Queue) getInitialContext().lookup("queue"); - - - //Declare the queue - Connection consumerConnection = getConnection(); - consumerConnection.createSession(false,Session.AUTO_ACKNOWLEDGE).createConsumer(_queue).close(); - - //Create Producer put some messages on the queue - Connection producerConnection = getConnection(); - - producerConnection.start(); - - Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - MessageProducer producer = producerSession.createProducer(_queue); - - for (int count = 1; count <= MSG_COUNT; count++) - { - Message msg = producerSession.createTextMessage("Message " + count); - msg.setIntProperty("count", count); - producer.send(msg); - } - - producerConnection.close(); - } - - /** - * This test sends x messages and receives them with an async consumer. - * Waits for all messages to be received or for 60 s - * and checks whether the queue is empty. - * - * @throws Exception - */ - public void testDupsOK() throws Exception - { - //Create Client - Connection clientConnection = getConnection(); - - final Session clientSession = clientConnection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE); - - MessageConsumer consumer = clientSession.createConsumer(_queue); - - assertEquals("The queue should have msgs at start", MSG_COUNT, ((AMQSession) clientSession).getQueueDepth((AMQDestination) _queue)); - - clientConnection.start(); - - consumer.setMessageListener(new MessageListener() - { - private int _msgCount = 0; - - public void onMessage(Message message) - { - _msgCount++; - if (message == null) - { - fail("Should not get null messages"); - } - - if (message instanceof TextMessage) - { - try - { - if (message.getIntProperty("count") == MSG_COUNT) - { - try - { - if(_msgCount != MSG_COUNT) - { - assertEquals("Wrong number of messages seen.", MSG_COUNT, _msgCount); - } - } - finally - { - //This is the last message so release test. - _awaitCompletion.countDown(); - } - } - } - catch (JMSException e) - { - fail("Unable to get int property 'count'"); - } - } - else - { - fail("Got wrong message type"); - } - } - }); - - try - { - if (!_awaitCompletion.await(120, TimeUnit.SECONDS)) - { - fail("Test did not complete in 120 seconds"); - } - } - catch (InterruptedException e) - { - fail("Unable to wait for test completion"); - throw e; - } - - //Close consumer to give broker time to process in bound Acks. As The main thread will be released while - // before the dispatcher has sent the ack back to the broker. - consumer.close(); - - clientSession.close(); - - final Session clientSession2 = clientConnection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE); - - assertEquals("The queue should have 0 msgs left", 0, ((AMQSession) clientSession2).getQueueDepth((AMQDestination) _queue)); - - clientConnection.close(); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/FlowControlTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/FlowControlTest.java deleted file mode 100644 index f8bc051be7..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/FlowControlTest.java +++ /dev/null @@ -1,220 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.test.client; - -import org.apache.log4j.Logger; - -import org.apache.qpid.client.AMQSession_0_8; -import org.apache.qpid.client.message.AbstractJMSMessage; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.BytesMessage; -import javax.jms.Connection; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.Session; - -public class FlowControlTest extends QpidBrokerTestCase -{ - private static final Logger _logger = Logger.getLogger(FlowControlTest.class); - - private Connection _clientConnection; - private Session _clientSession; - private Queue _queue; - - /** - * Simply - * - * @throws Exception - */ - public void testBasicBytesFlowControl() throws Exception - { - _queue = (Queue) getInitialContext().lookup("queue"); - - //Create Client - _clientConnection = getConnection(); - - _clientConnection.start(); - - _clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - //Ensure _queue is created - _clientSession.createConsumer(_queue).close(); - - Connection producerConnection = getConnection(); - - producerConnection.start(); - - Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageProducer producer = producerSession.createProducer(_queue); - - BytesMessage m1 = producerSession.createBytesMessage(); - m1.writeBytes(new byte[128]); - m1.setIntProperty("msg", 1); - producer.send(m1); - BytesMessage m2 = producerSession.createBytesMessage(); - m2.writeBytes(new byte[128]); - m2.setIntProperty("msg", 2); - producer.send(m2); - BytesMessage m3 = producerSession.createBytesMessage(); - m3.writeBytes(new byte[256]); - m3.setIntProperty("msg", 3); - producer.send(m3); - - producer.close(); - producerSession.close(); - producerConnection.close(); - - Connection consumerConnection = getConnection(); - Session consumerSession = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); - ((AMQSession_0_8) consumerSession).setPrefetchLimits(0, 256); - MessageConsumer recv = consumerSession.createConsumer(_queue); - consumerConnection.start(); - - Message r1 = recv.receive(RECEIVE_TIMEOUT); - assertNotNull("First message not received", r1); - assertEquals("Messages in wrong order", 1, r1.getIntProperty("msg")); - - Message r2 = recv.receive(RECEIVE_TIMEOUT); - assertNotNull("Second message not received", r2); - assertEquals("Messages in wrong order", 2, r2.getIntProperty("msg")); - - Message r3 = recv.receive(RECEIVE_TIMEOUT); - assertNull("Third message incorrectly delivered", r3); - - ((AbstractJMSMessage)r1).acknowledgeThis(); - - r3 = recv.receive(RECEIVE_TIMEOUT); - assertNull("Third message incorrectly delivered", r3); - - ((AbstractJMSMessage)r2).acknowledgeThis(); - - r3 = recv.receive(RECEIVE_TIMEOUT); - assertNotNull("Third message not received", r3); - assertEquals("Messages in wrong order", 3, r3.getIntProperty("msg")); - - ((AbstractJMSMessage)r3).acknowledgeThis(); - consumerConnection.close(); - } - - public void testTwoConsumersBytesFlowControl() throws Exception - { - _queue = (Queue) getInitialContext().lookup("queue"); - - //Create Client - _clientConnection = getConnection(); - - _clientConnection.start(); - - _clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - //Ensure _queue is created - _clientSession.createConsumer(_queue).close(); - - Connection producerConnection = getConnection(); - - producerConnection.start(); - - Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageProducer producer = producerSession.createProducer(_queue); - - BytesMessage m1 = producerSession.createBytesMessage(); - m1.writeBytes(new byte[128]); - m1.setIntProperty("msg", 1); - producer.send(m1); - BytesMessage m2 = producerSession.createBytesMessage(); - m2.writeBytes(new byte[256]); - m2.setIntProperty("msg", 2); - producer.send(m2); - BytesMessage m3 = producerSession.createBytesMessage(); - m3.writeBytes(new byte[128]); - m3.setIntProperty("msg", 3); - producer.send(m3); - - producer.close(); - producerSession.close(); - producerConnection.close(); - - Connection consumerConnection = getConnection(); - Session consumerSession1 = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); - ((AMQSession_0_8) consumerSession1).setPrefetchLimits(0, 256); - MessageConsumer recv1 = consumerSession1.createConsumer(_queue); - - consumerConnection.start(); - - Message r1 = recv1.receive(RECEIVE_TIMEOUT); - assertNotNull("First message not received", r1); - assertEquals("Messages in wrong order", 1, r1.getIntProperty("msg")); - - Message r2 = recv1.receive(RECEIVE_TIMEOUT); - assertNull("Second message incorrectly delivered", r2); - - Session consumerSession2 = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); - ((AMQSession_0_8) consumerSession2).setPrefetchLimits(0, 256); - MessageConsumer recv2 = consumerSession2.createConsumer(_queue); - - r2 = recv2.receive(RECEIVE_TIMEOUT); - assertNotNull("Second message not received", r2); - assertEquals("Messages in wrong order", 2, r2.getIntProperty("msg")); - - Message r3 = recv2.receive(RECEIVE_TIMEOUT); - assertNull("Third message incorrectly delivered", r3); - - r3 = recv1.receive(RECEIVE_TIMEOUT); - assertNotNull("Third message not received", r3); - assertEquals("Messages in wrong order", 3, r3.getIntProperty("msg")); - - r2.acknowledge(); - r3.acknowledge(); - recv1.close(); - recv2.close(); - consumerSession1.close(); - consumerSession2.close(); - consumerConnection.close(); - - } - - public static void main(String args[]) throws Throwable - { - FlowControlTest test = new FlowControlTest(); - - int run = 0; - while (true) - { - System.err.println("Test Run:" + ++run); - Thread.sleep(1000); - try - { - test.startBroker(); - test.testBasicBytesFlowControl(); - - Thread.sleep(1000); - } - finally - { - test.stopBroker(); - } - } - } -} - diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/ImmediateAndMandatoryPublishingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/ImmediateAndMandatoryPublishingTest.java deleted file mode 100644 index d012b9abbb..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/ImmediateAndMandatoryPublishingTest.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.test.client; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.Topic; - -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -/** - * @see CloseOnNoRouteForMandatoryMessageTest for related tests - */ -public class ImmediateAndMandatoryPublishingTest extends QpidBrokerTestCase -{ - private Connection _connection; - private UnroutableMessageTestExceptionListener _testExceptionListener = new UnroutableMessageTestExceptionListener(); - - @Override - public void setUp() throws Exception - { - getBrokerConfiguration().setBrokerAttribute(Broker.CONNECTION_CLOSE_WHEN_NO_ROUTE, false); - super.setUp(); - _connection = getConnection(); - _connection.setExceptionListener(_testExceptionListener); - } - - public void testPublishP2PWithNoConsumerAndImmediateOnAndAutoAck() throws Exception - { - publishIntoExistingDestinationWithNoConsumerAndImmediateOn(Session.AUTO_ACKNOWLEDGE, false); - } - - public void testPublishP2PWithNoConsumerAndImmediateOnAndTx() throws Exception - { - publishIntoExistingDestinationWithNoConsumerAndImmediateOn(Session.SESSION_TRANSACTED, false); - } - - public void testPublishPubSubWithDisconnectedDurableSubscriberAndImmediateOnAndAutoAck() throws Exception - { - publishIntoExistingDestinationWithNoConsumerAndImmediateOn(Session.AUTO_ACKNOWLEDGE, true); - } - - public void testPublishPubSubWithDisconnectedDurableSubscriberAndImmediateOnAndTx() throws Exception - { - publishIntoExistingDestinationWithNoConsumerAndImmediateOn(Session.SESSION_TRANSACTED, true); - } - - public void testPublishP2PIntoNonExistingDesitinationWithMandatoryOnAutoAck() throws Exception - { - publishWithMandatoryOnImmediateOff(Session.AUTO_ACKNOWLEDGE, false); - } - - public void testPublishP2PIntoNonExistingDesitinationWithMandatoryOnAndTx() throws Exception - { - publishWithMandatoryOnImmediateOff(Session.SESSION_TRANSACTED, false); - } - - public void testPubSubMandatoryAutoAck() throws Exception - { - publishWithMandatoryOnImmediateOff(Session.AUTO_ACKNOWLEDGE, true); - } - - public void testPubSubMandatoryTx() throws Exception - { - publishWithMandatoryOnImmediateOff(Session.SESSION_TRANSACTED, true); - } - - public void testP2PNoMandatoryAutoAck() throws Exception - { - publishWithMandatoryOffImmediateOff(Session.AUTO_ACKNOWLEDGE, false); - } - - public void testP2PNoMandatoryTx() throws Exception - { - publishWithMandatoryOffImmediateOff(Session.SESSION_TRANSACTED, false); - } - - public void testPubSubWithImmediateOnAndAutoAck() throws Exception - { - consumerCreateAndClose(true, false); - - Message message = produceMessage(Session.AUTO_ACKNOWLEDGE, true, false, true); - _testExceptionListener.assertReceivedNoRouteWithReturnedMessage(message, getTestQueueName()); - } - - private void publishIntoExistingDestinationWithNoConsumerAndImmediateOn(int acknowledgeMode, boolean pubSub) - throws JMSException, InterruptedException - { - consumerCreateAndClose(pubSub, true); - - Message message = produceMessage(acknowledgeMode, pubSub, false, true); - - _testExceptionListener.assertReceivedNoConsumersWithReturnedMessage(message); - } - - private void publishWithMandatoryOnImmediateOff(int acknowledgeMode, boolean pubSub) throws JMSException, - InterruptedException - { - Message message = produceMessage(acknowledgeMode, pubSub, true, false); - _testExceptionListener.assertReceivedNoRouteWithReturnedMessage(message, getTestQueueName()); - } - - private void publishWithMandatoryOffImmediateOff(int acknowledgeMode, boolean pubSub) throws JMSException, - InterruptedException - { - produceMessage(acknowledgeMode, pubSub, false, false); - - _testExceptionListener.assertNoException(); - } - - private void consumerCreateAndClose(boolean pubSub, boolean durable) throws JMSException - { - Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Destination destination = null; - MessageConsumer consumer = null; - if (pubSub) - { - destination = session.createTopic(getTestQueueName()); - if (durable) - { - consumer = session.createDurableSubscriber((Topic) destination, getTestName()); - } - else - { - consumer = session.createConsumer(destination); - } - } - else - { - destination = session.createQueue(getTestQueueName()); - consumer = session.createConsumer(destination); - } - consumer.close(); - } - - private Message produceMessage(int acknowledgeMode, boolean pubSub, boolean mandatory, boolean immediate) - throws JMSException - { - Session session = _connection.createSession(acknowledgeMode == Session.SESSION_TRANSACTED, acknowledgeMode); - Destination destination = null; - if (pubSub) - { - destination = session.createTopic(getTestQueueName()); - } - else - { - destination = session.createQueue(getTestQueueName()); - } - - MessageProducer producer = ((AMQSession) session).createProducer(destination, mandatory, immediate); - Message message = session.createMessage(); - producer.send(message); - if (session.getTransacted()) - { - session.commit(); - } - return message; - } - - public void testMandatoryAndImmediateDefaults() throws JMSException, InterruptedException - { - Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - // publish to non-existent queue - should get mandatory failure - MessageProducer producer = session.createProducer(session.createQueue(getTestQueueName())); - Message message = session.createMessage(); - producer.send(message); - - _testExceptionListener.assertReceivedNoRouteWithReturnedMessage(message, getTestQueueName()); - - producer = session.createProducer(null); - message = session.createMessage(); - producer.send(session.createQueue(getTestQueueName()), message); - - _testExceptionListener.assertReceivedNoRouteWithReturnedMessage(message, getTestQueueName()); - - // publish to non-existent topic - should get no failure - producer = session.createProducer(session.createTopic(getTestQueueName())); - message = session.createMessage(); - producer.send(message); - - _testExceptionListener.assertNoException(); - - producer = session.createProducer(null); - message = session.createMessage(); - producer.send(session.createTopic(getTestQueueName()), message); - - _testExceptionListener.assertNoException(); - - session.close(); - } - - public void testMandatoryAndImmediateSystemProperties() throws JMSException, InterruptedException - { - setTestClientSystemProperty("qpid.default_mandatory","true"); - Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - // publish to non-existent topic - should get mandatory failure - - MessageProducer producer = session.createProducer(session.createTopic(getTestQueueName())); - Message message = session.createMessage(); - producer.send(message); - - _testExceptionListener.assertReceivedNoRouteWithReturnedMessage(message, getTestQueueName()); - - // now set topic specific system property to false - should no longer get mandatory failure on new producer - setTestClientSystemProperty("qpid.default_mandatory_topic","false"); - producer = session.createProducer(null); - message = session.createMessage(); - producer.send(session.createTopic(getTestQueueName()), message); - - _testExceptionListener.assertNoException(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java deleted file mode 100644 index 6b6b4a7b3c..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java +++ /dev/null @@ -1,440 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.test.client; - -import java.util.Enumeration; -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.QueueBrowser; -import javax.jms.Session; -import javax.jms.TextMessage; -import javax.naming.NamingException; -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class QueueBrowserAutoAckTest extends QpidBrokerTestCase -{ - protected Connection _clientConnection; - protected Session _clientSession; - protected Queue _queue; - protected static final String MESSAGE_ID_PROPERTY = "MessageIDProperty"; - - public void setUp() throws Exception - { - super.setUp(); - - //Create Client - _clientConnection = getConnection(); - _clientConnection.start(); - - setupSession(); - - _queue = _clientSession.createQueue(getTestQueueName()); - _clientSession.createConsumer(_queue).close(); - - //Ensure there are no messages on the queue to start with. - checkQueueDepth(0); - } - - protected void setupSession() throws Exception - { - _clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - } - - public void tearDown() throws Exception - { - if (_clientConnection != null) - { - _clientConnection.close(); - } - - super.tearDown(); - } - - protected void sendMessages(int num) throws JMSException - { - Connection producerConnection = null; - try - { - producerConnection = getConnection(); - } - catch (Exception e) - { - fail("Unable to lookup connection in JNDI."); - } - - sendMessages(producerConnection, num); - } - - protected void sendMessages(Connection producerConnection, int messageSendCount) throws JMSException - { - producerConnection.start(); - - Session producerSession = producerConnection.createSession(true, Session.AUTO_ACKNOWLEDGE); - - //Ensure _queue is created - producerSession.createConsumer(_queue).close(); - - MessageProducer producer = producerSession.createProducer(_queue); - - for (int messsageID = 0; messsageID < messageSendCount; messsageID++) - { - TextMessage textMsg = producerSession.createTextMessage("Message " + messsageID); - textMsg.setIntProperty(MESSAGE_ID_PROPERTY, messsageID); - producer.send(textMsg); - } - producerSession.commit(); - - producerConnection.close(); - } - - /** - * Using the Protocol getQueueDepth method ensure that the correct number of messages are on the queue. - * - * Also uses a QueueBrowser as a second method of validating the message count on the queue. - * - * @param expectedDepth The expected Queue depth - * @throws JMSException on error - */ - protected void checkQueueDepth(int expectedDepth) throws JMSException - { - - // create QueueBrowser - _logger.info("Creating Queue Browser"); - - QueueBrowser queueBrowser = _clientSession.createBrowser(_queue); - - // check for messages - if (_logger.isDebugEnabled()) - { - _logger.debug("Checking for " + expectedDepth + " messages with QueueBrowser"); - } - - //Check what the session believes the queue count to be. - long queueDepth = 0; - - try - { - queueDepth = ((AMQSession) _clientSession).getQueueDepth((AMQDestination) _queue); - } - catch (AMQException e) - { - } - - assertEquals("Session reports Queue expectedDepth not as expected", expectedDepth, queueDepth); - - - - // Browse the queue to get a second opinion - int msgCount = 0; - Enumeration msgs = queueBrowser.getEnumeration(); - - while (msgs.hasMoreElements()) - { - msgs.nextElement(); - msgCount++; - } - - if (_logger.isDebugEnabled()) - { - _logger.debug("Found " + msgCount + " messages total in browser"); - } - - // check to see if all messages found - assertEquals("Browser did not find all messages", expectedDepth, msgCount); - - //Close browser - queueBrowser.close(); - } - - protected void closeBrowserBeforeAfterGetNext(int messageCount) throws JMSException - { - QueueBrowser queueBrowser = _clientSession.createBrowser(_queue); - - Enumeration msgs = queueBrowser.getEnumeration(); - - int msgCount = 0; - - while (msgs.hasMoreElements() && msgCount < messageCount) - { - msgs.nextElement(); - msgCount++; - } - - try - { - queueBrowser.close(); - } - catch (JMSException e) - { - fail("Close should happen without error:" + e.getMessage()); - } - } - - /** - * This method checks that multiple calls to getEnumeration() on a queueBrowser provide the same behaviour. - * - * @param sentMessages The number of messages sent - * @param browserEnumerationCount The number of times to call getEnumeration() - * @throws JMSException - */ - protected void checkMultipleGetEnum(int sentMessages, int browserEnumerationCount) throws JMSException - { - QueueBrowser queueBrowser = _clientSession.createBrowser(_queue); - - for (int count = 0; count < browserEnumerationCount; count++) - { - _logger.info("Checking getEnumeration:" + count); - Enumeration msgs = queueBrowser.getEnumeration(); - - int msgCount = 0; - - while (msgs.hasMoreElements()) - { - msgs.nextElement(); - msgCount++; - } - - // Verify that the browser can see all the messages sent. - assertEquals(sentMessages, msgCount); - } - - try - { - queueBrowser.close(); - } - catch (JMSException e) - { - fail("Close should happen without error:" + e.getMessage()); - } - } - - protected void checkOverlappingMultipleGetEnum(int expectedMessages, int browserEnumerationCount) throws JMSException - { - checkOverlappingMultipleGetEnum(expectedMessages, browserEnumerationCount, null); - } - - protected void checkOverlappingMultipleGetEnum(int expectedMessages, int browserEnumerationCount, String selector) throws JMSException - { - QueueBrowser queueBrowser = selector == null ? - _clientSession.createBrowser(_queue) : _clientSession.createBrowser(_queue, selector); - - Enumeration[] msgs = new Enumeration[browserEnumerationCount]; - int[] msgCount = new int[browserEnumerationCount]; - - //create Enums - for (int count = 0; count < browserEnumerationCount; count++) - { - msgs[count] = queueBrowser.getEnumeration(); - } - - //interleave reads - for (int cnt = 0; cnt < expectedMessages; cnt++) - { - for (int count = 0; count < browserEnumerationCount; count++) - { - if (msgs[count].hasMoreElements()) - { - msgs[count].nextElement(); - msgCount[count]++; - } - } - } - - //validate all browsers get right message count. - for (int count = 0; count < browserEnumerationCount; count++) - { - assertEquals(msgCount[count], expectedMessages); - } - - try - { - queueBrowser.close(); - } - catch (JMSException e) - { - fail("Close should happen without error:" + e.getMessage()); - } - } - - protected void validate(int messages) throws JMSException - { - //Create a new connection to validate message content - Connection connection = null; - - try - { - connection = getConnection(); - } - catch (Exception e) - { - fail("Unable to make validation connection"); - } - - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - connection.start(); - - MessageConsumer consumer = session.createConsumer(_queue); - - _logger.info("Verify messages are still on the queue"); - - Message tempMsg; - - for (int msgCount = 0; msgCount < messages; msgCount++) - { - tempMsg = (TextMessage) consumer.receive(RECEIVE_TIMEOUT); - if (tempMsg == null) - { - fail("Message " + msgCount + " not retrieved from queue"); - } - } - - //Close this new connection - connection.close(); - - _logger.info("All messages recevied from queue"); - - //ensure no message left. - checkQueueDepth(0); - } - - protected void checkQueueDepthWithSelectors(int totalMessages, int clients) throws JMSException - { - - String selector = MESSAGE_ID_PROPERTY + " % " + clients + " = 0" ; - - checkOverlappingMultipleGetEnum(totalMessages / clients, clients, selector); - } - - - /** - * This tests you can browse an empty queue, see QPID-785 - * - * @throws Exception - */ - public void testBrowsingEmptyQueue() throws Exception - { - checkQueueDepth(0); - } - - /* - * Test Messages Remain on Queue - * Create a queu and send messages to it. Browse them and then receive them all to verify they were still there - * - */ - public void testQueueBrowserMsgsRemainOnQueue() throws Exception - { - int messages = 10; - - sendMessages(messages); - - checkQueueDepth(messages); - - validate(messages); - } - - - public void testClosingBrowserMidReceiving() throws NamingException, JMSException - { - int messages = 100; - - sendMessages(messages); - - checkQueueDepth(messages); - - closeBrowserBeforeAfterGetNext(10); - - validate(messages); - } - - /** - * This tests that multiple getEnumerations on a QueueBrowser return the required number of messages. - * @throws NamingException - * @throws JMSException - */ - public void testMultipleGetEnum() throws NamingException, JMSException - { - int messages = 10; - - sendMessages(messages); - - checkQueueDepth(messages); - - checkMultipleGetEnum(messages, 5); - - validate(messages); - } - - public void testMultipleOverlappingGetEnum() throws NamingException, JMSException - { - int messages = 25; - - sendMessages(messages); - - checkQueueDepth(messages); - - checkOverlappingMultipleGetEnum(messages, 5); - - validate(messages); - } - - - public void testBrowsingWithSelector() throws JMSException - { - int messages = 40; - - sendMessages(messages); - - checkQueueDepth(messages); - - for (int clients = 2; clients <= 10; clients++) - { - checkQueueDepthWithSelectors(messages, clients); - } - - validate(messages); - } - - public void testBrowsingWhileStopped() throws JMSException - { - _clientConnection.stop(); - - try - { - QueueBrowser browser = _clientSession.createBrowser(getTestQueue()); - Enumeration messages = browser.getEnumeration(); - fail("Expected exception when attempting to browse on a stopped connection did not occur"); - } - catch(javax.jms.IllegalStateException e) - { - // pass - } - - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserClientAckTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserClientAckTest.java deleted file mode 100644 index f30b8043ad..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserClientAckTest.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.client; - -import javax.jms.Session; - -public class QueueBrowserClientAckTest extends QueueBrowserAutoAckTest -{ - - - protected void setupSession() throws Exception - { - _clientSession = _clientConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserDupsOkTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserDupsOkTest.java deleted file mode 100644 index b19809b8f2..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserDupsOkTest.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.client; - -import javax.jms.Session; - -public class QueueBrowserDupsOkTest extends QueueBrowserAutoAckTest -{ - protected void setupSession() throws Exception - { - _clientSession = _clientConnection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserNoAckTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserNoAckTest.java deleted file mode 100644 index c97343464c..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserNoAckTest.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.client; - -import org.apache.qpid.client.AMQSession; - - -public class QueueBrowserNoAckTest extends QueueBrowserAutoAckTest -{ - - protected void setupSession() throws Exception - { - _clientSession = _clientConnection.createSession(false, AMQSession.NO_ACKNOWLEDGE); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserPreAckTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserPreAckTest.java deleted file mode 100644 index bb1c0d3698..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserPreAckTest.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.client; - -import org.apache.qpid.client.AMQSession; - -public class QueueBrowserPreAckTest extends QueueBrowserAutoAckTest -{ - - protected void setupSession() throws Exception - { - _clientSession = _clientConnection.createSession(false, AMQSession.PRE_ACKNOWLEDGE); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserTransactedTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserTransactedTest.java deleted file mode 100644 index d79788f017..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserTransactedTest.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.client; - -import javax.jms.Session; - -public class QueueBrowserTransactedTest extends QueueBrowserAutoAckTest -{ - protected void setupSession() throws Exception - { - _clientSession = _clientConnection.createSession(true, Session.SESSION_TRANSACTED); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/RollbackOrderTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/RollbackOrderTest.java deleted file mode 100644 index d0968aefc7..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/RollbackOrderTest.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.client; - -import junit.framework.AssertionFailedError; - -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageListener; -import javax.jms.Queue; -import javax.jms.Session; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * RollbackOrderTest, QPID-1864, QPID-1871 - * - * Description: - * - * The problem that this test is exposing is that the dispatcher used to be capable - * of holding on to a message when stopped. This meant that when the rollback was - * called and the dispatcher stopped it may have hold of a message. So after all - * the local queues(preDeliveryQueue, SynchronousQueue, PostDeliveryTagQueue) - * have been cleared the client still had a single message, the one the - * dispatcher was holding on to. - * - * As a result the TxRollback operation would run and then release the dispatcher. - * Whilst the dispatcher would then proceed to reject the message it was holding - * the Broker would already have resent that message so the rejection would silently - * fail. - * - * And the client would receive that single message 'early', depending on the - * number of messages already received when rollback was called. - * - * - * Aims: - * - * The tests puts 50 messages on to the queue. - * - * The test then tries to cause the dispatcher to stop whilst it is in the process - * of moving a message from the preDeliveryQueue to a consumers sychronousQueue. - * - * To exercise this path we have 50 message flowing to the client to give the - * dispatcher a bit of work to do moving messages. - * - * Then we loop - 10 times - * - Validating that the first message received is always message 1. - * - Receive a few more so that there are a few messages to reject. - * - call rollback, to try and catch the dispatcher mid process. - * - * Outcome: - * - * The hope is that we catch the dispatcher mid process and cause a BasicReject - * to fail. Which will be indicated in the log but will also cause that failed - * rejected message to be the next to be delivered which will not be message 1 - * as expected. - * - * We are testing a race condition here but we can check through the log file if - * the race condition occurred. However, performing that check will only validate - * the problem exists and will not be suitable as part of a system test. - * - * @see org.apache.qpid.test.unit.transacted.CommitRollbackTest - */ -public class RollbackOrderTest extends QpidBrokerTestCase -{ - - private Connection _connection; - private Queue _queue; - private Session _session; - private MessageConsumer _consumer; - - @Override public void setUp() throws Exception - { - super.setUp(); - _connection = getConnection(); - - _session = _connection.createSession(true, Session.SESSION_TRANSACTED); - _queue = _session.createQueue(getTestQueueName()); - _consumer = _session.createConsumer(_queue); - - //Send more messages so it is more likely that the dispatcher is - // processing on rollback. - sendMessage(_session, _queue, 50); - _session.commit(); - - } - - public void testOrderingAfterRollback() throws Exception - { - //Start the session now so we - _connection.start(); - - for (int i = 0; i < 20; i++) - { - Message msg = _consumer.receive(); - assertEquals("Incorrect Message Received", 0, msg.getIntProperty(INDEX)); - - // Pull additional messages through so we have some reject work to do - for (int m=1; m <= 5 ; m++) - { - msg = _consumer.receive(); - assertEquals("Incorrect Message Received (message " + m + ")", m, msg.getIntProperty(INDEX)); - } - - _session.rollback(); - } - } - - public void testOrderingAfterRollbackOnMessage() throws Exception - { - final CountDownLatch count= new CountDownLatch(20); - final Exception exceptions[] = new Exception[20]; - final AtomicBoolean failed = new AtomicBoolean(false); - - _consumer.setMessageListener(new MessageListener() - { - - public void onMessage(Message message) - { - - Message msg = message; - try - { - count.countDown(); - assertEquals("Incorrect Message Received", 0, msg.getIntProperty(INDEX)); - - _session.rollback(); - } - catch (JMSException e) - { - _logger.error("Error:" + e.getMessage(), e); - exceptions[(int)count.getCount()] = e; - } - catch (AssertionFailedError cf) - { - // End Test if Equality test fails - while (count.getCount() != 0) - { - count.countDown(); - } - - _logger.error("Error:" + cf.getMessage(), cf); - failed.set(true); - } - } - }); - //Start the session now so we - _connection.start(); - - count.await(10l, TimeUnit.SECONDS); - assertEquals("Not all message received. Count should be 0.", 0, count.getCount()); - - for (Exception e : exceptions) - { - if (e != null) - { - _logger.error("Encountered exception", e); - failed.set(true); - } - } - - _connection.close(); - - assertFalse("Exceptions thrown during test run, Check Std.err.", failed.get()); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/UnroutableMessageTestExceptionListener.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/UnroutableMessageTestExceptionListener.java deleted file mode 100644 index 99afe0015d..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/UnroutableMessageTestExceptionListener.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.test.client; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.TimeUnit; - -import javax.jms.Connection; -import javax.jms.ExceptionListener; -import javax.jms.JMSException; -import javax.jms.Message; - -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQNoConsumersException; -import org.apache.qpid.client.AMQNoRouteException; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.protocol.AMQConstant; - -/** - * Provides utility methods for checking exceptions that are thrown on the client side when a message is - * not routable. - * - * Exception objects are passed either explicitly as method parameters or implicitly - * by previously doing {@link Connection#setExceptionListener(ExceptionListener)}. - */ -public class UnroutableMessageTestExceptionListener implements ExceptionListener -{ - private static final Logger _logger = Logger.getLogger(UnroutableMessageTestExceptionListener.class); - - /** - * Number of seconds to check for an event that should should NOT happen - */ - private static final int NEGATIVE_TIMEOUT = 2; - - /** - * Number of seconds to keep checking for an event that should should happen - */ - private static final int POSITIVE_TIMEOUT = 30; - - private BlockingQueue _exceptions = new ArrayBlockingQueue(1); - - @Override - public void onException(JMSException e) - { - _logger.info("Received exception " + e); - _exceptions.add(e); - } - - public void assertReceivedNoRouteWithReturnedMessage(Message message, String intendedQueueName) - { - JMSException exception = getReceivedException(); - assertNoRouteExceptionWithReturnedMessage(exception, message, intendedQueueName); - } - - public void assertReceivedNoRoute(String intendedQueueName) - { - JMSException exception = getReceivedException(); - assertNoRoute(exception, intendedQueueName); - } - - public void assertReceivedNoConsumersWithReturnedMessage(Message message) - { - JMSException exception = getReceivedException(); - AMQNoConsumersException noConsumersException = (AMQNoConsumersException) exception.getLinkedException(); - assertNotNull("AMQNoConsumersException should be linked to JMSException", noConsumersException); - Message bounceMessage = (Message) noConsumersException.getUndeliveredMessage(); - assertNotNull("Bounced Message is expected", bounceMessage); - - try - { - assertEquals("Unexpected message is bounced", message.getJMSMessageID(), bounceMessage.getJMSMessageID()); - } - catch (JMSException e) - { - throw new RuntimeException("Couldn't check exception", e); - } - } - - public void assertReceivedReturnedMessageWithLongExceptionMessage(Message message, AMQQueue queue) - { - JMSException exception = getReceivedException(); - assertNoRouteException(exception, message); - AMQShortString exchangeName = queue.getExchangeName(); - String expectedMessage = "Error: No Route for message [Exchange: " + exchangeName.asString().substring(0, 220) + "..."; - assertTrue("Unexpected exception message: " + exception.getMessage(), exception.getMessage().contains(expectedMessage)); - } - - public void assertNoRouteExceptionWithReturnedMessage( - JMSException exception, Message message, String intendedQueueName) - { - assertNoRoute(exception, intendedQueueName); - - assertNoRouteException(exception, message); - } - - private void assertNoRouteException(JMSException exception, Message message) - { - AMQNoRouteException noRouteException = (AMQNoRouteException) exception.getLinkedException(); - assertNotNull("AMQNoRouteException should be linked to JMSException", noRouteException); - Message bounceMessage = (Message) noRouteException.getUndeliveredMessage(); - assertNotNull("Bounced Message is expected", bounceMessage); - - try - { - assertEquals("Unexpected message is bounced", message.getJMSMessageID(), bounceMessage.getJMSMessageID()); - } - catch (JMSException e) - { - throw new RuntimeException("Couldn't check exception", e); - } - } - - public void assertNoRoute(JMSException exception, String intendedQueueName) - { - assertTrue( - exception + " message should contain intended queue name", - exception.getMessage().contains(intendedQueueName)); - - AMQException noRouteException = (AMQException) exception.getLinkedException(); - assertNotNull("AMQException should be linked to JMSException", noRouteException); - - assertEquals(AMQConstant.NO_ROUTE, noRouteException.getErrorCode()); - assertTrue( - "Linked exception " + noRouteException + " message should contain intended queue name", - noRouteException.getMessage().contains(intendedQueueName)); - } - - - public void assertNoException() - { - try - { - assertNull("Unexpected JMSException", _exceptions.poll(NEGATIVE_TIMEOUT, TimeUnit.SECONDS)); - } - catch (InterruptedException e) - { - throw new RuntimeException("Couldn't check exception", e); - } - } - - private JMSException getReceivedException() - { - try - { - JMSException exception = _exceptions.poll(POSITIVE_TIMEOUT, TimeUnit.SECONDS); - assertNotNull("JMSException is expected", exception); - return exception; - } - catch(InterruptedException e) - { - throw new RuntimeException("Couldn't check exception", e); - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/destination/AddressBasedDestinationTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/destination/AddressBasedDestinationTest.java deleted file mode 100644 index 14cadc2389..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/destination/AddressBasedDestinationTest.java +++ /dev/null @@ -1,1464 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.client.destination; - -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.QueueBrowser; -import javax.jms.QueueReceiver; -import javax.jms.QueueSession; -import javax.jms.Session; -import javax.jms.TextMessage; -import javax.jms.Topic; -import javax.jms.TopicSession; -import javax.jms.TopicSubscriber; -import javax.naming.Context; -import javax.naming.InitialContext; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQAnyDestination; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.AMQSession_0_10; -import org.apache.qpid.client.message.QpidMessageProperties; -import org.apache.qpid.jndi.PropertiesFileInitialContextFactory; -import org.apache.qpid.messaging.Address; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.transport.ExecutionErrorCode; - -public class AddressBasedDestinationTest extends QpidBrokerTestCase -{ - private static final Logger _logger = LoggerFactory.getLogger(AddressBasedDestinationTest.class); - private Connection _connection; - - @Override - public void setUp() throws Exception - { - super.setUp(); - _connection = getConnection() ; - _connection.start(); - } - - @Override - public void tearDown() throws Exception - { - _connection.close(); - super.tearDown(); - } - - public void testCreateOptions() throws Exception - { - Session jmsSession = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); - MessageProducer prod; - MessageConsumer cons; - - // default (create never, assert never) ------------------- - // create never -------------------------------------------- - String addr1 = "ADDR:testQueue1"; - AMQDestination dest = new AMQAnyDestination(addr1); - try - { - cons = jmsSession.createConsumer(dest); - } - catch(JMSException e) - { - assertTrue(e.getMessage().contains("The name 'testQueue1' supplied in the address " + - "doesn't resolve to an exchange or a queue")); - } - - try - { - prod = jmsSession.createProducer(dest); - } - catch(JMSException e) - { - assertTrue(e.getCause().getCause().getMessage().contains("The name 'testQueue1' supplied in the address " + - "doesn't resolve to an exchange or a queue")); - } - - assertFalse("Queue should not be created",( - (AMQSession_0_10)jmsSession).isQueueExist(dest,false)); - - - // create always ------------------------------------------- - addr1 = "ADDR:testQueue1; { create: always }"; - dest = new AMQAnyDestination(addr1); - cons = jmsSession.createConsumer(dest); - - assertTrue("Queue not created as expected",( - (AMQSession_0_10)jmsSession).isQueueExist(dest, true)); - assertTrue("Queue not bound as expected",( - (AMQSession_0_10)jmsSession).isQueueBound("", - dest.getAddressName(),dest.getAddressName(), null)); - - // create receiver ----------------------------------------- - addr1 = "ADDR:testQueue2; { create: receiver }"; - dest = new AMQAnyDestination(addr1); - try - { - prod = jmsSession.createProducer(dest); - } - catch(JMSException e) - { - assertTrue(e.getCause().getCause().getMessage().contains("The name 'testQueue2' supplied in the address " + - "doesn't resolve to an exchange or a queue")); - } - - assertFalse("Queue should not be created",( - (AMQSession_0_10)jmsSession).isQueueExist(dest, false)); - - - cons = jmsSession.createConsumer(dest); - - assertTrue("Queue not created as expected",( - (AMQSession_0_10)jmsSession).isQueueExist(dest, true)); - assertTrue("Queue not bound as expected",( - (AMQSession_0_10)jmsSession).isQueueBound("", - dest.getAddressName(),dest.getAddressName(), null)); - - // create never -------------------------------------------- - addr1 = "ADDR:testQueue3; { create: never }"; - dest = new AMQAnyDestination(addr1); - try - { - cons = jmsSession.createConsumer(dest); - } - catch(JMSException e) - { - assertTrue(e.getMessage().contains("The name 'testQueue3' supplied in the address " + - "doesn't resolve to an exchange or a queue")); - } - - try - { - prod = jmsSession.createProducer(dest); - } - catch(JMSException e) - { - assertTrue(e.getCause().getCause().getMessage().contains("The name 'testQueue3' supplied in the address " + - "doesn't resolve to an exchange or a queue")); - } - - assertFalse("Queue should not be created",( - (AMQSession_0_10)jmsSession).isQueueExist(dest, false)); - - // create sender ------------------------------------------ - addr1 = "ADDR:testQueue3; { create: sender }"; - dest = new AMQAnyDestination(addr1); - - try - { - cons = jmsSession.createConsumer(dest); - } - catch(JMSException e) - { - assertTrue(e.getMessage().contains("The name 'testQueue3' supplied in the address " + - "doesn't resolve to an exchange or a queue")); - } - assertFalse("Queue should not be created",( - (AMQSession_0_10)jmsSession).isQueueExist(dest, false)); - - prod = jmsSession.createProducer(dest); - assertTrue("Queue not created as expected",( - (AMQSession_0_10)jmsSession).isQueueExist(dest, true)); - assertTrue("Queue not bound as expected",( - (AMQSession_0_10)jmsSession).isQueueBound("", - dest.getAddressName(),dest.getAddressName(), null)); - - } - - public void testCreateQueue() throws Exception - { - Session jmsSession = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); - - String addr = "ADDR:my-queue/hello; " + - "{" + - "create: always, " + - "node: " + - "{" + - "durable: true ," + - "x-declare: " + - "{" + - "exclusive: true," + - "arguments: {" + - "'qpid.alert_size': 1000," + - "'qpid.alert_count': 100" + - "}" + - "}, " + - "x-bindings: [{exchange : 'amq.direct', key : test}, " + - "{exchange : 'amq.fanout'}," + - "{exchange: 'amq.match', arguments: {x-match: any, dep: sales, loc: CA}}," + - "{exchange : 'amq.topic', key : 'a.#'}" + - "]," + - - "}" + - "}"; - AMQDestination dest = new AMQAnyDestination(addr); - MessageConsumer cons = jmsSession.createConsumer(dest); - cons.close(); - - // Even if the consumer is closed the queue and the bindings should be intact. - - assertTrue("Queue not created as expected",( - (AMQSession_0_10)jmsSession).isQueueExist(dest, true)); - - assertTrue("Queue not bound as expected",( - (AMQSession_0_10)jmsSession).isQueueBound("", - dest.getAddressName(),dest.getAddressName(), null)); - - assertTrue("Queue not bound as expected",( - (AMQSession_0_10)jmsSession).isQueueBound("amq.direct", - dest.getAddressName(),"test", null)); - - assertTrue("Queue not bound as expected",( - (AMQSession_0_10)jmsSession).isQueueBound("amq.fanout", - dest.getAddressName(),null, null)); - - assertTrue("Queue not bound as expected",( - (AMQSession_0_10)jmsSession).isQueueBound("amq.topic", - dest.getAddressName(),"a.#", null)); - - Map args = new HashMap(); - args.put("x-match","any"); - args.put("dep","sales"); - args.put("loc","CA"); - assertTrue("Queue not bound as expected",( - (AMQSession_0_10)jmsSession).isQueueBound("amq.match", - dest.getAddressName(),null, args)); - - MessageProducer prod = jmsSession.createProducer(dest); - prod.send(jmsSession.createTextMessage("test")); - - MessageConsumer cons2 = jmsSession.createConsumer(jmsSession.createQueue("ADDR:my-queue")); - Message m = cons2.receive(1000); - assertNotNull("Should receive message sent to my-queue",m); - assertEquals("The subject set in the message is incorrect","hello",m.getStringProperty(QpidMessageProperties.QPID_SUBJECT)); - } - - public void testCreateExchange() throws Exception - { - createExchangeImpl(false, false, false); - } - - /** - * Verify creating an exchange via an Address, with supported - * exchange-declare arguments. - */ - public void testCreateExchangeWithArgs() throws Exception - { - createExchangeImpl(true, false, false); - } - - /** - * Verify that when creating an exchange via an Address, if a - * nonsense argument is specified the broker throws an execution - * exception back on the session with NOT_IMPLEMENTED status. - */ - public void testCreateExchangeWithNonsenseArgs() throws Exception - { - createExchangeImpl(true, true, false); - } - - private void createExchangeImpl(final boolean withExchangeArgs, - final boolean useNonsenseArguments, - final boolean useNonsenseExchangeType) throws Exception - { - Session jmsSession = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); - - String addr = "ADDR:my-exchange/hello; " + - "{ " + - "create: always, " + - "node: " + - "{" + - "type: topic, " + - "x-declare: " + - "{ " + - "type:" + - (useNonsenseExchangeType ? "nonsense" : "direct") + - ", " + - "auto-delete: true" + - createExchangeArgsString(withExchangeArgs, useNonsenseArguments) + - "}" + - "}" + - "}"; - - AMQDestination dest = new AMQAnyDestination(addr); - - MessageConsumer cons; - try - { - cons = jmsSession.createConsumer(dest); - if(useNonsenseArguments || useNonsenseExchangeType) - { - fail("Expected execution exception during exchange declare did not occur"); - } - } - catch(JMSException e) - { - if(useNonsenseArguments && e.getCause().getMessage().contains(ExecutionErrorCode.NOT_IMPLEMENTED.toString())) - { - //expected because we used an argument which the broker doesn't have functionality - //for. We can't do the rest of the test as a result of the exception, just stop. - return; - } - else if(useNonsenseExchangeType && (e.getErrorCode().equals(String.valueOf(AMQConstant.NOT_FOUND.getCode())))) - { - return; - } - else - { - fail("Unexpected exception whilst creating consumer: " + e); - } - } - - assertTrue("Exchange not created as expected",( - (AMQSession_0_10)jmsSession).isExchangeExist(dest,true)); - - // The existence of the queue is implicitly tested here - assertTrue("Queue not bound as expected",( - (AMQSession_0_10)jmsSession).isQueueBound("my-exchange", - dest.getQueueName(),"hello", null)); - - // The client should be able to query and verify the existence of my-exchange (QPID-2774) - dest = new AMQAnyDestination("ADDR:my-exchange; {create: never}"); - cons = jmsSession.createConsumer(dest); - } - - private String createExchangeArgsString(final boolean withExchangeArgs, - final boolean useNonsenseArguments) - { - String argsString; - - if(withExchangeArgs && useNonsenseArguments) - { - argsString = ", arguments: {" + - "'abcd.1234.wxyz': 1, " + - "}"; - } - else if(withExchangeArgs) - { - argsString = ", arguments: {" + - "'qpid.msg_sequence': 1, " + - "'qpid.ive': 1" + - "}"; - } - else - { - argsString = ""; - } - - return argsString; - } - - public void checkQueueForBindings(Session jmsSession, AMQDestination dest,String headersBinding) throws Exception - { - assertTrue("Queue not created as expected",( - (AMQSession_0_10)jmsSession).isQueueExist(dest, true)); - - assertTrue("Queue not bound as expected",( - (AMQSession_0_10)jmsSession).isQueueBound("", - dest.getAddressName(),dest.getAddressName(), null)); - - assertTrue("Queue not bound as expected",( - (AMQSession_0_10)jmsSession).isQueueBound("amq.direct", - dest.getAddressName(),"test", null)); - - assertTrue("Queue not bound as expected",( - (AMQSession_0_10)jmsSession).isQueueBound("amq.topic", - dest.getAddressName(),"a.#", null)); - - Address a = Address.parse(headersBinding); - assertTrue("Queue not bound as expected",( - (AMQSession_0_10)jmsSession).isQueueBound("amq.match", - dest.getAddressName(),null, a.getOptions())); - } - - /** - * Test goal: Verifies that a producer and consumer creation triggers the correct - * behavior for x-bindings specified in node props. - */ - public void testBindQueueWithArgs() throws Exception - { - - Session jmsSession = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); - String headersBinding = "{exchange: 'amq.match', arguments: {x-match: any, dep: sales, loc: CA}}"; - - String addr = "node: " + - "{" + - "durable: true ," + - "x-declare: " + - "{ " + - "auto-delete: true," + - "arguments: {'qpid.alert_count': 100}" + - "}, " + - "x-bindings: [{exchange : 'amq.direct', key : test}, " + - "{exchange : 'amq.topic', key : 'a.#'}," + - headersBinding + - "]" + - "}" + - "}"; - - - AMQDestination dest1 = new AMQAnyDestination("ADDR:my-queue/hello; {create: receiver, " +addr); - MessageConsumer cons = jmsSession.createConsumer(dest1); - checkQueueForBindings(jmsSession,dest1,headersBinding); - - AMQDestination dest2 = new AMQAnyDestination("ADDR:my-queue2/hello; {create: sender, " +addr); - MessageProducer prod = jmsSession.createProducer(dest2); - checkQueueForBindings(jmsSession,dest2,headersBinding); - } - - /** - * Test goal: Verifies the capacity property in address string is handled properly. - * Test strategy: - * Creates a destination with capacity 10. - * Creates consumer with client ack. - * Sends 15 messages to the queue, tries to receive 10. - * Tries to receive the 11th message and checks if its null. - * - * Since capacity is 10 and we haven't acked any messages, - * we should not have received the 11th. - * - * Acks the 10th message and verifies we receive the rest of the msgs. - */ - public void testCapacity() throws Exception - { - verifyCapacity("ADDR:my-queue; {create: always, link:{capacity: 10}}"); - } - - public void testSourceAndTargetCapacity() throws Exception - { - verifyCapacity("ADDR:my-queue; {create: always, link:{capacity: {source:10, target:15} }}"); - } - - private void verifyCapacity(String address) throws Exception - { - if (!isCppBroker()) - { - _logger.info("Not C++ broker, exiting test"); - return; - } - - Session jmsSession = _connection.createSession(false,Session.CLIENT_ACKNOWLEDGE); - - AMQDestination dest = new AMQAnyDestination(address); - MessageConsumer cons = jmsSession.createConsumer(dest); - MessageProducer prod = jmsSession.createProducer(dest); - - for (int i=0; i< 15; i++) - { - prod.send(jmsSession.createTextMessage("msg" + i) ); - } - Message msg = null; - for (int i=0; i< 10; i++) - { - msg = cons.receive(RECEIVE_TIMEOUT); - assertNotNull("Should have received " + i + " message", msg); - assertEquals("Unexpected message received", "msg" + i, ((TextMessage)msg).getText()); - } - assertNull("Shouldn't have received the 11th message as capacity is 10",cons.receive(RECEIVE_TIMEOUT)); - msg.acknowledge(); - for (int i=11; i<16; i++) - { - assertNotNull("Should have received the " + i + "th message as we acked the last 10",cons.receive(RECEIVE_TIMEOUT)); - } - } - - /** - * Test goal: Verifies if the new address format based destinations - * can be specified and loaded correctly from the properties file. - * - */ - public void testLoadingFromPropertiesFile() throws Exception - { - Hashtable map = new Hashtable(); - map.put("destination.myQueue1", "ADDR:my-queue/hello; {create: always, node: " + - "{x-declare: {auto-delete: true, arguments : {'qpid.alert_size': 1000}}}}"); - - map.put("destination.myQueue2", "ADDR:my-queue2; { create: receiver }"); - - map.put("destination.myQueue3", "BURL:direct://amq.direct/my-queue3?routingkey='test'"); - - PropertiesFileInitialContextFactory props = new PropertiesFileInitialContextFactory(); - Context ctx = props.getInitialContext(map); - - AMQDestination dest1 = (AMQDestination)ctx.lookup("myQueue1"); - AMQDestination dest2 = (AMQDestination)ctx.lookup("myQueue2"); - AMQDestination dest3 = (AMQDestination)ctx.lookup("myQueue3"); - - Session jmsSession = _connection.createSession(false,Session.CLIENT_ACKNOWLEDGE); - MessageConsumer cons1 = jmsSession.createConsumer(dest1); - MessageConsumer cons2 = jmsSession.createConsumer(dest2); - MessageConsumer cons3 = jmsSession.createConsumer(dest3); - - assertTrue("Destination1 was not created as expected",( - (AMQSession_0_10)jmsSession).isQueueExist(dest1, true)); - - assertTrue("Destination1 was not bound as expected",( - (AMQSession_0_10)jmsSession).isQueueBound("", - dest1.getAddressName(),dest1.getAddressName(), null)); - - assertTrue("Destination2 was not created as expected",( - (AMQSession_0_10)jmsSession).isQueueExist(dest2,true)); - - assertTrue("Destination2 was not bound as expected",( - (AMQSession_0_10)jmsSession).isQueueBound("", - dest2.getAddressName(),dest2.getAddressName(), null)); - - MessageProducer producer = jmsSession.createProducer(dest3); - producer.send(jmsSession.createTextMessage("Hello")); - TextMessage msg = (TextMessage)cons3.receive(1000); - assertEquals("Destination3 was not created as expected.",msg.getText(),"Hello"); - } - - /** - * Test goal: Verifies the subject can be overridden using "qpid.subject" message property. - * Test strategy: Creates and address with a default subject "topic1" - * Creates a message with "qpid.subject"="topic2" and sends it. - * Verifies that the message goes to "topic2" instead of "topic1". - */ - public void testOverridingSubject() throws Exception - { - Session jmsSession = _connection.createSession(false,Session.CLIENT_ACKNOWLEDGE); - - AMQDestination topic1 = new AMQAnyDestination("ADDR:amq.topic/topic1; {link:{name: queue1}}"); - - MessageProducer prod = jmsSession.createProducer(topic1); - - Message m = jmsSession.createTextMessage("Hello"); - m.setStringProperty("qpid.subject", "topic2"); - - MessageConsumer consForTopic1 = jmsSession.createConsumer(topic1); - MessageConsumer consForTopic2 = jmsSession.createConsumer(new AMQAnyDestination("ADDR:amq.topic/topic2; {link:{name: queue2}}")); - - prod.send(m); - Message msg = consForTopic1.receive(1000); - assertNull("message shouldn't have been sent to topic1",msg); - - msg = consForTopic2.receive(1000); - assertNotNull("message should have been sent to topic2",msg); - - } - - /** - * Test goal: Verifies that session.createQueue method - * works as expected both with the new and old addressing scheme. - */ - public void testSessionCreateQueue() throws Exception - { - Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); - - // Using the BURL method - Destination queue = ssn.createQueue("my-queue"); - MessageProducer prod = ssn.createProducer(queue); - MessageConsumer cons = ssn.createConsumer(queue); - assertTrue("my-queue was not created as expected",( - (AMQSession_0_10)ssn).isQueueBound("amq.direct", - "my-queue","my-queue", null)); - - prod.send(ssn.createTextMessage("test")); - assertNotNull("consumer should receive a message",cons.receive(1000)); - cons.close(); - - // Using the ADDR method - // default case - queue = ssn.createQueue("ADDR:my-queue2"); - try - { - prod = ssn.createProducer(queue); - fail("The client should throw an exception, since there is no queue present in the broker"); - } - catch(Exception e) - { - String s = "The name 'my-queue2' supplied in the address " + - "doesn't resolve to an exchange or a queue"; - assertEquals(s,e.getCause().getCause().getMessage()); - } - - // explicit create case - queue = ssn.createQueue("ADDR:my-queue2; {create: sender}"); - prod = ssn.createProducer(queue); - cons = ssn.createConsumer(queue); - assertTrue("my-queue2 was not created as expected",( - (AMQSession_0_10)ssn).isQueueBound("", - "my-queue2","my-queue2", null)); - - prod.send(ssn.createTextMessage("test")); - assertNotNull("consumer should receive a message",cons.receive(1000)); - cons.close(); - - // Using the ADDR method to create a more complicated queue - String addr = "ADDR:amq.direct/x512; {" + - "link : {name : 'MY.RESP.QUEUE', " + - "x-declare : { auto-delete: true, exclusive: true, " + - "arguments : {'qpid.alert_size': 1000, 'qpid.policy_type': ring} } } }"; - queue = ssn.createQueue(addr); - - cons = ssn.createConsumer(queue); - prod = ssn.createProducer(queue); - assertTrue("MY.RESP.QUEUE was not created as expected",( - (AMQSession_0_10)ssn).isQueueBound("amq.direct", - "MY.RESP.QUEUE","x512", null)); - cons.close(); - } - - /** - * Test goal: Verifies that session.creatTopic method works as expected - * both with the new and old addressing scheme. - */ - public void testSessionCreateTopic() throws Exception - { - sessionCreateTopicImpl(false); - } - - /** - * Test goal: Verifies that session.creatTopic method works as expected - * both with the new and old addressing scheme when adding exchange arguments. - */ - public void testSessionCreateTopicWithExchangeArgs() throws Exception - { - sessionCreateTopicImpl(true); - } - - private void sessionCreateTopicImpl(boolean withExchangeArgs) throws Exception - { - Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); - - // Using the BURL method - Topic topic = ssn.createTopic("ACME"); - MessageProducer prod = ssn.createProducer(topic); - MessageConsumer cons = ssn.createConsumer(topic); - - prod.send(ssn.createTextMessage("test")); - assertNotNull("consumer should receive a message",cons.receive(1000)); - cons.close(); - - // Using the ADDR method - topic = ssn.createTopic("ADDR:ACME"); - prod = ssn.createProducer(topic); - cons = ssn.createConsumer(topic); - - prod.send(ssn.createTextMessage("test")); - assertNotNull("consumer should receive a message",cons.receive(1000)); - cons.close(); - - String addr = "ADDR:vehicles/bus; " + - "{ " + - "create: always, " + - "node: " + - "{" + - "type: topic, " + - "x-declare: " + - "{ " + - "type:direct, " + - "auto-delete: true" + - createExchangeArgsString(withExchangeArgs, false) + - "}" + - "}, " + - "link: {name : my-topic, " + - "x-bindings: [{exchange : 'vehicles', key : car}, " + - "{exchange : 'vehicles', key : van}]" + - "}" + - "}"; - - // Using the ADDR method to create a more complicated topic - topic = ssn.createTopic(addr); - cons = ssn.createConsumer(topic); - prod = ssn.createProducer(topic); - - assertTrue("The queue was not bound to vehicle exchange using bus as the binding key",( - (AMQSession_0_10)ssn).isQueueBound("vehicles", - "my-topic","bus", null)); - - assertTrue("The queue was not bound to vehicle exchange using car as the binding key",( - (AMQSession_0_10)ssn).isQueueBound("vehicles", - "my-topic","car", null)); - - assertTrue("The queue was not bound to vehicle exchange using van as the binding key",( - (AMQSession_0_10)ssn).isQueueBound("vehicles", - "my-topic","van", null)); - - Message msg = ssn.createTextMessage("test"); - msg.setStringProperty("qpid.subject", "van"); - prod.send(msg); - assertNotNull("consumer should receive a message",cons.receive(1000)); - cons.close(); - } - - /** - * Test Goal : Verify the default subjects used for each exchange type. - * The default for amq.topic is "#" and for the rest it's "" - */ - public void testDefaultSubjects() throws Exception - { - Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); - - MessageConsumer queueCons = ssn.createConsumer(new AMQAnyDestination("ADDR:amq.direct")); - MessageConsumer topicCons = ssn.createConsumer(new AMQAnyDestination("ADDR:amq.topic")); - - MessageProducer queueProducer = ssn.createProducer(new AMQAnyDestination("ADDR:amq.direct")); - MessageProducer topicProducer1 = ssn.createProducer(new AMQAnyDestination("ADDR:amq.topic/usa.weather")); - MessageProducer topicProducer2 = ssn.createProducer(new AMQAnyDestination("ADDR:amq.topic/sales")); - - queueProducer.send(ssn.createBytesMessage()); - assertNotNull("The consumer subscribed to amq.direct " + - "with empty binding key should have received the message ",queueCons.receive(1000)); - - topicProducer1.send(ssn.createTextMessage("25c")); - assertEquals("The consumer subscribed to amq.topic " + - "with '#' binding key should have received the message ", - ((TextMessage)topicCons.receive(1000)).getText(),"25c"); - - topicProducer2.send(ssn.createTextMessage("1000")); - assertEquals("The consumer subscribed to amq.topic " + - "with '#' binding key should have received the message ", - ((TextMessage)topicCons.receive(1000)).getText(),"1000"); - } - - /** - * Test Goal : Verify that 'mode : browse' works as expected using a regular consumer. - * This indirectly tests ring queues as well. - */ - public void testBrowseMode() throws Exception - { - - Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); - - String addr = "ADDR:my-ring-queue; {create: always, mode: browse, " + - "node: {x-bindings: [{exchange : 'amq.direct', key : test}], " + - "x-declare:{arguments : {'qpid.policy_type':ring, 'qpid.max_count':2}}}}"; - - Destination dest = ssn.createQueue(addr); - MessageConsumer browseCons = ssn.createConsumer(dest); - MessageProducer prod = ssn.createProducer(ssn.createQueue("ADDR:amq.direct/test")); - - prod.send(ssn.createTextMessage("Test1")); - prod.send(ssn.createTextMessage("Test2")); - - TextMessage msg = (TextMessage)browseCons.receive(1000); - assertEquals("Didn't receive the first message",msg.getText(),"Test1"); - - msg = (TextMessage)browseCons.receive(1000); - assertEquals("Didn't receive the first message",msg.getText(),"Test2"); - - browseCons.close(); - prod.send(ssn.createTextMessage("Test3")); - browseCons = ssn.createConsumer(dest); - - msg = (TextMessage)browseCons.receive(1000); - assertEquals("Should receive the second message again",msg.getText(),"Test2"); - - msg = (TextMessage)browseCons.receive(1000); - assertEquals("Should receive the third message since it's a ring queue",msg.getText(),"Test3"); - - assertNull("Should not receive anymore messages",browseCons.receive(500)); - } - - /** - * Test Goal : When the same destination is used when creating two consumers, - * If the type == topic, verify that unique subscription queues are created, - * unless subscription queue has a name. - * - * If the type == queue, same queue should be shared. - */ - public void testSubscriptionForSameDestination() throws Exception - { - Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); - Destination dest = ssn.createTopic("ADDR:amq.topic/foo"); - MessageConsumer consumer1 = ssn.createConsumer(dest); - MessageConsumer consumer2 = ssn.createConsumer(dest); - MessageProducer prod = ssn.createProducer(dest); - - prod.send(ssn.createTextMessage("A")); - TextMessage m = (TextMessage)consumer1.receive(1000); - assertEquals("Consumer1 should recieve message A",m.getText(),"A"); - m = (TextMessage)consumer2.receive(1000); - assertEquals("Consumer2 should recieve message A",m.getText(),"A"); - - consumer1.close(); - consumer2.close(); - - dest = ssn.createTopic("ADDR:amq.topic/foo; { link: {name: my-queue}}"); - consumer1 = ssn.createConsumer(dest); - try - { - consumer2 = ssn.createConsumer(dest); - fail("An exception should be thrown as 'my-queue' already have an exclusive subscriber"); - } - catch(Exception e) - { - } - _connection.close(); - - _connection = getConnection() ; - _connection.start(); - ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); - dest = ssn.createTopic("ADDR:my_queue; {create: always}"); - consumer1 = ssn.createConsumer(dest); - consumer2 = ssn.createConsumer(dest); - prod = ssn.createProducer(dest); - - prod.send(ssn.createTextMessage("A")); - Message m1 = consumer1.receive(1000); - Message m2 = consumer2.receive(1000); - - if (m1 != null) - { - assertNull("Only one consumer should receive the message",m2); - } - else - { - assertNotNull("Only one consumer should receive the message",m2); - } - } - - public void testXBindingsWithoutExchangeName() throws Exception - { - Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); - String addr = "ADDR:MRKT; " + - "{" + - "create: receiver," + - "node : {type: topic, x-declare: {type: topic} }," + - "link:{" + - "name: my-topic," + - "x-bindings:[{key:'NYSE.#'},{key:'NASDAQ.#'},{key:'CNTL.#'}]" + - "}" + - "}"; - - // Using the ADDR method to create a more complicated topic - Topic topic = ssn.createTopic(addr); - MessageConsumer cons = ssn.createConsumer(topic); - - assertTrue("The queue was not bound to MRKT exchange using NYSE.# as the binding key",( - (AMQSession_0_10)ssn).isQueueBound("MRKT", - "my-topic","NYSE.#", null)); - - assertTrue("The queue was not bound to MRKT exchange using NASDAQ.# as the binding key",( - (AMQSession_0_10)ssn).isQueueBound("MRKT", - "my-topic","NASDAQ.#", null)); - - assertTrue("The queue was not bound to MRKT exchange using CNTL.# as the binding key",( - (AMQSession_0_10)ssn).isQueueBound("MRKT", - "my-topic","CNTL.#", null)); - - MessageProducer prod = ssn.createProducer(topic); - Message msg = ssn.createTextMessage("test"); - msg.setStringProperty("qpid.subject", "NASDAQ.ABCD"); - prod.send(msg); - assertNotNull("consumer should receive a message",cons.receive(1000)); - cons.close(); - } - - public void testXSubscribeOverrides() throws Exception - { - Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); - String str = "ADDR:my_queue; {create:always,link: {x-subscribes:{exclusive: true, arguments: {a:b,x:y}}}}"; - Destination dest = ssn.createTopic(str); - MessageConsumer consumer1 = ssn.createConsumer(dest); - try - { - MessageConsumer consumer2 = ssn.createConsumer(dest); - fail("An exception should be thrown as 'my-queue' already have an exclusive subscriber"); - } - catch(Exception e) - { - } - } - - public void testQueueReceiversAndTopicSubscriber() throws Exception - { - Queue queue = new AMQAnyDestination("ADDR:my-queue; {create: always}"); - Topic topic = new AMQAnyDestination("ADDR:amq.topic/test"); - - QueueSession qSession = ((AMQConnection)_connection).createQueueSession(false, Session.AUTO_ACKNOWLEDGE); - QueueReceiver receiver = qSession.createReceiver(queue); - - TopicSession tSession = ((AMQConnection)_connection).createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - TopicSubscriber sub = tSession.createSubscriber(topic); - - Session ssn = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageProducer prod1 = ssn.createProducer(ssn.createQueue("ADDR:my-queue")); - prod1.send(ssn.createTextMessage("test1")); - - MessageProducer prod2 = ssn.createProducer(ssn.createTopic("ADDR:amq.topic/test")); - prod2.send(ssn.createTextMessage("test2")); - - Message msg1 = receiver.receive(); - assertNotNull(msg1); - assertEquals("test1",((TextMessage)msg1).getText()); - - Message msg2 = sub.receive(); - assertNotNull(msg2); - assertEquals("test2",((TextMessage)msg2).getText()); - } - - public void testDurableSubscriber() throws Exception - { - Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); - - String bindingStr = "x-bindings:[{key:'NYSE.#'},{key:'NASDAQ.#'},{key:'CNTL.#'}]}}"; - - Properties props = new Properties(); - props.setProperty("java.naming.factory.initial", "org.apache.qpid.jndi.PropertiesFileInitialContextFactory"); - props.setProperty("destination.address1", "ADDR:amq.topic/test"); - props.setProperty("destination.address2", "ADDR:amq.topic/test; {node:{" + bindingStr); - props.setProperty("destination.address3", "ADDR:amq.topic/test; {link:{" + bindingStr); - String addrStr = "ADDR:my_queue; {create:always,link: {x-subscribes:{exclusive: true, arguments: {a:b,x:y}}}}"; - props.setProperty("destination.address5", addrStr); - - Context ctx = new InitialContext(props); - - for (int i=1; i < 4; i++) - { - Topic topic = (Topic) ctx.lookup("address"+i); - createDurableSubscriber(ctx,ssn,"address"+i,topic,"ADDR:amq.topic/test"); - } - - Topic topic = ssn.createTopic("ADDR:news.us"); - createDurableSubscriber(ctx,ssn,"my-dest",topic,"ADDR:news.us"); - - Topic namedQueue = (Topic) ctx.lookup("address5"); - try - { - createDurableSubscriber(ctx,ssn,"my-queue",namedQueue,"ADDR:amq.topic/test"); - fail("Exception should be thrown. Durable subscribers cannot be created for Queues"); - } - catch(JMSException e) - { - assertEquals("Durable subscribers can only be created for Topics", - e.getMessage()); - } - } - - public void testDurableSubscription() throws Exception - { - Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Topic topic = session.createTopic("ADDR:amq.topic/" + getTestQueueName()); - MessageProducer publisher = session.createProducer(topic); - MessageConsumer subscriber = session.createDurableSubscriber(topic, getTestQueueName()); - - TextMessage messageToSend = session.createTextMessage("Test0"); - publisher.send(messageToSend); - ((AMQSession)session).sync(); - - Message receivedMessage = subscriber.receive(1000); - assertNotNull("Message has not been received", receivedMessage); - assertEquals("Unexpected message", messageToSend.getText(), ((TextMessage)receivedMessage).getText()); - - subscriber.close(); - - messageToSend = session.createTextMessage("Test1"); - publisher.send(messageToSend); - ((AMQSession)session).sync(); - - subscriber = session.createDurableSubscriber(topic, getTestQueueName()); - receivedMessage = subscriber.receive(1000); - assertNotNull("Message has not been received", receivedMessage); - assertEquals("Unexpected message", messageToSend.getText(), ((TextMessage)receivedMessage).getText()); - } - - public void testDurableSubscriptionnWithSelector() throws Exception - { - Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Topic topic = session.createTopic("ADDR:amq.topic/" + getTestQueueName()); - MessageProducer publisher = session.createProducer(topic); - MessageConsumer subscriber = session.createDurableSubscriber(topic, getTestQueueName(), "id=1", false); - - TextMessage messageToSend = session.createTextMessage("Test0"); - messageToSend.setIntProperty("id", 1); - publisher.send(messageToSend); - ((AMQSession)session).sync(); - - Message receivedMessage = subscriber.receive(1000); - assertNotNull("Message has not been received", receivedMessage); - assertEquals("Unexpected message", messageToSend.getText(), ((TextMessage)receivedMessage).getText()); - assertEquals("Unexpected id", 1, receivedMessage.getIntProperty("id")); - - subscriber.close(); - - messageToSend = session.createTextMessage("Test1"); - messageToSend.setIntProperty("id", 1); - publisher.send(messageToSend); - ((AMQSession)session).sync(); - - subscriber = session.createDurableSubscriber(topic, getTestQueueName(), "id=1", false); - receivedMessage = subscriber.receive(1000); - assertNotNull("Message has not been received", receivedMessage); - assertEquals("Unexpected message", messageToSend.getText(), ((TextMessage)receivedMessage).getText()); - assertEquals("Unexpected id", 1, receivedMessage.getIntProperty("id")); - } - - private void createDurableSubscriber(Context ctx,Session ssn,String destName,Topic topic, String producerAddr) throws Exception - { - MessageConsumer cons = ssn.createDurableSubscriber(topic, destName); - MessageProducer prod = ssn.createProducer(ssn.createTopic(producerAddr)); - - Message m = ssn.createTextMessage(destName); - prod.send(m); - Message msg = cons.receive(1000); - assertNotNull("Message not received as expected when using Topic : " + topic,msg); - assertEquals(destName,((TextMessage)msg).getText()); - ssn.unsubscribe(destName); - } - - public void testDeleteOptions() throws Exception - { - Session jmsSession = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); - MessageConsumer cons; - - // default (create never, assert never) ------------------- - // create never -------------------------------------------- - String addr1 = "ADDR:testQueue1;{create: always, delete: always}"; - AMQDestination dest = new AMQAnyDestination(addr1); - try - { - cons = jmsSession.createConsumer(dest); - cons.close(); - } - catch(JMSException e) - { - fail("Exception should not be thrown. Exception thrown is : " + e); - } - - assertFalse("Queue not deleted as expected",( - (AMQSession_0_10)jmsSession).isQueueExist(dest, false)); - - - String addr2 = "ADDR:testQueue2;{create: always, delete: receiver}"; - dest = new AMQAnyDestination(addr2); - try - { - cons = jmsSession.createConsumer(dest); - cons.close(); - } - catch(JMSException e) - { - fail("Exception should not be thrown. Exception thrown is : " + e); - } - - assertFalse("Queue not deleted as expected",( - (AMQSession_0_10)jmsSession).isQueueExist(dest, false)); - - - String addr3 = "ADDR:testQueue3;{create: always, delete: sender}"; - dest = new AMQAnyDestination(addr3); - try - { - cons = jmsSession.createConsumer(dest); - MessageProducer prod = jmsSession.createProducer(dest); - prod.close(); - } - catch(JMSException e) - { - fail("Exception should not be thrown. Exception thrown is : " + e); - } - - assertFalse("Queue not deleted as expected",( - (AMQSession_0_10)jmsSession).isQueueExist(dest, false)); - } - - /** - * Test Goals : 1. Test if the client sets the correct accept mode for unreliable - * and at-least-once. - * 2. Test default reliability modes for Queues and Topics. - * 3. Test if an exception is thrown if exactly-once is used. - * 4. Test if an exception is thrown if at-least-once is used with topics. - * - * Test Strategy: For goal #1 & #2 - * For unreliable and at-least-once the test tries to receives messages - * in client_ack mode but does not ack the messages. - * It will then close the session, recreate a new session - * and will then try to verify the queue depth. - * For unreliable the messages should have been taken off the queue. - * For at-least-once the messages should be put back onto the queue. - * - */ - - public void testReliabilityOptions() throws Exception - { - String addr1 = "ADDR:testQueue1;{create: always, delete : receiver, link : {reliability : unreliable}}"; - acceptModeTest(addr1,0); - - String addr2 = "ADDR:testQueue2;{create: always, delete : receiver, link : {reliability : at-least-once}}"; - acceptModeTest(addr2,2); - - // Default accept-mode for topics - acceptModeTest("ADDR:amq.topic/test",0); - - // Default accept-mode for queues - acceptModeTest("ADDR:testQueue1;{create: always}",2); - - String addr3 = "ADDR:testQueue2;{create: always, delete : receiver, link : {reliability : exactly-once}}"; - try - { - AMQAnyDestination dest = new AMQAnyDestination(addr3); - fail("An exception should be thrown indicating it's an unsupported type"); - } - catch(Exception e) - { - assertTrue(e.getCause().getMessage().contains("The reliability mode 'exactly-once' is not yet supported")); - } - } - - private void acceptModeTest(String address, int expectedQueueDepth) throws Exception - { - Session ssn = _connection.createSession(false,Session.CLIENT_ACKNOWLEDGE); - MessageConsumer cons; - MessageProducer prod; - - AMQDestination dest = new AMQAnyDestination(address); - cons = ssn.createConsumer(dest); - prod = ssn.createProducer(dest); - - for (int i=0; i < expectedQueueDepth; i++) - { - prod.send(ssn.createTextMessage("Msg" + i)); - } - - for (int i=0; i < expectedQueueDepth; i++) - { - Message msg = cons.receive(1000); - assertNotNull(msg); - assertEquals("Msg" + i,((TextMessage)msg).getText()); - } - - ssn.close(); - ssn = _connection.createSession(false,Session.CLIENT_ACKNOWLEDGE); - long queueDepth = ((AMQSession) ssn).getQueueDepth(dest); - assertEquals(expectedQueueDepth,queueDepth); - cons.close(); - prod.close(); - } - - public void testDestinationOnSend() throws Exception - { - Session ssn = _connection.createSession(false,Session.CLIENT_ACKNOWLEDGE); - MessageConsumer cons = ssn.createConsumer(ssn.createTopic("ADDR:amq.topic/test")); - MessageProducer prod = ssn.createProducer(null); - - Topic queue = ssn.createTopic("ADDR:amq.topic/test"); - prod.send(queue,ssn.createTextMessage("A")); - - Message msg = cons.receive(1000); - assertNotNull(msg); - assertEquals("A",((TextMessage)msg).getText()); - prod.close(); - cons.close(); - } - - public void testReplyToWithNamelessExchange() throws Exception - { - System.setProperty("qpid.declare_exchanges","false"); - replyToTest("ADDR:my-queue;{create: always}"); - System.setProperty("qpid.declare_exchanges","true"); - } - - public void testReplyToWithCustomExchange() throws Exception - { - replyToTest("ADDR:hello;{create:always,node:{type:topic}}"); - } - - private void replyToTest(String replyTo) throws Exception - { - Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Destination replyToDest = AMQDestination.createDestination(replyTo); - MessageConsumer replyToCons = session.createConsumer(replyToDest); - - Destination dest = session.createQueue("ADDR:amq.direct/test"); - - MessageConsumer cons = session.createConsumer(dest); - MessageProducer prod = session.createProducer(dest); - Message m = session.createTextMessage("test"); - m.setJMSReplyTo(replyToDest); - prod.send(m); - - Message msg = cons.receive(); - MessageProducer prodR = session.createProducer(msg.getJMSReplyTo()); - prodR.send(session.createTextMessage("x")); - - Message m1 = replyToCons.receive(); - assertNotNull("The reply to consumer should have received the messsage",m1); - } - - public void testAltExchangeInAddressString() throws Exception - { - String addr1 = "ADDR:my-exchange/test; {create: always, node:{type: topic,x-declare:{alternate-exchange:'amq.fanout'}}}"; - Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - String altQueueAddr = "ADDR:my-alt-queue;{create: always, delete: receiver,node:{x-bindings:[{exchange:'amq.fanout'}] }}"; - MessageConsumer cons = session.createConsumer(session.createQueue(altQueueAddr)); - - MessageProducer prod = session.createProducer(session.createTopic(addr1)); - prod.send(session.createMessage()); - prod.close(); - assertNotNull("The consumer on the queue bound to the alt-exchange should receive the message",cons.receive(1000)); - - String addr2 = "ADDR:test-queue;{create:sender, delete: sender,node:{type:queue,x-declare:{alternate-exchange:'amq.fanout'}}}"; - prod = session.createProducer(session.createTopic(addr2)); - prod.send(session.createMessage()); - prod.close(); - assertNotNull("The consumer on the queue bound to the alt-exchange should receive the message",cons.receive(1000)); - cons.close(); - } - - public void testUnknownAltExchange() throws Exception - { - Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - String altQueueAddr = "ADDR:my-alt-queue;{create: always, delete: receiver,node:{x-bindings:[{exchange:'doesnotexist'}] }}"; - try - { - session.createConsumer(session.createQueue(altQueueAddr)); - fail("Attempt to create a queue with an unknown alternate exchange should fail"); - } - catch(JMSException e) - { - assertEquals("Failure code is not as expected", "404", e.getErrorCode()); - } - } - - public void testUnknownExchangeType() throws Exception - { - createExchangeImpl(false, false, true); - } - - public void testQueueBrowserWithSelectorAutoAcknowledgement() throws Exception - { - assertQueueBrowserWithSelector(Session.AUTO_ACKNOWLEDGE); - } - - public void testQueueBrowserWithSelectorClientAcknowldgement() throws Exception - { - assertQueueBrowserWithSelector(Session.CLIENT_ACKNOWLEDGE); - } - - public void testQueueBrowserWithSelectorTransactedSession() throws Exception - { - assertQueueBrowserWithSelector(Session.SESSION_TRANSACTED); - } - - public void testConsumerWithSelectorAutoAcknowledgement() throws Exception - { - assertConsumerWithSelector(Session.AUTO_ACKNOWLEDGE); - } - - public void testConsumerWithSelectorClientAcknowldgement() throws Exception - { - assertConsumerWithSelector(Session.CLIENT_ACKNOWLEDGE); - } - - public void testConsumerWithSelectorTransactedSession() throws Exception - { - assertConsumerWithSelector(Session.SESSION_TRANSACTED); - } - - private void assertQueueBrowserWithSelector(int acknowledgement) throws Exception - { - String queueAddress = "ADDR:" + getTestQueueName() + ";{create: always}"; - - boolean transacted = acknowledgement == Session.SESSION_TRANSACTED; - Session session = _connection.createSession(transacted, acknowledgement); - - Queue queue = session.createQueue(queueAddress); - - final int numberOfMessages = 10; - List sentMessages = sendMessage(session, queue, numberOfMessages); - assertNotNull("Messages were not sent", sentMessages); - assertEquals("Unexpected number of messages were sent", numberOfMessages, sentMessages.size()); - - QueueBrowser browser = session.createBrowser(queue, INDEX + "%2=0"); - _connection.start(); - - Enumeration enumaration = browser.getEnumeration(); - - int counter = 0; - int expectedIndex = 0; - while (enumaration.hasMoreElements()) - { - Message m = enumaration.nextElement(); - assertNotNull("Expected not null message at step " + counter, m); - int messageIndex = m.getIntProperty(INDEX); - assertEquals("Unexpected index", expectedIndex, messageIndex); - expectedIndex += 2; - counter++; - } - assertEquals("Unexpected number of messsages received", 5, counter); - } - - private void assertConsumerWithSelector(int acknowledgement) throws Exception - { - String queueAddress = "ADDR:" + getTestQueueName() + ";{create: always}"; - - boolean transacted = acknowledgement == Session.SESSION_TRANSACTED; - Session session = _connection.createSession(transacted, acknowledgement); - - Queue queue = session.createQueue(queueAddress); - - final int numberOfMessages = 10; - List sentMessages = sendMessage(session, queue, numberOfMessages); - assertNotNull("Messages were not sent", sentMessages); - assertEquals("Unexpected number of messages were sent", numberOfMessages, sentMessages.size()); - - MessageConsumer consumer = session.createConsumer(queue, INDEX + "%2=0"); - - int expectedIndex = 0; - for (int i = 0; i < 5; i++) - { - Message m = consumer.receive(RECEIVE_TIMEOUT); - assertNotNull("Expected not null message at step " + i, m); - int messageIndex = m.getIntProperty(INDEX); - assertEquals("Unexpected index", expectedIndex, messageIndex); - expectedIndex += 2; - - if (transacted) - { - session.commit(); - } - else if (acknowledgement == Session.CLIENT_ACKNOWLEDGE) - { - m.acknowledge(); - } - } - - Message m = consumer.receive(RECEIVE_TIMEOUT); - assertNull("Unexpected message received", m); - } - - /** - * Tests that a client using a session in {@link Session#CLIENT_ACKNOWLEDGE} can correctly - * recover a session and re-receive the same message. - */ - public void testTopicRereceiveAfterRecover() throws Exception - { - final Session jmsSession = _connection.createSession(false,Session.CLIENT_ACKNOWLEDGE); - final Destination topic = jmsSession.createTopic("ADDR:amq.topic/topic1; {link:{name: queue1}}"); - - final MessageProducer prod = jmsSession.createProducer(topic); - final MessageConsumer consForTopic1 = jmsSession.createConsumer(topic); - final Message sentMessage = jmsSession.createTextMessage("Hello"); - - prod.send(sentMessage); - Message receivedMessage = consForTopic1.receive(1000); - assertNotNull("message should be received by consumer", receivedMessage); - - jmsSession.recover(); - receivedMessage = consForTopic1.receive(1000); - assertNotNull("message should be re-received by consumer after recover", receivedMessage); - receivedMessage.acknowledge(); - } - - /** - * Tests that a client using a session in {@link Session#SESSION_TRANSACTED} can correctly - * rollback a session and re-receive the same message. - */ - public void testTopicRereceiveAfterRollback() throws Exception - { - final Session jmsSession = _connection.createSession(true,Session.SESSION_TRANSACTED); - final Destination topic = jmsSession.createTopic("ADDR:amq.topic/topic1; {link:{name: queue1}}"); - - final MessageProducer prod = jmsSession.createProducer(topic); - final MessageConsumer consForTopic1 = jmsSession.createConsumer(topic); - final Message sentMessage = jmsSession.createTextMessage("Hello"); - - prod.send(sentMessage); - jmsSession.commit(); - - Message receivedMessage = consForTopic1.receive(1000); - assertNotNull("message should be received by consumer", receivedMessage); - - jmsSession.rollback(); - receivedMessage = consForTopic1.receive(1000); - assertNotNull("message should be re-received by consumer after rollback", receivedMessage); - jmsSession.commit(); - } - - /** - * Test Goals : - * - * 1. Verify that link bindings are created and destroyed after creating and closing a subscriber. - * 2. Verify that link bindings are created and destroyed after creating and closing a subscriber. - */ - public void testLinkBindingBehavior() throws Exception - { - Session jmsSession = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); - String addr = "ADDR:my-queue; {create: always, " + - "link: " + - "{" + - "x-bindings: [{exchange : 'amq.direct', key : test}]," + - "}" + - "}"; - - AMQDestination dest = (AMQDestination)jmsSession.createQueue(addr); - MessageConsumer cons = jmsSession.createConsumer(dest); - AMQSession_0_10 ssn = (AMQSession_0_10)jmsSession; - - assertTrue("Queue not created as expected",ssn.isQueueExist(dest, true)); - assertTrue("Queue not bound as expected",ssn.isQueueBound("amq.direct","my-queue","test", null)); - - cons.close(); // closing consumer, link binding should be removed now. - assertTrue("Queue should still be there",ssn.isQueueExist(dest, true)); - assertFalse("Binding should not exist anymore",ssn.isQueueBound("amq.direct","my-queue","test", null)); - - MessageProducer prod = jmsSession.createProducer(dest); - assertTrue("Queue not bound as expected",ssn.isQueueBound("amq.direct","my-queue","test", null)); - prod.close(); - assertFalse("Binding should not exist anymore",ssn.isQueueBound("amq.direct","my-queue","test", null)); - } - - /** - * Test Goals : Verifies that the subscription queue created is as specified under link properties. - */ - public void testCustomizingSubscriptionQueue() throws Exception - { - Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); - String xDeclareArgs = "x-declare: { exclusive: false, auto-delete: false," + - "alternate-exchange: 'amq.fanout'," + - "arguments: {'qpid.alert_size': 1000,'qpid.alert_count': 100}" + - "}"; - - String addr = "ADDR:amq.topic/test; {link: {name:my-queue, durable:true," + xDeclareArgs + "}}"; - Destination dest = ssn.createTopic(addr); - MessageConsumer cons = ssn.createConsumer(dest); - - String verifyAddr = "ADDR:my-queue;{ node: {durable:true, " + xDeclareArgs + "}}"; - AMQDestination verifyDest = (AMQDestination)ssn.createQueue(verifyAddr); - ((AMQSession_0_10)ssn).isQueueExist(verifyDest, true); - - // Verify that the producer does not delete the subscription queue. - MessageProducer prod = ssn.createProducer(dest); - prod.close(); - ((AMQSession_0_10)ssn).isQueueExist(verifyDest, true); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/failover/FailoverTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/failover/FailoverTest.java deleted file mode 100644 index 2875e2c6b1..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/failover/FailoverTest.java +++ /dev/null @@ -1,349 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.test.client.failover; - -import org.apache.log4j.Logger; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.jms.ConnectionListener; -import org.apache.qpid.test.utils.FailoverBaseCase; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.Session; -import javax.jms.TextMessage; -import java.util.Random; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -public class FailoverTest extends FailoverBaseCase implements ConnectionListener -{ - private static final Logger _logger = Logger.getLogger(FailoverTest.class); - - private static final int DEFAULT_NUM_MESSAGES = 10; - private static final int DEFAULT_SEED = 20080921; - protected int numMessages = 0; - protected Connection connection; - private Session producerSession; - private Queue queue; - private MessageProducer producer; - private Session consumerSession; - private MessageConsumer consumer; - - private CountDownLatch failoverComplete; - private boolean CLUSTERED = Boolean.getBoolean("profile.clustered"); - private int seed; - private Random rand; - private int _currentPort = getFailingPort(); - - @Override - protected void setUp() throws Exception - { - super.setUp(); - - numMessages = Integer.getInteger("profile.failoverMsgCount",DEFAULT_NUM_MESSAGES); - seed = Integer.getInteger("profile.failoverRandomSeed",DEFAULT_SEED); - rand = new Random(seed); - - connection = getConnection(); - ((AMQConnection) connection).setConnectionListener(this); - connection.start(); - failoverComplete = new CountDownLatch(1); - } - - private void init(boolean transacted, int mode) throws Exception - { - consumerSession = connection.createSession(transacted, mode); - queue = consumerSession.createQueue(getName()+System.currentTimeMillis()); - consumer = consumerSession.createConsumer(queue); - - producerSession = connection.createSession(transacted, mode); - producer = producerSession.createProducer(queue); - } - - @Override - public void tearDown() throws Exception - { - try - { - connection.close(); - } - catch (Exception e) - { - - } - - super.tearDown(); - } - - private void consumeMessages(int startIndex,int endIndex, boolean transacted) throws JMSException - { - Message msg; - _logger.debug("**************** Receive (Start: " + startIndex + ", End:" + endIndex + ")***********************"); - - for (int i = startIndex; i < endIndex; i++) - { - msg = consumer.receive(1000); - assertNotNull("Message " + i + " was null!", msg); - - _logger.debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - _logger.debug("Received : " + ((TextMessage) msg).getText()); - _logger.debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - - assertEquals("Invalid message order","message " + i, ((TextMessage) msg).getText()); - - } - _logger.debug("***********************************************************"); - - if (transacted) - { - consumerSession.commit(); - } - } - - private void sendMessages(int startIndex,int endIndex, boolean transacted) throws Exception - { - _logger.debug("**************** Send (Start: " + startIndex + ", End:" + endIndex + ")***********************"); - - for (int i = startIndex; i < endIndex; i++) - { - producer.send(producerSession.createTextMessage("message " + i)); - - _logger.debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - _logger.debug("Sending message"+i); - _logger.debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - } - - _logger.debug("***********************************************************"); - - if (transacted) - { - producerSession.commit(); - } - else - { - ((AMQSession)producerSession).sync(); - } - } - - public void testP2PFailover() throws Exception - { - testP2PFailover(numMessages, true,true, false); - } - - public void testP2PFailoverWithMessagesLeftToConsumeAndProduce() throws Exception - { - if (CLUSTERED) - { - testP2PFailover(numMessages, false,false, false); - } - } - - public void testP2PFailoverWithMessagesLeftToConsume() throws Exception - { - if (CLUSTERED) - { - testP2PFailover(numMessages, false, true, false); - } - } - - public void testP2PFailoverTransacted() throws Exception - { - testP2PFailover(numMessages, true,true, true); - } - - public void testP2PFailoverTransactedWithMessagesLeftToConsumeAndProduce() throws Exception - { - // Currently the cluster does not support transactions that span a failover - if (CLUSTERED) - { - testP2PFailover(numMessages, false, false, false); - } - } - private void testP2PFailover(int totalMessages, boolean consumeAll, boolean produceAll , boolean transacted) throws Exception - { - init(transacted, Session.AUTO_ACKNOWLEDGE); - runP2PFailover(totalMessages,consumeAll, produceAll , transacted); - } - - private void runP2PFailover(int totalMessages, boolean consumeAll, boolean produceAll , boolean transacted) throws Exception - { - int toProduce = totalMessages; - - _logger.debug("==================================================================="); - _logger.debug("Total messages used for the test " + totalMessages + " messages"); - _logger.debug("==================================================================="); - - if (!produceAll) - { - toProduce = totalMessages - rand.nextInt(totalMessages); - } - - _logger.debug("=================="); - _logger.debug("Sending " + toProduce + " messages"); - _logger.debug("=================="); - - sendMessages(0,toProduce, transacted); - - // Consume some messages - int toConsume = toProduce; - if (!consumeAll) - { - toConsume = toProduce - rand.nextInt(toProduce); - } - - consumeMessages(0,toConsume, transacted); - - _logger.debug("=================="); - _logger.debug("Consuming " + toConsume + " messages"); - _logger.debug("=================="); - - _logger.info("Failing over"); - - causeFailure(_currentPort, DEFAULT_FAILOVER_TIME); - - // Check that you produce and consume the rest of messages. - _logger.debug("=================="); - _logger.debug("Sending " + (totalMessages-toProduce) + " messages"); - _logger.debug("=================="); - - sendMessages(toProduce,totalMessages, transacted); - consumeMessages(toConsume,totalMessages, transacted); - - _logger.debug("=================="); - _logger.debug("Consuming " + (totalMessages-toConsume) + " messages"); - _logger.debug("=================="); - } - - private void causeFailure(int port, long delay) - { - - failBroker(port); - - _logger.info("Awaiting Failover completion"); - try - { - if (!failoverComplete.await(delay, TimeUnit.MILLISECONDS)) - { - fail("failover did not complete"); - } - } - catch (InterruptedException e) - { - //evil ignore IE. - } - } - - public void testClientAckFailover() throws Exception - { - init(false, Session.CLIENT_ACKNOWLEDGE); - sendMessages(0,1, false); - Message msg = consumer.receive(); - assertNotNull("Expected msgs not received", msg); - - causeFailure(getFailingPort(), DEFAULT_FAILOVER_TIME); - - Exception failure = null; - try - { - msg.acknowledge(); - } - catch (Exception e) - { - failure = e; - } - assertNotNull("Exception should be thrown", failure); - } - - /** - * The idea is to run a failover test in a loop by failing over - * to the other broker each time. - */ - public void testFailoverInALoop() throws Exception - { - if (!CLUSTERED) - { - return; - } - - int iterations = Integer.getInteger("profile.failoverIterations",0); - boolean useAltPort = false; - int altPort = FAILING_PORT; - int stdPort = DEFAULT_PORT; - init(false, Session.AUTO_ACKNOWLEDGE); - for (int i=0; i < iterations; i++) - { - _logger.debug("==================================================================="); - _logger.debug("Failover In a loop : iteration number " + i); - _logger.debug("==================================================================="); - - runP2PFailover(numMessages, false,false, false); - startBroker(_currentPort); - if (useAltPort) - { - _currentPort = altPort; - useAltPort = false; - } - else - { - _currentPort = stdPort; - useAltPort = true; - } - - } - //To prevent any failover logic being initiated when we shutdown the brokers. - connection.close(); - - // Shutdown the brokers - stopBroker(altPort); - stopBroker(stdPort); - - } - - 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() - { - failoverComplete.countDown(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/JMSDestinationTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/JMSDestinationTest.java deleted file mode 100644 index 760884e654..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/JMSDestinationTest.java +++ /dev/null @@ -1,359 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.client.message; - -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.client.CustomJMSXProperty; -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.management.common.mbeans.ManagedQueue; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -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.Topic; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.TabularData; - -import java.util.Iterator; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -/** - * From the API Docs getJMSDestination: - * - * When a message is received, its JMSDestination value must be equivalent to - * the value assigned when it was sent. - */ -public class JMSDestinationTest extends QpidBrokerTestCase -{ - - private Connection _connection; - private Session _session; - - private CountDownLatch _receiveMessage; - private Message _message; - - public void setUp() throws Exception - { - getBrokerConfiguration().addJmxManagementConfiguration(); - - super.setUp(); - - _connection = getConnection(); - - _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - } - - /** - * Test a message sent to a queue comes back with JMSDestination queue - * - * @throws Exception - */ - public void testQueue() throws Exception - { - - Queue queue = _session.createQueue(getTestQueueName()); - - MessageConsumer consumer = _session.createConsumer(queue); - - sendMessage(_session, queue, 1); - - _connection.start(); - - Message receivedMessage = consumer.receive(10000); - - assertNotNull("Message should not be null", receivedMessage); - - Destination receivedDestination = receivedMessage.getJMSDestination(); - - assertNotNull("JMSDestination should not be null", receivedDestination); - - assertEquals("Incorrect Destination type", queue.getClass(), receivedDestination.getClass()); - } - - /** - * Test a message sent to a topic comes back with JMSDestination topic - * - * @throws Exception - */ - public void testTopic() throws Exception - { - - Topic topic = _session.createTopic(getTestQueueName() + "Topic"); - - MessageConsumer consumer = _session.createConsumer(topic); - - sendMessage(_session, topic, 1); - - _connection.start(); - - Message receivedMessage = consumer.receive(10000); - - assertNotNull("Message should not be null", receivedMessage); - - Destination receivedDestination = receivedMessage.getJMSDestination(); - - assertNotNull("JMSDestination should not be null", receivedDestination); - assertEquals("Incorrect Destination type", topic.getClass(), receivedDestination.getClass()); - } - - /** - * Test a message sent to a topic then moved on the broker - * comes back with JMSDestination queue. - * - * i.e. The client is not just setting the value to be the same as the - * current consumer destination. - * - * This test can only be run against the Java broker as it uses JMX to move - * messages between queues. - * - * @throws Exception - */ - public void testMovedToQueue() throws Exception - { - // Setup JMXUtils - JMXTestUtils jmxUtils = new JMXTestUtils(this); - - // Open the JMX Connection - jmxUtils.open(); - try - { - - Queue queue = _session.createQueue(getTestQueueName()); - - _session.createConsumer(queue).close(); - - sendMessage(_session, queue, 1); - - Topic topic = _session.createTopic(getTestQueueName() + "Topic"); - - MessageConsumer consumer = _session.createConsumer(topic); - - // Use Management to move message. - - ManagedQueue managedQueue = jmxUtils. - getManagedObject(ManagedQueue.class, - jmxUtils.getQueueObjectName(getConnectionFactory().getVirtualPath().substring(1), - getTestQueueName())); - - // Find the first message on the queue - TabularData data = managedQueue.viewMessages(1L, 2L); - - Iterator values = data.values().iterator(); - assertTrue("No Messages found via JMX", values.hasNext()); - - // Get its message ID - Long msgID = (Long) ((CompositeDataSupport) values.next()).get("AMQ MessageId"); - - // Start the connection and consume message that has been moved to the - // queue - _connection.start(); - - Message message = consumer.receive(1000); - - //Validate we don't have a message on the queue before we start - assertNull("Message should be null", message); - - // Move it to from the topic to the queue - managedQueue.moveMessages(msgID, msgID, ((AMQTopic) topic).getQueueName()); - - // Retrieve the newly moved message - message = consumer.receive(1000); - - assertNotNull("Message should not be null", message); - - Destination receivedDestination = message.getJMSDestination(); - - assertNotNull("JMSDestination should not be null", receivedDestination); - - assertEquals("Incorrect Destination type", queue.getClass(), receivedDestination.getClass()); - - } - finally - { - jmxUtils.close(); - } - - } - - /** - * Test a message sent to a queue comes back with JMSDestination queue - * when received via a message listener - * - * @throws Exception - */ - public void testQueueAsync() throws Exception - { - - Queue queue = _session.createQueue(getTestQueueName()); - - MessageConsumer consumer = _session.createConsumer(queue); - - sendMessage(_session, queue, 1); - - _connection.start(); - - _message = null; - _receiveMessage = new CountDownLatch(1); - - consumer.setMessageListener(new MessageListener() - { - public void onMessage(Message message) - { - _message = message; - _receiveMessage.countDown(); - } - }); - - assertTrue("Timed out waiting for message to be received ", _receiveMessage.await(1, TimeUnit.SECONDS)); - - assertNotNull("Message should not be null", _message); - - Destination receivedDestination = _message.getJMSDestination(); - - assertNotNull("JMSDestination should not be null", receivedDestination); - - assertEquals("Incorrect Destination type", queue.getClass(), receivedDestination.getClass()); - } - - /** - * Test a message received without the JMS_QPID_DESTTYPE can be resent - * and correctly have the property set. - * - * To do this we need to create a 0-10 connection and send a message - * which is then received by a 0-8/9 client. - * - * @throws Exception - */ - public void testReceiveResend() throws Exception - { - // Create a 0-10 Connection and send message - setSystemProperty(ClientProperties.AMQP_VERSION, "0-10"); - - Connection connection010 = getConnection(); - - Session session010 = connection010.createSession(true, Session.SESSION_TRANSACTED); - - // Create queue for testing - Queue queue = session010.createQueue(getTestQueueName()); - - // Ensure queue exists - session010.createConsumer(queue).close(); - - sendMessage(session010, queue, 1); - - // Close the 010 connection - connection010.close(); - - // Create a 0-8 Connection and receive message - setSystemProperty(ClientProperties.AMQP_VERSION, "0-8"); - - Connection connection08 = getConnection(); - - Session session08 = connection08.createSession(false, Session.AUTO_ACKNOWLEDGE); - - MessageConsumer consumer = session08.createConsumer(queue); - - connection08.start(); - - Message message = consumer.receive(1000); - - assertNotNull("Didn't receive 0-10 message.", message); - - // Validate that JMS_QPID_DESTTYPE is not set - try - { - message.getIntProperty(CustomJMSXProperty.JMS_QPID_DESTTYPE.toString()); - fail("JMS_QPID_DESTTYPE should not be set, so should throw NumberFormatException"); - } - catch (NumberFormatException nfe) - { - - } - - // Resend message back to queue and validate that - // a) getJMSDestination works without the JMS_QPID_DESTTYPE - // b) we can actually send without a BufferOverFlow. - - MessageProducer producer = session08.createProducer(queue); - producer.send(message); - - message = consumer.receive(1000); - - assertNotNull("Didn't receive recent 0-8 message.", message); - - // Validate that JMS_QPID_DESTTYPE is not set - assertEquals("JMS_QPID_DESTTYPE should be set to a Queue", AMQDestination.QUEUE_TYPE, - message.getIntProperty(CustomJMSXProperty.JMS_QPID_DESTTYPE.toString())); - - } - - public void testQueueWithBindingUrlUsingCustomExchange() throws Exception - { - String exchangeName = "exch_" + getTestQueueName(); - String queueName = "queue_" + getTestQueueName(); - - String address = String.format("direct://%s/%s/%s?routingkey='%s'", exchangeName, queueName, queueName, queueName); - sendReceive(address); - } - - public void testQueueWithBindingUrlUsingAmqDirectExchange() throws Exception - { - String queueName = getTestQueueName(); - String address = String.format("direct://amq.direct/%s/%s?routingkey='%s'", queueName, queueName, queueName); - sendReceive(address); - } - - public void testQueueWithBindingUrlUsingDefaultExchange() throws Exception - { - String queueName = getTestQueueName(); - String address = String.format("direct:///%s/%s?routingkey='%s'", queueName, queueName, queueName); - sendReceive(address); - } - - private void sendReceive(String address) throws JMSException, Exception - { - Destination dest = _session.createQueue(address); - MessageConsumer consumer = _session.createConsumer(dest); - - _connection.start(); - - sendMessage(_session, dest, 1); - - Message receivedMessage = consumer.receive(10000); - - assertNotNull("Message should not be null", receivedMessage); - - Destination receivedDestination = receivedMessage.getJMSDestination(); - - assertNotNull("JMSDestination should not be null", receivedDestination); - assertEquals("JMSDestination should match that sent", address, receivedDestination.toString()); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/JMSReplyToTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/JMSReplyToTest.java deleted file mode 100644 index fe8180d6c6..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/JMSReplyToTest.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.client.message; - -import java.util.concurrent.atomic.AtomicReference; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.IllegalStateException; -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.TemporaryQueue; - -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -/** - * Tests that {@link Message#setJMSReplyTo(Destination)} can be used to pass a {@link Destination} between - * messaging clients as is commonly used in request/response messaging pattern implementations. - */ -public class JMSReplyToTest extends QpidBrokerTestCase -{ - private AtomicReference _caughtException = new AtomicReference(); - private Queue _requestQueue; - private Connection _connection; - private Session _session; - - @Override - protected void setUp() throws Exception - { - super.setUp(); - - _requestQueue = startAsyncRespondingJmsConsumerOnSeparateConnection(); - - _connection = getConnection(); - _connection.start(); - _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - } - - public void testRequestResponseUsingJmsReplyTo() throws Exception - { - final String responseQueueName = getTestQueueName() + ".response"; - Queue replyToQueue = _session.createQueue(responseQueueName); - sendRequestAndValidateResponse(replyToQueue); - } - - public void testRequestResponseUsingTemporaryJmsReplyTo() throws Exception - { - TemporaryQueue replyToQueue = _session.createTemporaryQueue(); - - sendRequestAndValidateResponse(replyToQueue); - } - - private void sendRequestAndValidateResponse(Queue replyToQueue) throws JMSException, Exception - { - MessageConsumer replyConsumer = _session.createConsumer(replyToQueue); - - Message requestMessage = createRequestMessageWithJmsReplyTo(_session, replyToQueue); - sendRequest(_requestQueue, _session, requestMessage); - - receiveAndValidateResponse(replyConsumer, requestMessage); - - assertNull("Async responder caught unexpected exception", _caughtException.get()); - } - - private Message createRequestMessageWithJmsReplyTo(Session session, Queue replyToQueue) - throws JMSException - { - Message requestMessage = session.createTextMessage("My request"); - requestMessage.setJMSReplyTo(replyToQueue); - return requestMessage; - } - - private void sendRequest(final Queue requestQueue, Session session, Message requestMessage) throws Exception - { - MessageProducer producer = session.createProducer(requestQueue); - producer.send(requestMessage); - } - - private void receiveAndValidateResponse(MessageConsumer replyConsumer, Message requestMessage) throws JMSException - { - Message responseMessage = replyConsumer.receive(RECEIVE_TIMEOUT); - assertNotNull("Response message not received", responseMessage); - assertEquals("Correlation id of the response should match message id of the request", - responseMessage.getJMSCorrelationID(), requestMessage.getJMSMessageID()); - } - - private Queue startAsyncRespondingJmsConsumerOnSeparateConnection() throws Exception - { - final String requestQueueName = getTestQueueName() + ".request"; - final Connection responderConnection = getConnection(); - responderConnection.start(); - final Session responderSession = responderConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - final Queue requestQueue = responderSession.createQueue(requestQueueName); - - final MessageConsumer requestConsumer = responderSession.createConsumer(requestQueue); - requestConsumer.setMessageListener(new AsyncResponder(responderSession)); - - return requestQueue; - } - - private final class AsyncResponder implements MessageListener - { - private final Session _responderSession; - - private AsyncResponder(Session responderSession) - { - _responderSession = responderSession; - } - - @Override - public void onMessage(Message requestMessage) - { - try - { - Destination replyTo = getReplyToQueue(requestMessage); - - Message responseMessage = _responderSession.createMessage(); - responseMessage.setJMSCorrelationID(requestMessage.getJMSMessageID()); - - sendResponseToQueue(replyTo, responseMessage); - } - catch (Throwable t) - { - _caughtException.set(t); - } - } - - private Destination getReplyToQueue(Message requestMessage) throws JMSException, IllegalStateException - { - Destination replyTo = requestMessage.getJMSReplyTo(); - if (replyTo == null) - { - throw new IllegalStateException("JMSReplyTo was null on message " + requestMessage); - } - return replyTo; - } - - private void sendResponseToQueue(Destination replyTo, Message responseMessage) - throws JMSException - { - MessageProducer responseProducer = _responderSession.createProducer(replyTo); - responseProducer.send(responseMessage); - } - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/MessageToStringTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/MessageToStringTest.java deleted file mode 100644 index dc1f690b1e..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/MessageToStringTest.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.client.message; - -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.BytesMessage; -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.MapMessage; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.ObjectMessage; -import javax.jms.Queue; -import javax.jms.Session; -import javax.jms.StreamMessage; -import javax.jms.TextMessage; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectOutput; -import java.io.ObjectOutputStream; -import java.util.UUID; - -public class MessageToStringTest extends QpidBrokerTestCase -{ - private Connection _connection; - private Session _session; - private Queue _queue; - private MessageConsumer _consumer; - private static final String BYTE_TEST = "MapByteTest"; - - public void setUp() throws Exception - { - super.setUp(); - - //Create Producer put some messages on the queue - _connection = getConnection(); - - //Create Consumer - _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - String queueName = getTestQueueName(); - - //Create Queue - ((AMQSession) _session).createQueue(new AMQShortString(queueName), true, false, false); - _queue = _session.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='false'&autodelete='true'"); - - - _consumer = _session.createConsumer(_queue); - - _connection.start(); - } - - public void tearDown() throws Exception - { - //clean up - _connection.close(); - - super.tearDown(); - } - - public void testBytesMessage() throws JMSException - { - //Create Sample Message using UUIDs - UUID test = UUID.randomUUID(); - - BytesMessage testMessage = _session.createBytesMessage(); - - //Convert UUID into bytes for transit - byte[] testBytes = test.toString().getBytes(); - - testMessage.writeBytes(testBytes); - - sendAndTest(testMessage, testBytes); - } - - public void testMapMessage() throws JMSException, IOException - { - //Create Sample Message using UUIDs - UUID test = UUID.randomUUID(); - - MapMessage testMessage = _session.createMapMessage(); - - byte[] testBytes = convertToBytes(test); - - testMessage.setBytes(BYTE_TEST, testBytes); - - sendAndTest(testMessage, testBytes); - } - - public void testObjectMessage() throws JMSException - { - MessageProducer producer = _session.createProducer(_queue); - - //Create Sample Message using UUIDs - UUID test = UUID.randomUUID(); - - Message testMessage = _session.createObjectMessage(test); - - sendAndTest(testMessage, test); - } - - public void testStreamMessage() throws JMSException, IOException - { - //Create Sample Message using UUIDs - UUID test = UUID.randomUUID(); - - StreamMessage testMessage = _session.createStreamMessage(); - - byte[] testBytes = convertToBytes(test); - - testMessage.writeBytes(testBytes); - - sendAndTest(testMessage, testBytes); - } - - public void testTextMessage() throws JMSException, IOException - { - //Create Sample Message using UUIDs - UUID test = UUID.randomUUID(); - - TextMessage testMessage = _session.createTextMessage(); - - String stringValue = String.valueOf(test); - byte[] testBytes = stringValue.getBytes(); - - testMessage.setText(stringValue); - - sendAndTest(testMessage, testBytes); - } - - //***************** Helpers - - private void sendAndTest(Message message, Object testBytes) throws JMSException - { - MessageProducer producer = _session.createProducer(_queue); - - producer.send(message); - - Message receivedMessage = _consumer.receive(1000); - - assertNotNull("Message was not received.", receivedMessage); - - //Ensure that to calling toString doesn't error and that doing this doesn't break next tests. - assertNotNull("Message returned null from toString", receivedMessage.toString()); - - byte[] byteResults; - UUID result; - - try - { - if (receivedMessage instanceof ObjectMessage) - { - result = (UUID) ((ObjectMessage) receivedMessage).getObject(); - assertEquals("UUIDs were not equal", testBytes, result); - } - else - { - byteResults = getBytes(receivedMessage, ((byte[]) testBytes).length); - assertBytesEquals("UUIDs were not equal", (byte[]) testBytes, byteResults); - } - } - catch (Exception e) - { - fail(e.getMessage()); - } - - } - - private void assertBytesEquals(String message, byte[] expected, byte[] actual) - { - if (expected.length == actual.length) - { - int index = 0; - boolean failed = false; - for (byte b : expected) - { - if (actual[index++] != b) - { - failed = true; - break; - } - } - - if (!failed) - { - return; - } - - } - - fail(message); - } - - private byte[] getBytes(Message receivedMessage, int testBytesLength) throws JMSException - { - byte[] byteResults = new byte[testBytesLength]; - - if (receivedMessage instanceof BytesMessage) - { - assertEquals(testBytesLength, ((BytesMessage) receivedMessage).readBytes(byteResults)); - } - else if (receivedMessage instanceof StreamMessage) - { - assertEquals(testBytesLength, ((StreamMessage) receivedMessage).readBytes(byteResults)); - } - else if (receivedMessage instanceof MapMessage) - { - byteResults = ((MapMessage) receivedMessage).getBytes(BYTE_TEST); - assertEquals(testBytesLength, byteResults.length); - } - else if (receivedMessage instanceof TextMessage) - { - byteResults = ((TextMessage) receivedMessage).getText().getBytes(); - assertEquals(testBytesLength, byteResults.length); - } - - - return byteResults; - } - - private byte[] convertToBytes(UUID test) throws IOException - { - //Convert UUID into bytes for transit - ObjectOutput out; - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - out = new ObjectOutputStream(bos); - out.writeObject(test); - out.close(); - - return bos.toByteArray(); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/ObjectMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/ObjectMessageTest.java deleted file mode 100644 index 3bd2c4a44e..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/ObjectMessageTest.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.test.client.message; - -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.ObjectMessage; -import javax.jms.Queue; -import javax.jms.Session; -import java.util.UUID; - -public class ObjectMessageTest extends QpidBrokerTestCase -{ - private Connection _connection; - private Session _session; - private MessageConsumer _consumer; - private MessageProducer _producer; - - public void setUp() throws Exception - { - super.setUp(); - - //Create Connection - _connection = getConnection(); - - - //Create Session - _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - //Create Queue - String queueName = getTestQueueName(); - ((AMQSession) _session).createQueue(new AMQShortString(queueName), true, false, false); - Queue queue = _session.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='false'&autodelete='true'"); - - //Create Consumer - _consumer = _session.createConsumer(queue); - - //Create Producer - _producer = _session.createProducer(queue); - - _connection.start(); - } - - public void tearDown() throws Exception - { - //clean up - _connection.close(); - - super.tearDown(); - } - - public void testGetAndSend() throws JMSException - { - //Create Sample Message using UUIDs - UUID test = UUID.randomUUID(); - - ObjectMessage testMessage = _session.createObjectMessage(test); - - Object o = testMessage.getObject(); - - assertNotNull("Object was null", o); - - sendAndTest(testMessage, test); - } - - public void testSend() throws JMSException - { - //Create Sample Message using UUIDs - UUID test = UUID.randomUUID(); - - ObjectMessage testMessage = _session.createObjectMessage(test); - - sendAndTest(testMessage, test); - } - - public void testTostringAndSend() throws JMSException - { - //Create Sample Message using UUIDs - UUID test = UUID.randomUUID(); - - ObjectMessage testMessage = _session.createObjectMessage(test); - - assertNotNull("Object was null", testMessage.toString()); - - sendAndTest(testMessage, test); - } - - public void testSendNull() throws JMSException - { - - ObjectMessage testMessage = _session.createObjectMessage(null); - - assertNotNull("Object was null", testMessage.toString()); - - sendAndTest(testMessage, null); - } - - //***************** Helpers - - private void sendAndTest(ObjectMessage message, Object sent) throws JMSException - { - _producer.send(message); - - ObjectMessage receivedMessage = (ObjectMessage) _consumer.receive(1000); - - assertNotNull("Message was not received.", receivedMessage); - - UUID result = (UUID) receivedMessage.getObject(); - - assertEquals("First read: UUIDs were not equal", sent, result); - - result = (UUID) receivedMessage.getObject(); - - assertEquals("Second read: UUIDs were not equal", sent, result); - } - - - public void testSendEmptyObjectMessage() throws JMSException - { - ObjectMessage testMessage = _session.createObjectMessage(); - testMessage.setStringProperty("test-property", "test-value"); - assertNotNull("Object was null", testMessage.toString()); - - _producer.send(testMessage); - - ObjectMessage receivedMessage = (ObjectMessage) _consumer.receive(1000); - - assertNotNull("Message was not received.", receivedMessage); - assertNull("No object was sent", receivedMessage.getObject()); - assertEquals("Unexpected property received", "test-value", receivedMessage.getStringProperty("test-property")); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/SelectorTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/SelectorTest.java deleted file mode 100644 index d945301bbe..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/SelectorTest.java +++ /dev/null @@ -1,314 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.client.message; - -import org.junit.Assert; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.BasicMessageProducer; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.DeliveryMode; -import javax.jms.Destination; -import javax.jms.InvalidSelectorException; -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.TextMessage; -import java.util.concurrent.CountDownLatch; - -public class SelectorTest extends QpidBrokerTestCase implements MessageListener -{ - private static final Logger _logger = LoggerFactory.getLogger(SelectorTest.class); - - private AMQConnection _connection; - private AMQDestination _destination; - private int count; - private static final String INVALID_SELECTOR = "Cost LIKE 5"; - CountDownLatch _responseLatch = new CountDownLatch(1); - - private static final String BAD_MATHS_SELECTOR = " 1 % 5"; - - private static final long RECIEVE_TIMEOUT = 1000; - - protected void setUp() throws Exception - { - super.setUp(); - init((AMQConnection) getConnection("guest", "guest")); - } - - private void init(AMQConnection connection) throws JMSException - { - init(connection, new AMQQueue(connection, getTestQueueName(), true)); - } - - private void init(AMQConnection connection, AMQDestination destination) throws JMSException - { - _connection = connection; - _destination = destination; - connection.start(); - } - - public void onMessage(Message message) - { - count++; - _logger.info("Got Message:" + message); - _responseLatch.countDown(); - } - - public void testUsingOnMessage() throws Exception - { - String selector = "Cost = 2 AND \"property-with-hyphen\" = 'wibble'"; - // selector = "JMSType = Special AND Cost = 2 AND AMQMessageID > 0 AND JMSDeliveryMode=" + DeliveryMode.NON_PERSISTENT; - - Session session = (AMQSession) _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); - // _session.createConsumer(destination).setMessageListener(this); - session.createConsumer(_destination, selector).setMessageListener(this); - - try - { - Message msg = session.createTextMessage("Message"); - msg.setJMSPriority(1); - msg.setIntProperty("Cost", 2); - msg.setStringProperty("property-with-hyphen", "wibble"); - msg.setJMSType("Special"); - - _logger.info("Sending Message:" + msg); - - ((BasicMessageProducer) session.createProducer(_destination)).send(msg, DeliveryMode.NON_PERSISTENT); - _logger.info("Message sent, waiting for response..."); - - _responseLatch.await(); - - if (count > 0) - { - _logger.info("Got message"); - } - - if (count == 0) - { - fail("Did not get message!"); - // throw new RuntimeException("Did not get message!"); - } - } - catch (JMSException e) - { - _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage()); - if (!(e instanceof InvalidSelectorException)) - { - fail("Wrong exception:" + e.getMessage()); - } - else - { - _logger.debug("SUCCESS!!"); - } - } - catch (InterruptedException e) - { - _logger.debug("IE :" + e.getClass().getSimpleName() + ":" + e.getMessage()); - } - - } - - public void testUnparsableSelectors() throws Exception - { - AMQSession session = (AMQSession) _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); - boolean caught = false; - - //Try Creating a Browser - try - { - session.createBrowser(session.createQueue("Ping"), INVALID_SELECTOR); - } - catch (JMSException e) - { - _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage()); - if (!(e instanceof InvalidSelectorException)) - { - fail("Wrong exception:" + e.getMessage()); - } - caught = true; - } - assertTrue("No exception thrown!", caught); - caught = false; - - //Try Creating a Consumer - try - { - session.createConsumer(session.createQueue("Ping"), INVALID_SELECTOR); - } - catch (JMSException e) - { - _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage()); - if (!(e instanceof InvalidSelectorException)) - { - fail("Wrong exception:" + e.getMessage()); - } - caught = true; - } - assertTrue("No exception thrown!", caught); - caught = false; - - //Try Creating a Receiever - try - { - session.createReceiver(session.createQueue("Ping"), INVALID_SELECTOR); - } - catch (JMSException e) - { - _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage()); - if (!(e instanceof InvalidSelectorException)) - { - fail("Wrong exception:" + e.getMessage()); - } - caught = true; - } - assertTrue("No exception thrown!", caught); - caught = false; - - try - { - session.createReceiver(session.createQueue("Ping"), BAD_MATHS_SELECTOR); - } - catch (JMSException e) - { - _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage()); - if (!(e instanceof InvalidSelectorException)) - { - fail("Wrong exception:" + e.getMessage()); - } - caught = true; - } - assertTrue("No exception thrown!", caught); - caught = false; - - } - - public void testRuntimeSelectorError() throws JMSException - { - Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer consumer = session.createConsumer(_destination , "testproperty % 5 = 1"); - MessageProducer producer = session.createProducer(_destination); - Message sentMsg = session.createTextMessage(); - - sentMsg.setIntProperty("testproperty", 1); // 1 % 5 - producer.send(sentMsg); - Message recvd = consumer.receive(RECIEVE_TIMEOUT); - assertNotNull(recvd); - - sentMsg.setStringProperty("testproperty", "hello"); // "hello" % 5 makes no sense - producer.send(sentMsg); - try - { - recvd = consumer.receive(RECIEVE_TIMEOUT); - assertNull(recvd); - } - catch (Exception e) - { - - } - assertFalse("Connection should not be closed", _connection.isClosed()); - } - - public void testSelectorWithJMSMessageID() throws Exception - { - Session session = _connection.createSession(true, Session.SESSION_TRANSACTED); - - MessageProducer prod = session.createProducer(_destination); - MessageConsumer consumer = session.createConsumer(_destination,"JMSMessageID IS NOT NULL"); - - for (int i=0; i<2; i++) - { - Message msg = session.createTextMessage("Msg" + String.valueOf(i)); - prod.send(msg); - } - session.commit(); - - Message msg1 = consumer.receive(1000); - Message msg2 = consumer.receive(1000); - - Assert.assertNotNull("Msg1 should not be null", msg1); - Assert.assertNotNull("Msg2 should not be null", msg2); - - session.commit(); - - prod.setDisableMessageID(true); - - for (int i=2; i<4; i++) - { - Message msg = session.createTextMessage("Msg" + String.valueOf(i)); - prod.send(msg); - } - - session.commit(); - Message msg3 = consumer.receive(1000); - Assert.assertNull("Msg3 should be null", msg3); - session.commit(); - consumer = session.createConsumer(_destination,"JMSMessageID IS NULL"); - - Message msg4 = consumer.receive(1000); - Message msg5 = consumer.receive(1000); - session.commit(); - Assert.assertNotNull("Msg4 should not be null", msg4); - Assert.assertNotNull("Msg5 should not be null", msg5); - } - - public void testSelectorWithJMSDeliveryMode() throws Exception - { - Session session = _connection.createSession(false, Session.SESSION_TRANSACTED); - - Destination dest1 = session.createTopic("test1"); - Destination dest2 = session.createTopic("test2"); - - MessageProducer prod1 = session.createProducer(dest1); - MessageProducer prod2 = session.createProducer(dest2); - MessageConsumer consumer1 = session.createConsumer(dest1,"JMSDeliveryMode = 'PERSISTENT'"); - MessageConsumer consumer2 = session.createConsumer(dest2,"JMSDeliveryMode = 'NON_PERSISTENT'"); - - Message msg1 = session.createTextMessage("Persistent"); - prod1.send(msg1); - prod2.send(msg1); - - prod1.setDeliveryMode(DeliveryMode.NON_PERSISTENT); - prod2.setDeliveryMode(DeliveryMode.NON_PERSISTENT); - - Message msg2 = session.createTextMessage("Non_Persistent"); - prod1.send(msg2); - prod2.send(msg2); - - TextMessage m1 = (TextMessage)consumer1.receive(1000); - assertEquals("Consumer1 should receive the persistent message","Persistent",m1.getText()); - assertNull("Consumer1 should not receiver another message",consumer1.receive(1000)); - - TextMessage m2 = (TextMessage)consumer2.receive(1000); - assertEquals("Consumer2 should receive the non persistent message","Non_Persistent",m2.getText()); - assertNull("Consumer2 should not receiver another message",consumer2.receive(1000)); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/queue/LVQTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/queue/LVQTest.java deleted file mode 100644 index 51566403b3..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/queue/LVQTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.client.queue; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.TextMessage; - -public class LVQTest extends QpidBrokerTestCase -{ - private static final Logger _logger = LoggerFactory.getLogger(LVQTest.class); - private Connection _connection; - - @Override - public void setUp() throws Exception - { - super.setUp(); - _connection = getConnection() ; - _connection.start(); - } - - @Override - public void tearDown() throws Exception - { - _connection.close(); - super.tearDown(); - } - - public void testLVQQueue() throws Exception - { - String addr = "ADDR:my-lvq-queue; {create: always, " + - "node: {x-bindings: [{exchange : 'amq.direct', key : test}], " + - "x-declare:{arguments : {'qpid.last_value_queue':1}}}}"; - - Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); - - Destination dest = ssn.createQueue(addr); - MessageConsumer consumer = ssn.createConsumer(dest); - MessageProducer prod = ssn.createProducer(ssn.createQueue("ADDR:amq.direct/test")); - - for (int i=0; i<40; i++) - { - Message msg = ssn.createTextMessage(String.valueOf(i)); - msg.setStringProperty("qpid.LVQ_key", String.valueOf(i%10)); - prod.send(msg); - } - - for (int i=0; i<10; i++) - { - TextMessage msg = (TextMessage)consumer.receive(500); - assertEquals("The last value is not reflected","3" + i,msg.getText()); - } - - assertNull("There should not be anymore messages",consumer.receive(500)); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/queue/QueuePolicyTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/queue/QueuePolicyTest.java deleted file mode 100644 index b785326ef2..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/queue/QueuePolicyTest.java +++ /dev/null @@ -1,120 +0,0 @@ -/* -* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you under the Apache License, Version 2.0 (the -* "License"); you may not use this file except in compliance -* with the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -* -*/ -package org.apache.qpid.test.client.queue; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.TextMessage; - -public class QueuePolicyTest extends QpidBrokerTestCase -{ - private static final Logger _logger = LoggerFactory.getLogger(QueuePolicyTest.class); - private Connection _connection; - - @Override - public void setUp() throws Exception - { - super.setUp(); - _connection = getConnection() ; - _connection.start(); - } - - @Override - public void tearDown() throws Exception - { - _connection.close(); - super.tearDown(); - } - - /** - * Test Goal : To create a ring queue programitcally with max queue count using the - * address string and observe that it works as expected. - */ - public void testRejectPolicy() throws Exception - { - String addr = "ADDR:queue; {create: always, " + - "node: {x-bindings: [{exchange : 'amq.direct', key : test}], " + - "x-declare:{ arguments : {'qpid.max_count':5} }}}"; - - Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); - - Destination dest = ssn.createQueue(addr); - MessageConsumer consumer = ssn.createConsumer(dest); - MessageProducer prod = ssn.createProducer(ssn.createQueue("ADDR:amq.direct/test")); - - for (int i=0; i<6; i++) - { - prod.send(ssn.createMessage()); - } - - try - { - prod.send(ssn.createMessage()); - ((AMQSession)ssn).sync(); - fail("The client did not receive an exception after exceeding the queue limit"); - } - catch (AMQException e) - { - assertTrue("The correct error code is not set",e.getErrorCode().toString().contains("506")); - } - } - - /** - * Test Goal : To create a ring queue programitcally using the address string and observe - * that it works as expected. - */ - public void testRingPolicy() throws Exception - { - Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); - - String addr = "ADDR:my-ring-queue; {create: always, " + - "node: {x-bindings: [{exchange : 'amq.direct', key : test}], " + - "x-declare:{arguments : {'qpid.policy_type':ring, 'qpid.max_count':2} }}}"; - - Destination dest = ssn.createQueue(addr); - MessageConsumer consumer = ssn.createConsumer(dest); - MessageProducer prod = ssn.createProducer(ssn.createQueue("ADDR:amq.direct/test")); - - _connection.stop(); - - prod.send(ssn.createTextMessage("Test1")); - prod.send(ssn.createTextMessage("Test2")); - prod.send(ssn.createTextMessage("Test3")); - - _connection.start(); - - TextMessage msg = (TextMessage)consumer.receive(1000); - assertEquals("The consumer should receive the msg with body='Test2'","Test2",msg.getText()); - - msg = (TextMessage)consumer.receive(1000); - assertEquals("The consumer should receive the msg with body='Test3'","Test3",msg.getText()); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/Acknowledge2ConsumersTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/Acknowledge2ConsumersTest.java deleted file mode 100644 index 23efb656d2..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/Acknowledge2ConsumersTest.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.test.unit.ack; - -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.Queue; -import javax.jms.Session; - -public class Acknowledge2ConsumersTest extends QpidBrokerTestCase -{ - protected static int NUM_MESSAGES = 100; - protected Connection _con; - protected Queue _queue; - private Session _producerSession; - private Session _consumerSession; - private MessageConsumer _consumerA; - - @Override - protected void setUp() throws Exception - { - super.setUp(); - - _queue = (Queue) getInitialContext().lookup("queue"); - - //Create Producer put some messages on the queue - _con = getConnection(); - } - - private void init(boolean transacted, int mode) throws JMSException - { - _producerSession = _con.createSession(true, Session.SESSION_TRANSACTED); - _consumerSession = _con.createSession(transacted, mode); - _consumerA = _consumerSession.createConsumer(_queue); - _con.start(); - } - - /** - * Produces Messages that - * - * @param transacted - * @param mode - * - * @throws Exception - */ - private void test2ConsumersAcking(boolean transacted, int mode) throws Exception - { - init(transacted, mode); - - // These should all end up being prefetched by sessionA - sendMessage(_producerSession, _queue, NUM_MESSAGES / 2); - - //Create a second consumer (consumerB) to consume some of the messages - MessageConsumer consumerB = _consumerSession.createConsumer(_queue); - - // These messages should be roundrobined between A and B - sendMessage(_producerSession, _queue, NUM_MESSAGES / 2); - - int count = 0; - //Use consumerB to receive messages it has - Message msg = consumerB.receive(1500); - while (msg != null) - { - if (mode == Session.CLIENT_ACKNOWLEDGE) - { - msg.acknowledge(); - } - count++; - msg = consumerB.receive(1500); - } - if (transacted) - { - _consumerSession.commit(); - } - - // Close the consumers - _consumerA.close(); - consumerB.close(); - - // and close the session to release any prefetched messages. - _consumerSession.close(); - assertEquals("Wrong number of messages on queue", NUM_MESSAGES - count, - ((AMQSession) _producerSession).getQueueDepth((AMQDestination) _queue)); - - // Clean up messages that may be left on the queue - _consumerSession = _con.createSession(transacted, mode); - _consumerA = _consumerSession.createConsumer(_queue); - msg = _consumerA.receive(1500); - while (msg != null) - { - if (mode == Session.CLIENT_ACKNOWLEDGE) - { - msg.acknowledge(); - } - msg = _consumerA.receive(1500); - } - _consumerA.close(); - if (transacted) - { - _consumerSession.commit(); - } - _consumerSession.close(); - } - - public void test2ConsumersAutoAck() throws Exception - { - test2ConsumersAcking(false, Session.AUTO_ACKNOWLEDGE); - } - - public void test2ConsumersClientAck() throws Exception - { - test2ConsumersAcking(false, Session.CLIENT_ACKNOWLEDGE); - } - - public void test2ConsumersTx() throws Exception - { - test2ConsumersAcking(true, Session.SESSION_TRANSACTED); - } - - - -// -// /** -// * Check that session level acknowledge does correctly ack all previous -// * values. Send 3 messages(0,1,2) then ack 1 and 2. If session ack is -// * working correctly then acking 1 will also ack 0. Acking 2 will not -// * attempt to re-ack 0 and 1. -// * -// * @throws Exception -// */ -// public void testSessionAck() throws Exception -// { -// init(false, Session.CLIENT_ACKNOWLEDGE); -// -// sendMessage(_producerSession, _queue, 3); -// Message msg; -// -// // Drop msg 0 -// _consumerA.receive(RECEIVE_TIMEOUT); -// -// // Take msg 1 -// msg = _consumerA.receive(RECEIVE_TIMEOUT); -// -// assertNotNull("Message 1 not correctly received.", msg); -// assertEquals("Incorrect message received", 1, msg.getIntProperty(INDEX)); -// -// // This should also ack msg 0 -// msg.acknowledge(); -// -// // Take msg 2 -// msg = _consumerA.receive(RECEIVE_TIMEOUT); -// -// assertNotNull("Message 2 not correctly received.", msg); -// assertEquals("Incorrect message received", 2, msg.getIntProperty(INDEX)); -// -// // This should just ack msg 2 -// msg.acknowledge(); -// -// _consumerA.close(); -// _consumerSession.close(); -// -// assertEquals("Queue not empty.", 0, -// ((AMQSession) _producerSession).getQueueDepth((AMQDestination) _queue)); -// _con.close(); -// -// -// } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeOnMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeOnMessageTest.java deleted file mode 100644 index 602eb5137a..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeOnMessageTest.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.ack; - -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.JMSAMQException; -import org.apache.qpid.client.failover.FailoverException; - -import javax.jms.Message; -import javax.jms.MessageListener; -import javax.jms.Session; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -/** - * This test extends the synchronous AcknowledgeTest to use a MessageListener - * and receive messages asynchronously. - */ -public class AcknowledgeOnMessageTest extends AcknowledgeTest implements MessageListener -{ - protected CountDownLatch _receivedAll; - protected AtomicReference _causeOfFailure = new AtomicReference(null); - - @Override - public void setUp() throws Exception - { - super.setUp(); - } - - /** - * Override the synchronous AcknowledgeTest init to provide the _receivedAll - * CountDownLatch init and ensure that we set the MessageListener. - * @param transacted - * @param mode - * @throws Exception - */ - @Override - public void init(boolean transacted, int mode) throws Exception - { - _receivedAll = new CountDownLatch(NUM_MESSAGES); - - super.init(transacted, mode); - _consumer.setMessageListener(this); - } - - /** - * This test overrides the testAcking from the simple recieve() model to all - * for asynchronous receiving of messages. - * - * Again the transaction/ack mode is provided to this main test run - * - * The init method is called which will setup the listener so that we can - * then sit and await using the _receivedAll CountDownLatch. We wait for up - * to 10s if no messages have been received in the last 10s then test will - * fail. - * - * If the test fails then it will attempt to retrieve any exception that the - * asynchronous delivery thread may have recorded. - * - * @param transacted - * @param mode - * - * @throws Exception - */ - @Override - protected void testAcking(boolean transacted, int mode) throws Exception - { - init(transacted, mode); - - _connection.start(); - - // Set the lastCount to NUM_MESSAGES, this ensures that the compare - // against the receviedAll count is accurate. - int lastCount = NUM_MESSAGES; - - // Wait for messages to arrive - boolean complete = _receivedAll.await(10000L, TimeUnit.MILLISECONDS); - - // If the messasges haven't arrived - while (!complete) - { - // Check how many we have received - int currentCount = (int) _receivedAll.getCount(); - - // make sure we have received a message in the last cycle. - if (lastCount == currentCount) - { - // If we didn't receive any messages then stop. - // Something must have gone wrong. - System.err.println("Giving up waiting as we didn't receive anything."); - break; - } - // Remember the currentCount as the lastCount for the next cycle. - // so we can exit if things get locked up. - lastCount = currentCount; - - // Wait again for messages to arrive. - complete = _receivedAll.await(10000L, TimeUnit.MILLISECONDS); - } - - // If we failed to receive all the messages then fail the test. - if (!complete) - { - // Check to see if we ended due to an exception in the onMessage handler - Exception cause = _causeOfFailure.get(); - if (cause != null) - { - _logger.error("Cause of failure is: ", cause); - fail(cause.getMessage()); - } - else - { - _logger.info("AOMT: Check QueueDepth:" + _queue); - long onQueue=((AMQSession) getConnection().createSession(false, Session.AUTO_ACKNOWLEDGE)).getQueueDepth((AMQDestination) _queue); - fail("All messages not received missing:" + _receivedAll.getCount() + "/" + NUM_MESSAGES+" On Queue:"+onQueue); - - } - } - - // Even if we received all the messages. - // Check to see if we ended due to an exception in the onMessage handler - Exception cause = _causeOfFailure.get(); - if (cause != null) - { - _logger.error("Failed due to following exception", cause); - fail(cause.getMessage()); - } - - try - { - _consumer.close(); - } - catch (JMSAMQException amqe) - { - if (amqe.getLinkedException() instanceof FailoverException) - { - fail("QPID-143 : Auto Ack can acknowledge message from previous session after failver. If failover occurs between deliver and ack."); - } - // else Rethrow for TestCase to catch. - throw amqe; - } - - _consumerSession.close(); - - _logger.info("AOMT: check number of message at end of test."); - assertEquals("Wrong number of messages on queue", 0, - ((AMQSession) getConnection().createSession(false, Session.AUTO_ACKNOWLEDGE)).getQueueDepth((AMQDestination) _queue)); - } - - /** - * The MessageListener interface that recieves the message and counts down - * the _receivedAll CountDownLatch. - * - * Again like AcknowledgeTest acknowledgement is actually handled in - * doAcknowlegement. - * - * The message INDEX is validated to ensure the correct message order is - * preserved. - * - * @param message - */ - public void onMessage(Message message) - { - // Log received Message for debugging - _logger.info("RECEIVED MESSAGE:" + message); - - try - { - int count = NUM_MESSAGES - (int) _receivedAll.getCount(); - - assertEquals("Incorrect message received", count, message.getIntProperty(INDEX)); - - count++; - if (count < NUM_MESSAGES) - { - //Send the next message - _producer.send(createNextMessage(_consumerSession, count)); - } - - doAcknowlegement(message); - - _receivedAll.countDown(); - } - catch (Exception e) - { - // This will end the test run by counting down _receivedAll - fail(e); - } - } - - /** - * Pass the given exception back to the waiting thread to fail the test run. - * - * @param e The exception that is causing the test to fail. - */ - protected void fail(Exception e) - { - //record the failure - _causeOfFailure.set(e); - // End the test. - while (_receivedAll.getCount() != 0) - { - _receivedAll.countDown(); - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java deleted file mode 100644 index 841d0ea4ba..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.test.unit.ack; - -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.Session; - -/** - * Test the various JMS Acknowledge Modes the single testAcking method does all - * the work of receiving and validation of acking. - * - * The ack mode is provided from the various test methods. - */ -public class AcknowledgeTest extends QpidBrokerTestCase -{ - protected int NUM_MESSAGES; - protected Connection _connection; - protected Queue _queue; - protected Session _consumerSession; - protected MessageConsumer _consumer; - protected MessageProducer _producer; - - @Override - protected void setUp() throws Exception - { - super.setUp(); - NUM_MESSAGES = 5; - - _queue = getTestQueue(); - - //Create Producer put some messages on the queue - _connection = getConnection(); - } - - protected void init(boolean transacted, int mode) throws Exception - { - _consumerSession = _connection.createSession(transacted, mode); - _consumer = _consumerSession.createConsumer(_queue); - _producer = _consumerSession.createProducer(_queue); - - // These should all end up being prefetched by session - sendMessage(_consumerSession, _queue, 1); - - syncIfNotTransacted(transacted); - - assertEquals("Wrong number of messages on queue", 1, - ((AMQSession) _consumerSession).getQueueDepth((AMQDestination) _queue)); - } - - /** - * The main test method. - * - * Receive the initial message and then proceed to send and ack messages - * until we have processed NUM_MESSAGES worth of messages. - * - * Each message is tagged with an INDEX value and these are used to check - * that the messages are received in the correct order. - * - * The test concludes by validating that the queue depth is 0 as expected. - * - * @param transacted - * @param mode - * - * @throws Exception - */ - protected void testAcking(boolean transacted, int mode) throws Exception - { - init(transacted, mode); - - _connection.start(); - - Message msg = _consumer.receive(1500); - - int count = 0; - while (count < NUM_MESSAGES) - { - assertNotNull("Message " + count + " not correctly received.", msg); - assertEquals("Incorrect message received", count, msg.getIntProperty(INDEX)); - count++; - - if (count < NUM_MESSAGES) - { - //Send the next message - _producer.send(createNextMessage(_consumerSession, count)); - syncIfNotTransacted(transacted); - } - - doAcknowlegement(msg); - - msg = _consumer.receive(1500); - } - - if (_consumerSession.getTransacted()) - { - //Acknowledge the last msg if we are testing transacted otherwise queueDepth will be 1 - doAcknowlegement(msg); - } - - assertEquals("Wrong number of messages on queue", 0, - ((AMQSession) _consumerSession).getQueueDepth((AMQDestination) _queue)); - } - - /** - * Perform the acknowledgement of messages if additionally required. - * - * @param msg - * - * @throws JMSException - */ - protected void doAcknowlegement(Message msg) throws JMSException - { - if (_consumerSession.getTransacted()) - { - _consumerSession.commit(); - } - - if (_consumerSession.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE) - { - msg.acknowledge(); - } - } - - public void testClientAck() throws Exception - { - testAcking(false, Session.CLIENT_ACKNOWLEDGE); - } - - public void testAutoAck() throws Exception - { - testAcking(false, Session.AUTO_ACKNOWLEDGE); - } - - public void testTransacted() throws Exception - { - testAcking(true, Session.SESSION_TRANSACTED); - } - - public void testDupsOk() throws Exception - { - testAcking(false, Session.DUPS_OK_ACKNOWLEDGE); - } - - public void testNoAck() throws Exception - { - testAcking(false, AMQSession.NO_ACKNOWLEDGE); - } - - public void testPreAck() throws Exception - { - testAcking(false, AMQSession.PRE_ACKNOWLEDGE); - } - - private void syncIfNotTransacted(boolean transacted) throws Exception - { - if(!transacted) - { - ((AMQSession)_consumerSession).sync(); - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/ClientAcknowledgeTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/ClientAcknowledgeTest.java deleted file mode 100644 index 291e1697ca..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/ClientAcknowledgeTest.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.test.unit.ack; - -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.Session; - -public class ClientAcknowledgeTest extends QpidBrokerTestCase -{ - private static final long ONE_DAY_MS = 1000l * 60 * 60 * 24; - private Connection _connection; - private Queue _queue; - private Session _consumerSession; - private MessageConsumer _consumer; - private MessageProducer _producer; - - @Override - protected void setUp() throws Exception - { - super.setUp(); - _queue = getTestQueue(); - _connection = getConnection(); - } - - /** - * Test that message.acknowledge actually acknowledges, regardless of - * the flusher thread period, by restarting the broker after calling - * acknowledge, and then verifying after restart that the message acked - * is no longer present. This test requires a persistent store. - */ - public void testClientAckWithLargeFlusherPeriod() throws Exception - { - setTestClientSystemProperty("qpid.session.max_ack_delay", Long.toString(ONE_DAY_MS)); - _consumerSession = _connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); - _consumer = _consumerSession.createConsumer(_queue); - _connection.start(); - - _producer = _consumerSession.createProducer(_queue); - _producer.send(createNextMessage(_consumerSession, 1)); - _producer.send(createNextMessage(_consumerSession, 2)); - - Message message = _consumer.receive(1000l); - assertNotNull("Message has not been received", message); - assertEquals("Unexpected message is received", 1, message.getIntProperty(INDEX)); - message.acknowledge(); - - //restart broker to allow verification of the acks - //without explicitly closing connection (which acks) - restartBroker(); - - // try to receive the message again, which should fail (as it was ackd) - _connection = getConnection(); - _connection.start(); - _consumerSession = _connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); - _consumer = _consumerSession.createConsumer(_queue); - message = _consumer.receive(1000l); - assertNotNull("Message has not been received", message); - assertEquals("Unexpected message is received", 2, message.getIntProperty(INDEX)); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java deleted file mode 100644 index 23ea4ac258..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java +++ /dev/null @@ -1,483 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.ack; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.jms.Session; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -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.TextMessage; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -public class RecoverTest extends QpidBrokerTestCase -{ - static final Logger _logger = LoggerFactory.getLogger(RecoverTest.class); - - private static final int POSIITIVE_TIMEOUT = 2000; - - private volatile Exception _error; - private AtomicInteger count; - - protected AMQConnection _connection; - protected Session _consumerSession; - protected MessageConsumer _consumer; - static final int SENT_COUNT = 4; - - @Override - protected void setUp() throws Exception - { - super.setUp(); - _error = null; - count = new AtomicInteger(); - } - - protected void initTest() throws Exception - { - _connection = (AMQConnection) getConnection(); - - _consumerSession = _connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); - Queue queue = _consumerSession.createQueue(getTestQueueName()); - - _consumer = _consumerSession.createConsumer(queue); - - _logger.info("Sending four messages"); - sendMessage(_connection.createSession(false, Session.AUTO_ACKNOWLEDGE), queue, SENT_COUNT); - _logger.info("Starting connection"); - _connection.start(); - } - - protected Message validateNextMessages(int nextCount, int startIndex) throws JMSException - { - Message message = null; - for (int index = 0; index < nextCount; index++) - { - message = _consumer.receive(3000); - assertEquals(startIndex + index, message.getIntProperty(INDEX)); - } - return message; - } - - protected void validateRemainingMessages(int remaining) throws JMSException - { - int index = SENT_COUNT - remaining; - - Message message = null; - while (index != SENT_COUNT) - { - message = _consumer.receive(3000); - assertNotNull(message); - assertEquals(index++, message.getIntProperty(INDEX)); - } - - if (message != null) - { - _logger.info("Received redelivery of three messages. Acknowledging last message"); - message.acknowledge(); - } - - _logger.info("Calling acknowledge with no outstanding messages"); - // all acked so no messages to be delivered - _consumerSession.recover(); - - message = _consumer.receiveNoWait(); - assertNull(message); - _logger.info("No messages redelivered as is expected"); - } - - public void testRecoverResendsMsgs() throws Exception - { - initTest(); - - Message message = validateNextMessages(1, 0); - message.acknowledge(); - _logger.info("Received and acknowledged first message"); - - _consumer.receive(); - _consumer.receive(); - _consumer.receive(); - _logger.info("Received all four messages. Calling recover with three outstanding messages"); - // no ack for last three messages so when I call recover I expect to get three messages back - - _consumerSession.recover(); - - validateRemainingMessages(3); - } - - public void testRecoverResendsMsgsAckOnEarlier() throws Exception - { - initTest(); - - Message message = validateNextMessages(2, 0); - message.acknowledge(); - _logger.info("Received 2 messages, acknowledge() first message, should acknowledge both"); - - _consumer.receive(); - _consumer.receive(); - _logger.info("Received all four messages. Calling recover with two outstanding messages"); - // no ack for last three messages so when I call recover I expect to get three messages back - _consumerSession.recover(); - - Message message2 = _consumer.receive(3000); - assertNotNull(message2); - assertEquals(2, message2.getIntProperty(INDEX)); - - Message message3 = _consumer.receive(3000); - assertNotNull(message3); - assertEquals(3, message3.getIntProperty(INDEX)); - - _logger.info("Received redelivery of two messages. calling acknolwedgeThis() first of those message"); - ((org.apache.qpid.jms.Message) message2).acknowledgeThis(); - - _logger.info("Calling recover"); - // all acked so no messages to be delivered - _consumerSession.recover(); - - message3 = _consumer.receive(3000); - assertNotNull(message3); - assertEquals(3, message3.getIntProperty(INDEX)); - ((org.apache.qpid.jms.Message) message3).acknowledgeThis(); - - // all acked so no messages to be delivered - validateRemainingMessages(0); - } - - public void testAcknowledgePerConsumer() throws Exception - { - AMQConnection con = (AMQConnection) getConnection(); - - Session consumerSession = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); - Queue queue = - new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q1"), new AMQShortString("Q1"), - false, true); - Queue queue2 = - new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q2"), new AMQShortString("Q2"), - false, true); - MessageConsumer consumer = consumerSession.createConsumer(queue); - MessageConsumer consumer2 = consumerSession.createConsumer(queue2); - - AMQConnection con2 = (AMQConnection) getConnection(); - Session producerSession = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE); - MessageProducer producer = producerSession.createProducer(queue); - MessageProducer producer2 = producerSession.createProducer(queue2); - - producer.send(producerSession.createTextMessage("msg1")); - producer2.send(producerSession.createTextMessage("msg2")); - - con2.close(); - - _logger.info("Starting connection"); - con.start(); - - TextMessage tm2 = (TextMessage) consumer2.receive(2000); - assertNotNull(tm2); - assertEquals("msg2", tm2.getText()); - - tm2.acknowledge(); - consumerSession.recover(); - - TextMessage tm1 = (TextMessage) consumer.receive(2000); - assertNotNull(tm1); - assertEquals("msg1", tm1.getText()); - - con.close(); - - } - - public void testRecoverInAutoAckListener() throws Exception - { - AMQConnection con = (AMQConnection) getConnection(); - - final Session consumerSession = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - Queue queue = - new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q3"), new AMQShortString("Q3"), - false, true); - MessageConsumer consumer = consumerSession.createConsumer(queue); - MessageProducer producer = consumerSession.createProducer(queue); - producer.send(consumerSession.createTextMessage("hello")); - - final Object lock = new Object(); - - consumer.setMessageListener(new MessageListener() - { - - public void onMessage(Message message) - { - try - { - count.incrementAndGet(); - if (count.get() == 1) - { - if (message.getJMSRedelivered()) - { - setError(new Exception("Message marked as redelivered on what should be first delivery attempt")); - } - - consumerSession.recover(); - } - else if (count.get() == 2) - { - if (!message.getJMSRedelivered()) - { - setError(new Exception("Message not marked as redelivered on what should be second delivery attempt")); - } - } - else - { - _logger.error(message.toString()); - setError(new Exception("Message delivered too many times!: " + count)); - } - } - catch (JMSException e) - { - _logger.error("Error recovering session: " + e, e); - setError(e); - } - - synchronized (lock) - { - lock.notify(); - } - } - }); - - con.start(); - - long waitTime = 30000L; - long waitUntilTime = System.currentTimeMillis() + waitTime; - - synchronized (lock) - { - while ((count.get() <= 1) && (waitTime > 0)) - { - lock.wait(waitTime); - if (count.get() <= 1) - { - waitTime = waitUntilTime - System.currentTimeMillis(); - } - } - } - - Thread.sleep(1000); - - if (_error != null) - { - throw _error; - } - - assertEquals("Message not received the correct number of times.", - 2, count.get()); - } - - private void setError(Exception e) - { - _error = e; - } - - /** - * Goal : Check if ordering is preserved when doing recovery under reasonable circumstances. - * Refer QPID-2471 for more details. - * Test strategy : - * Send 8 messages to a topic. - * The consumer will call recover until it sees a message 5 times, - * at which point it will ack that message. - * It will continue the above until it acks all the messages. - * While doing so it will verify that the messages are not - * delivered out of order. - */ - public void testOrderingWithSyncConsumer() throws Exception - { - Connection con = (Connection) getConnection(); - javax.jms.Session session = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); - Destination topic = session.createTopic("myTopic"); - MessageConsumer cons = session.createConsumer(topic); - - sendMessage(session,topic,8); - con.start(); - - int messageSeen = 0; - int expectedIndex = 0; - long startTime = System.currentTimeMillis(); - - while(expectedIndex < 8) - { - // Based on historical data, on average the test takes about 6 secs to complete. - if (System.currentTimeMillis() - startTime > 8000) - { - fail("Test did not complete on time. Received " + - expectedIndex + " msgs so far. Please check the logs"); - } - - Message message = cons.receive(POSIITIVE_TIMEOUT); - int actualIndex = message.getIntProperty(INDEX); - - assertEquals("Received Message Out Of Order",expectedIndex, actualIndex); - - //don't ack the message until we receive it 5 times - if( messageSeen < 5 ) - { - _logger.debug("Ignoring message " + actualIndex + " and calling recover"); - session.recover(); - messageSeen++; - } - else - { - messageSeen = 0; - expectedIndex++; - message.acknowledge(); - _logger.debug("Acknowledging message " + actualIndex); - } - } - } - - /** - * Goal : Same as testOderingWithSyncConsumer - * Test strategy : - * Same as testOderingWithSyncConsumer but using a - * Message Listener instead of a sync receive(). - */ - public void testOrderingWithAsyncConsumer() throws Exception - { - Connection con = (Connection) getConnection(); - final javax.jms.Session session = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); - Destination topic = session.createTopic("myTopic"); - MessageConsumer cons = session.createConsumer(topic); - - sendMessage(session,topic,8); - con.start(); - - final Object lock = new Object(); - final AtomicBoolean pass = new AtomicBoolean(false); //used as work around for 'final' - - cons.setMessageListener(new MessageListener() - { - private int messageSeen = 0; - private int expectedIndex = 0; - - public void onMessage(Message message) - { - try - { - int actualIndex = message.getIntProperty(INDEX); - assertEquals("Received Message Out Of Order", expectedIndex, actualIndex); - - //don't ack the message until we receive it 5 times - if( messageSeen < 5 ) - { - _logger.debug("Ignoring message " + actualIndex + " and calling recover"); - session.recover(); - messageSeen++; - } - else - { - messageSeen = 0; - expectedIndex++; - message.acknowledge(); - _logger.debug("Acknowledging message " + actualIndex); - if (expectedIndex == 8) - { - pass.set(true); - synchronized (lock) - { - lock.notifyAll(); - } - } - } - } - catch (JMSException e) - { - _error = e; - synchronized (lock) - { - lock.notifyAll(); - } - } - } - }); - - synchronized(lock) - { - // Based on historical data, on average the test takes about 6 secs to complete. - lock.wait(8000); - } - - assertNull("Unexpected exception thrown by async listener", _error); - - if (!pass.get()) - { - fail("Test did not complete on time. Please check the logs"); - } - } - - /** - * This test ensures that after exhausting credit (prefetch), a {@link Session#recover()} successfully - * restores credit and allows the same messages to be re-received. - */ - public void testRecoverSessionAfterCreditExhausted() throws Exception - { - final int maxPrefetch = 5; - - // We send more messages than prefetch size. This ensure that if the 0-10 client were to - // complete the message commands before the rollback command is sent, the broker would - // send additional messages utilising the release credit. This problem would manifest itself - // as an incorrect message (or no message at all) being received at the end of the test. - - final int numMessages = maxPrefetch * 2; - - setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, String.valueOf(maxPrefetch)); - - Connection con = (Connection) getConnection(); - final javax.jms.Session session = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); - Destination dest = session.createQueue(getTestQueueName()); - MessageConsumer cons = session.createConsumer(dest); - - sendMessage(session, dest, numMessages); - con.start(); - - for (int i=0; i< maxPrefetch; i++) - { - final Message message = cons.receive(POSIITIVE_TIMEOUT); - assertNotNull("Received:" + i, message); - assertEquals("Unexpected message received", i, message.getIntProperty(INDEX)); - } - - _logger.info("Recovering"); - session.recover(); - - Message result = cons.receive(POSIITIVE_TIMEOUT); - // Expect the first message - assertEquals("Unexpected message received", 0, result.getIntProperty(INDEX)); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java deleted file mode 100644 index b545f610d1..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.basic; - -import org.junit.Assert; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.message.JMSBytesMessage; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.transport.util.Waiter; - -import javax.jms.BytesMessage; -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageListener; -import javax.jms.MessageNotReadableException; -import javax.jms.MessageNotWriteableException; -import javax.jms.MessageProducer; -import javax.jms.Session; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -public class BytesMessageTest extends QpidBrokerTestCase implements MessageListener -{ - private static final Logger _logger = LoggerFactory.getLogger(BytesMessageTest.class); - - private Connection _connection; - private Destination _destination; - private Session _session; - private final List received = new ArrayList(); - private final List messages = new ArrayList(); - private int _count = 100; - public String _connectionString = "vm://:1"; - - protected void setUp() throws Exception - { - super.setUp(); - init((AMQConnection) getConnection("guest", "guest")); - } - - protected void tearDown() throws Exception - { - super.tearDown(); - } - - void init(AMQConnection connection) throws Exception - { - init(connection, new AMQQueue(connection, randomize("BytesMessageTest"), true)); - } - - void init(AMQConnection connection, AMQDestination destination) throws Exception - { - _connection = connection; - _destination = destination; - _session = connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); - - // Set up a slow consumer. - _session.createConsumer(destination).setMessageListener(this); - connection.start(); - } - - public void test() throws Exception - { - try - { - send(_count); - waitFor(_count); - check(); - _logger.info("Completed without failure"); - } - finally - { - _connection.close(); - } - } - - void send(int count) throws JMSException - { - // create a publisher - MessageProducer producer = _session.createProducer(_destination); - for (int i = 0; i < count; i++) - { - BytesMessage msg = _session.createBytesMessage(); - - try - { - msg.readFloat(); - Assert.fail("Message should not be readable"); - } - catch (MessageNotReadableException mnwe) - { - // normal execution - } - - byte[] data = ("Message " + i).getBytes(); - msg.writeBytes(data); - messages.add(data); - producer.send(msg); - } - } - - void waitFor(int count) throws InterruptedException - { - synchronized (received) - { - Waiter w = new Waiter(received, 30000); - while (received.size() < count && w.hasTime()) - { - w.await(); - } - } - } - - void check() throws JMSException - { - List actual = new ArrayList(); - for (JMSBytesMessage m : received) - { - ByteBuffer buffer = m.getData(); - byte[] data = new byte[buffer.remaining()]; - buffer.get(data); - actual.add(data); - - // Check Body Write Status - try - { - m.writeBoolean(true); - Assert.fail("Message should not be writeable"); - } - catch (MessageNotWriteableException mnwe) - { - // normal execution - } - - m.clearBody(); - - try - { - m.writeBoolean(true); - } - catch (MessageNotWriteableException mnwe) - { - Assert.fail("Message should be writeable"); - } - - // Check property write status - try - { - m.setStringProperty("test", "test"); - Assert.fail("Message should not be writeable"); - } - catch (MessageNotWriteableException mnwe) - { - // normal execution - } - - m.clearProperties(); - - try - { - m.setStringProperty("test", "test"); - } - catch (MessageNotWriteableException mnwe) - { - Assert.fail("Message should be writeable"); - } - - } - - assertEqual(messages.iterator(), actual.iterator()); - } - - private static void assertEqual(Iterator expected, Iterator actual) - { - List errors = new ArrayList(); - while (expected.hasNext() && actual.hasNext()) - { - try - { - assertEquivalent((byte[]) expected.next(), (byte[]) actual.next()); - } - catch (Exception e) - { - errors.add(e.getMessage()); - } - } - while (expected.hasNext()) - { - errors.add("Expected " + expected.next() + " but no more actual values."); - } - while (actual.hasNext()) - { - errors.add("Found " + actual.next() + " but no more expected values."); - } - - if (!errors.isEmpty()) - { - throw new RuntimeException(errors.toString()); - } - } - - private static void assertEquivalent(byte[] expected, byte[] actual) - { - if (expected.length != actual.length) - { - throw new RuntimeException("Expected length " + expected.length + " got " + actual.length); - } - - for (int i = 0; i < expected.length; i++) - { - if (expected[i] != actual[i]) - { - throw new RuntimeException("Failed on byte " + i + " of " + expected.length); - } - } - } - - public void onMessage(Message message) - { - synchronized (received) - { - received.add((JMSBytesMessage) message); - received.notify(); - } - } - - private static String randomize(String in) - { - return in + System.currentTimeMillis(); - } - - public static void main(String[] argv) throws Exception - { - final String connectionString; - final int count; - if (argv.length == 0) - { - connectionString = "vm://:1"; - count = 100; - } - else - { - connectionString = argv[0]; - count = Integer.parseInt(argv[1]); - } - - _logger.info("connectionString = " + connectionString); - _logger.info("count = " + count); - - BytesMessageTest test = new BytesMessageTest(); - test._connectionString = connectionString; - test._count = count; - test.test(); - } - - public void testModificationAfterSend() throws Exception - { - Connection connection = getConnection(); - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - BytesMessage jmsMsg = session.createBytesMessage(); - Destination destination = getTestQueue(); - - /* Set the constant message contents. */ - - jmsMsg.setStringProperty("foo", "test"); - - /* Pre-populate the message body buffer to the target size. */ - byte[] jmsMsgBodyBuffer = new byte[1024]; - - connection.start(); - - /* Send messages. */ - MessageProducer producer = session.createProducer(destination); - - MessageConsumer consumer = session.createConsumer(destination); - - for(int writtenMsgCount = 0; writtenMsgCount < 10; writtenMsgCount++) - { - /* Set the per send message contents. */ - jmsMsgBodyBuffer[0] = (byte) writtenMsgCount; - jmsMsg.writeBytes(jmsMsgBodyBuffer, 0, jmsMsgBodyBuffer.length); - /** Try to write a message. */ - producer.send(jmsMsg); - } - - - for(int writtenMsgCount = 0; writtenMsgCount < 10; writtenMsgCount++) - { - BytesMessage recvdMsg = (BytesMessage) consumer.receive(1000L); - assertNotNull("Expected to receive message " + writtenMsgCount + " but did not", recvdMsg); - assertEquals("Message "+writtenMsgCount+" not of expected size", (long) ((writtenMsgCount + 1)*1024), - recvdMsg.getBodyLength()); - - } - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/FieldTableMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/FieldTableMessageTest.java deleted file mode 100644 index 599c8061a7..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/FieldTableMessageTest.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.basic; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.message.JMSBytesMessage; -import org.apache.qpid.framing.AMQFrameDecodingException; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.FieldTableFactory; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.BytesMessage; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageListener; -import javax.jms.MessageProducer; -import java.io.ByteArrayInputStream; -import java.io.DataInputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -public class FieldTableMessageTest extends QpidBrokerTestCase implements MessageListener -{ - private static final Logger _logger = LoggerFactory.getLogger(FieldTableMessageTest.class); - - private AMQConnection _connection; - private AMQDestination _destination; - private AMQSession _session; - private final ArrayList received = new ArrayList(); - private FieldTable _expected; - private int _count = 10; - private String _connectionString = "vm://:1"; - private CountDownLatch _waitForCompletion; - - protected void setUp() throws Exception - { - super.setUp(); - init( (AMQConnection) getConnection("guest", "guest")); - } - - protected void tearDown() throws Exception - { - super.tearDown(); - } - - private void init(AMQConnection connection) throws Exception - { - init(connection, new AMQQueue(connection, randomize("FieldTableMessageTest"), true)); - } - - private void init(AMQConnection connection, AMQDestination destination) throws Exception - { - _connection = connection; - _destination = destination; - _session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); - - // set up a slow consumer - _session.createConsumer(destination).setMessageListener(this); - connection.start(); - - // _expected = new FieldTableTest().load("FieldTableTest2.properties"); - _expected = load(); - } - - private FieldTable load() throws IOException - { - FieldTable result = FieldTableFactory.newFieldTable(); - result.setLong("one", 1L); - result.setLong("two", 2L); - result.setLong("three", 3L); - result.setLong("four", 4L); - result.setLong("five", 5L); - - return result; - } - - public void test() throws Exception - { - int count = _count; - _waitForCompletion = new CountDownLatch(_count); - send(count); - _waitForCompletion.await(20, TimeUnit.SECONDS); - check(); - _logger.info("Completed without failure"); - _connection.close(); - } - - void send(int count) throws JMSException, IOException - { - // create a publisher - MessageProducer producer = _session.createProducer(_destination); - for (int i = 0; i < count; i++) - { - BytesMessage msg = _session.createBytesMessage(); - msg.writeBytes(_expected.getDataAsBytes()); - producer.send(msg); - } - } - - - void check() throws JMSException, AMQFrameDecodingException, IOException - { - for (Object m : received) - { - final BytesMessage bytesMessage = (BytesMessage) m; - final long bodyLength = bytesMessage.getBodyLength(); - byte[] data = new byte[(int) bodyLength]; - bytesMessage.readBytes(data); - FieldTable actual = FieldTableFactory.newFieldTable(new DataInputStream(new ByteArrayInputStream(data)), bodyLength); - for (String key : _expected.keys()) - { - assertEquals("Values for " + key + " did not match", _expected.getObject(key), actual.getObject(key)); - } - } - } - - public void onMessage(Message message) - { - synchronized (received) - { - received.add((JMSBytesMessage) message); - _waitForCompletion.countDown(); - } - } - - private static String randomize(String in) - { - return in + System.currentTimeMillis(); - } - - public static void main(String[] argv) throws Exception - { - FieldTableMessageTest test = new FieldTableMessageTest(); - test._connectionString = (argv.length == 0) ? "vm://:1" : argv[0]; - test.setUp(); - test._count = (argv.length > 1) ? Integer.parseInt(argv[1]) : 5; - test.test(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java deleted file mode 100644 index 8961574d1e..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.test.unit.basic; - -import java.util.Collections; -import java.util.Map; -import javax.jms.Connection; -import javax.jms.InvalidDestinationException; -import javax.jms.JMSException; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.QueueSender; -import javax.jms.QueueSession; -import javax.jms.Session; -import javax.jms.TextMessage; -import javax.jms.Topic; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.jms.ConnectionURL; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class InvalidDestinationTest extends QpidBrokerTestCase -{ - private AMQConnection _connection; - - protected void setUp() throws Exception - { - super.setUp(); - _connection = (AMQConnection) getConnection("guest", "guest"); - } - - protected void tearDown() throws Exception - { - _connection.close(); - super.tearDown(); - } - - public void testInvalidDestination() throws Exception - { - QueueSession queueSession = _connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); - - Queue invalidDestination = queueSession.createQueue("unknownQ"); - - Queue validDestination = queueSession.createQueue(getTestQueueName()); - - // This is the only easy way to create and bind a queue from the API :-( - queueSession.createConsumer(validDestination); - QueueSender sender; - TextMessage msg= queueSession.createTextMessage("Hello"); - - try - { - sender = queueSession.createSender(invalidDestination); - - sender.send(msg); - fail("Expected InvalidDestinationException"); - } - catch (InvalidDestinationException ex) - { - // pass - } - - sender = queueSession.createSender(null); - - try - { - sender.send(invalidDestination,msg); - fail("Expected InvalidDestinationException"); - } - catch (InvalidDestinationException ex) - { - // pass - } - sender.send(validDestination,msg); - sender.close(); - sender = queueSession.createSender(validDestination); - sender.send(msg); - } - - /** - * Tests that specifying the {@value ClientProperties#VERIFY_QUEUE_ON_SEND} system property - * results in an exception when sending to an invalid queue destination. - */ - public void testInvalidDestinationOnMessageProducer() throws Exception - { - setTestSystemProperty(ClientProperties.VERIFY_QUEUE_ON_SEND, "true"); - final AMQConnection connection = (AMQConnection) getConnection(); - doInvalidDestinationOnMessageProducer(connection); - } - - /** - * Tests that specifying the {@value ConnectionURL.OPTIONS_VERIFY_QUEUE_ON_SEND} - * connection URL option property results in an exception when sending to an - * invalid queue destination. - */ - public void testInvalidDestinationOnMessageProducerURL() throws Exception - { - Map options = Collections.singletonMap(ConnectionURL.OPTIONS_VERIFY_QUEUE_ON_SEND, "true"); - doInvalidDestinationOnMessageProducer(getConnectionWithOptions(options)); - } - - private void doInvalidDestinationOnMessageProducer(Connection connection) throws JMSException - { - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - String invalidQueueName = getTestQueueName() + "UnknownQ"; - Queue invalidDestination = session.createQueue(invalidQueueName); - - String validQueueName = getTestQueueName() + "KnownQ"; - Queue validDestination = session.createQueue(validQueueName); - - // This is the only easy way to create and bind a queue from the API :-( - session.createConsumer(validDestination); - - MessageProducer sender; - TextMessage msg = session.createTextMessage("Hello"); - try - { - sender = session.createProducer(invalidDestination); - sender.send(msg); - fail("Expected InvalidDestinationException"); - } - catch (InvalidDestinationException ex) - { - // pass - } - - sender = session.createProducer(null); - invalidDestination = new AMQQueue("amq.direct",invalidQueueName); - - try - { - sender.send(invalidDestination,msg); - fail("Expected InvalidDestinationException"); - } - catch (InvalidDestinationException ex) - { - // pass - } - sender.send(validDestination, msg); - sender.close(); - sender = session.createProducer(validDestination); - sender.send(msg); - - //Verify sending to an 'invalid' Topic doesn't throw an exception - String invalidTopic = getTestQueueName() + "UnknownT"; - Topic topic = session.createTopic(invalidTopic); - sender = session.createProducer(topic); - sender.send(msg); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java deleted file mode 100644 index ace8324dab..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.test.unit.basic; - - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.TextMessage; - -public class LargeMessageTest extends QpidBrokerTestCase -{ - private static final Logger _logger = LoggerFactory.getLogger(LargeMessageTest.class); - - private Destination _destination; - private AMQSession _session; - private AMQConnection _connection; - - protected void setUp() throws Exception - { - super.setUp(); - try - { - _connection = (AMQConnection) getConnection("guest", "guest"); - init( _connection ); - } - catch (Exception e) - { - fail("Unable to initialilse connection: " + e); - } - } - - protected void tearDown() throws Exception - { - _connection.close(); - super.tearDown(); - } - - private void init(AMQConnection connection) throws Exception - { - Destination destination = new AMQQueue(connection, "LargeMessageTest", true); - init(connection, destination); - } - - private void init(AMQConnection connection, Destination destination) throws Exception - { - _destination = destination; - _session = (AMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - connection.start(); - } - - // Test boundary of 1 packet to 2 packets - public void test64kminus9() - { - checkLargeMessage((64 * 1024) - 9); - } - - public void test64kminus8() - { - checkLargeMessage((64 * 1024)-8); - } - - public void test64kminus7() - { - checkLargeMessage((64 * 1024)-7); - } - - - public void test64kplus1() - { - checkLargeMessage((64 * 1024) + 1); - } - - // Test packet boundary of 3 packtes - public void test128kminus1() - { - checkLargeMessage((128 * 1024) - 1); - } - - public void test128k() - { - checkLargeMessage(128 * 1024); - } - - public void test128kplus1() - { - checkLargeMessage((128 * 1024) + 1); - } - - // Testing larger messages - - public void test256k() - { - checkLargeMessage(256 * 1024); - } - - public void test512k() - { - checkLargeMessage(512 * 1024); - } - - public void test1024k() - { - checkLargeMessage(1024 * 1024); - } - - protected void checkLargeMessage(int messageSize) - { - try - { - MessageConsumer consumer = _session.createConsumer(_destination); - MessageProducer producer = _session.createProducer(_destination); - _logger.info("Testing message of size:" + messageSize); - - String _messageText = buildLargeMessage(messageSize); - - _logger.debug("Message built"); - - producer.send(_session.createTextMessage(_messageText)); - - TextMessage result = (TextMessage) consumer.receive(10000); - - assertNotNull("Null message recevied", result); - assertEquals("Message Size", _messageText.length(), result.getText().length()); - assertEquals("Message content differes", _messageText, result.getText()); - } - catch (JMSException e) - { - _logger.error("Exception occured", e); - fail("Exception occured:" + e.getCause()); - } - } - - private String buildLargeMessage(int size) - { - StringBuilder builder = new StringBuilder(size); - - char ch = 'a'; - - for (int i = 1; i <= size; i++) - { - builder.append(ch); - - if ((i % 1000) == 0) - { - ch++; - if (ch == ('z' + 1)) - { - ch = 'a'; - } - } - } - - return builder.toString(); - } - - public static junit.framework.Test suite() - { - return new junit.framework.TestSuite(LargeMessageTest.class); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/MapMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/MapMessageTest.java deleted file mode 100644 index 1b9c9fcb17..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/MapMessageTest.java +++ /dev/null @@ -1,1269 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.basic; - -import org.junit.Assert; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.message.JMSMapMessage; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.MapMessage; -import javax.jms.Message; -import javax.jms.MessageFormatException; -import javax.jms.MessageListener; -import javax.jms.MessageNotWriteableException; -import javax.jms.MessageProducer; -import javax.jms.Session; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -public class MapMessageTest extends QpidBrokerTestCase implements MessageListener -{ - private static final Logger _logger = LoggerFactory.getLogger(MapMessageTest.class); - - private AMQConnection _connection; - private Destination _destination; - private AMQSession _session; - private final List received = new ArrayList(); - - private static final String MESSAGE = "Message "; - private int _count = 100; - public String _connectionString = "vm://:1"; - private byte[] _bytes = { 99, 98, 97, 96, 95 }; - private static final float _smallfloat = 100.0f; - - protected void setUp() throws Exception - { - super.setUp(); - try - { - init((AMQConnection) getConnection("guest", "guest")); - } - catch (Exception e) - { - fail("Unable to initialilse connection: " + e); - } - } - - protected void tearDown() throws Exception - { - _logger.info("Tearing Down unit.basic.MapMessageTest"); - super.tearDown(); - } - - private void init(AMQConnection connection) throws Exception - { - Destination destination = new AMQQueue(connection, randomize("MapMessageTest"), true); - init(connection, destination); - } - - private void init(AMQConnection connection, Destination destination) throws Exception - { - _connection = connection; - _destination = destination; - _session = (AMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - // set up a slow consumer - _session.createConsumer(destination).setMessageListener(this); - connection.start(); - } - - public void test() throws Exception - { - int count = _count; - send(count); - waitFor(count); - check(); - _connection.close(); - } - - void send(int count) throws JMSException - { - // create a publisher - MessageProducer producer = _session.createProducer(_destination); - for (int i = 0; i < count; i++) - { - MapMessage message = _session.createMapMessage(); - - setMapValues(message, i); - - producer.send(message); - } - } - - private void setMapValues(MapMessage message, int i) throws JMSException - { - message.setBoolean("odd", (i / 2) == 0); - message.setByte("byte",Byte.MAX_VALUE); - message.setBytes("bytes", _bytes); - message.setChar("char",'c'); - message.setDouble("double", Double.MAX_VALUE); - message.setFloat("float", Float.MAX_VALUE); - message.setFloat("smallfloat", 100); - message.setInt("messageNumber", i); - message.setInt("int", Integer.MAX_VALUE); - message.setLong("long", Long.MAX_VALUE); - message.setShort("short", Short.MAX_VALUE); - message.setString("message", MESSAGE + i); - - // Test Setting Object Values - message.setObject("object-bool", true); - message.setObject("object-byte", Byte.MAX_VALUE); - message.setObject("object-bytes", _bytes); - message.setObject("object-char", 'c'); - message.setObject("object-double", Double.MAX_VALUE); - message.setObject("object-float", Float.MAX_VALUE); - message.setObject("object-int", Integer.MAX_VALUE); - message.setObject("object-long", Long.MAX_VALUE); - message.setObject("object-short", Short.MAX_VALUE); - - // Set a null String value - message.setString("nullString", null); - // Highlight protocol problem - message.setString("emptyString", ""); - - } - - void waitFor(int count) throws Exception - { - long waitTime = 30000L; - long waitUntilTime = System.currentTimeMillis() + 30000L; - - synchronized (received) - { - while ((received.size() < count) && (waitTime > 0)) - { - if (received.size() < count) - { - received.wait(waitTime); - } - - if (received.size() < count) - { - waitTime = waitUntilTime - System.currentTimeMillis(); - } - } - - if (received.size() < count) - { - throw new Exception("Timed-out. Waiting for " + count + " only got " + received.size()); - } - } - } - - void check() throws JMSException - { - int count = 0; - for (JMSMapMessage m : received) - { - testMapValues(m, count); - - testCorrectExceptions(m); - - testMessageWriteStatus(m); - - testPropertyWriteStatus(m); - - count++; - } - } - - private void testCorrectExceptions(JMSMapMessage m) throws JMSException - { - testBoolean(m); - - testByte(m); - - testBytes(m); - - testChar(m); - - testDouble(m); - - testFloat(m); - - testInt(m); - - testLong(m); - - testShort(m); - - testString(m); - } - - private void testString(JMSMapMessage m) throws JMSException - { - - Assert.assertFalse(m.getBoolean("message")); - - try - { - m.getByte("message"); - fail("Exception Expected."); - } - catch (NumberFormatException nfe) - { - // normal execution - } - - try - { - m.getShort("message"); - fail("Exception Expected."); - } - catch (NumberFormatException nfe) - { - // normal execution - } - - // Try bad reads - try - { - m.getChar("message"); - fail("Exception Expected."); - } - catch (MessageFormatException npe) - { - // normal execution - } - - try - { - m.getInt("message"); - fail("Exception Expected."); - } - catch (NumberFormatException nfe) - { - // normal execution - } - - try - { - m.getLong("message"); - fail("Exception Expected."); - } - catch (NumberFormatException nfe) - { - // normal execution - } - - // Try bad reads - try - { - m.getFloat("message"); - fail("Exception Expected."); - } - catch (NumberFormatException nfe) - { - // normal execution - } - // Try bad reads - try - { - m.getDouble("message"); - fail("Exception Expected."); - } - catch (NumberFormatException nfe) - { - // normal execution - } - // Try bad reads - try - { - m.getBytes("message"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - Assert.assertEquals(MESSAGE + m.getInt("messageNumber"), m.getString("message")); - } - - private void testShort(JMSMapMessage m) throws JMSException - { - - // Try bad reads - try - { - m.getBoolean("short"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - try - { - m.getByte("short"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - Assert.assertEquals(Short.MAX_VALUE, m.getShort("short")); - - // Try bad reads - try - { - m.getChar("short"); - fail("Exception Expected."); - } - catch (MessageFormatException npe) - { - // normal execution - } - - Assert.assertEquals(Short.MAX_VALUE, m.getInt("short")); - - Assert.assertEquals(Short.MAX_VALUE, m.getLong("short")); - - // Try bad reads - try - { - m.getFloat("short"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - // Try bad reads - try - { - m.getDouble("short"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - // Try bad reads - try - { - m.getBytes("short"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - Assert.assertEquals("" + Short.MAX_VALUE, m.getString("short")); - } - - private void testLong(JMSMapMessage m) throws JMSException - { - - // Try bad reads - try - { - m.getBoolean("long"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - try - { - m.getByte("long"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - try - { - m.getShort("long"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - // Try bad reads - try - { - m.getChar("long"); - fail("Exception Expected."); - } - catch (MessageFormatException npe) - { - // normal execution - } - - try - { - m.getInt("long"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - Assert.assertEquals(Long.MAX_VALUE, m.getLong("long")); - - // Try bad reads - try - { - m.getFloat("long"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - // Try bad reads - try - { - m.getDouble("long"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - // Try bad reads - try - { - m.getBytes("long"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - Assert.assertEquals("" + Long.MAX_VALUE, m.getString("long")); - } - - private void testDouble(JMSMapMessage m) throws JMSException - { - - // Try bad reads - try - { - m.getBoolean("double"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - try - { - m.getByte("double"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - try - { - m.getShort("double"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - // Try bad reads - try - { - m.getChar("double"); - fail("Exception Expected."); - } - catch (MessageFormatException npe) - { - // normal execution - } - - try - { - m.getInt("double"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - try - { - m.getLong("double"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - // Try bad reads - try - { - m.getFloat("double"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - Assert.assertEquals(Double.MAX_VALUE, m.getDouble("double"), 0d); - - // Try bad reads - try - { - m.getBytes("double"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - Assert.assertEquals("" + Double.MAX_VALUE, m.getString("double")); - } - - private void testFloat(JMSMapMessage m) throws JMSException - { - - // Try bad reads - try - { - m.getBoolean("float"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - try - { - m.getByte("float"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - try - { - m.getShort("float"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - // Try bad reads - try - { - m.getChar("float"); - fail("Exception Expected."); - } - catch (MessageFormatException npe) - { - // normal execution - } - - try - { - m.getInt("float"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - try - { - m.getLong("float"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - Assert.assertEquals(Float.MAX_VALUE, m.getFloat("float"), 0f); - - Assert.assertEquals(_smallfloat, m.getDouble("smallfloat"), 0f); - - // Try bad reads - try - { - m.getBytes("float"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - Assert.assertEquals("" + Float.MAX_VALUE, m.getString("float")); - } - - private void testInt(JMSMapMessage m) throws JMSException - { - - // Try bad reads - try - { - m.getBoolean("int"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - try - { - m.getByte("int"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - try - { - m.getShort("int"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - // Try bad reads - try - { - m.getChar("int"); - fail("Exception Expected."); - } - catch (MessageFormatException npe) - { - // normal execution - } - - Assert.assertEquals(Integer.MAX_VALUE, m.getInt("int")); - - Assert.assertEquals(Integer.MAX_VALUE, (int) m.getLong("int")); - - // Try bad reads - try - { - m.getFloat("int"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - // Try bad reads - try - { - m.getDouble("int"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - // Try bad reads - try - { - m.getBytes("int"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - Assert.assertEquals("" + Integer.MAX_VALUE, m.getString("int")); - } - - private void testChar(JMSMapMessage m) throws JMSException - { - - // Try bad reads - try - { - m.getBoolean("char"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - try - { - m.getByte("char"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - try - { - m.getShort("char"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - Assert.assertEquals('c', m.getChar("char")); - - try - { - m.getInt("char"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - try - { - m.getLong("char"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - // Try bad reads - try - { - m.getFloat("char"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - // Try bad reads - try - { - m.getDouble("char"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - // Try bad reads - try - { - m.getBytes("char"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - Assert.assertEquals("" + 'c', m.getString("char")); - } - - private void testBytes(JMSMapMessage m) throws JMSException - { - // Try bad reads - try - { - m.getBoolean("bytes"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - try - { - m.getByte("bytes"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - try - { - m.getShort("bytes"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - // Try bad reads - try - { - m.getChar("bytes"); - fail("Exception Expected."); - } - catch (MessageFormatException npe) - { - // normal execution - } - - try - { - m.getInt("bytes"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - try - { - m.getLong("bytes"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - // Try bad reads - try - { - m.getFloat("bytes"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - // Try bad reads - try - { - m.getDouble("bytes"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - assertBytesEqual(_bytes, m.getBytes("bytes")); - - try - { - m.getString("bytes"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - } - - private void testByte(JMSMapMessage m) throws JMSException - { - // Try bad reads - try - { - m.getBoolean("byte"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - Assert.assertEquals(Byte.MAX_VALUE, m.getByte("byte")); - - Assert.assertEquals((short) Byte.MAX_VALUE, m.getShort("byte")); - - // Try bad reads - try - { - m.getChar("byte"); - fail("Exception Expected."); - } - catch (MessageFormatException npe) - { - // normal execution - } - - // Reading a byte as an int is ok - Assert.assertEquals((short) Byte.MAX_VALUE, m.getInt("byte")); - - Assert.assertEquals((short) Byte.MAX_VALUE, m.getLong("byte")); - - // Try bad reads - try - { - m.getFloat("byte"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - // Try bad reads - try - { - m.getDouble("byte"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - // Try bad reads - try - { - m.getBytes("byte"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - Assert.assertEquals("" + Byte.MAX_VALUE, m.getString("byte")); - - } - - private void testBoolean(JMSMapMessage m) throws JMSException - { - - Assert.assertEquals((m.getInt("messageNumber") / 2) == 0, m.getBoolean("odd")); - - // Try bad reads - try - { - m.getByte("odd"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - // Try bad reads - try - { - m.getShort("odd"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - // Try bad reads - try - { - m.getChar("odd"); - fail("Exception Expected."); - } - catch (MessageFormatException npe) - { - // normal execution - } - // Try bad reads - try - { - m.getInt("odd"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - // Try bad reads - try - { - m.getLong("odd"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - // Try bad reads - try - { - m.getFloat("odd"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - // Try bad reads - try - { - m.getDouble("odd"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - // Try bad reads - try - { - m.getBytes("odd"); - fail("Exception Expected."); - } - catch (MessageFormatException nfe) - { - // normal execution - } - - Assert.assertEquals("" + ((m.getInt("messageNumber") / 2) == 0), m.getString("odd")); - } - - private void testPropertyWriteStatus(JMSMapMessage m) throws JMSException - { - // Check property write status - try - { - m.setStringProperty("test", "test"); - Assert.fail("Message should not be writeable"); - } - catch (MessageNotWriteableException mnwe) - { - // normal execution - } - - m.clearProperties(); - - try - { - m.setStringProperty("test", "test"); - } - catch (MessageNotWriteableException mnwe) - { - Assert.fail("Message should be writeable"); - } - } - - private void testMessageWriteStatus(JMSMapMessage m) throws JMSException - { - try - { - m.setInt("testint", 3); - fail("Message should not be writeable"); - } - catch (MessageNotWriteableException mnwe) - { - // normal execution - } - - m.clearBody(); - - try - { - m.setInt("testint", 3); - } - catch (MessageNotWriteableException mnwe) - { - Assert.fail("Message should be writeable"); - } - } - - private void testMapValues(JMSMapMessage m, int count) throws JMSException - { - // Test get - - // Boolean - assertEqual((count / 2) == 0, m.getBoolean("odd")); - assertEqual("" + ((count / 2) == 0), m.getString("odd")); - - // Byte - assertEqual(Byte.MAX_VALUE, m.getByte("byte")); - assertEqual("" + Byte.MAX_VALUE, m.getString("byte")); - - // Bytes - assertBytesEqual(_bytes, m.getBytes("bytes")); - - // Char - assertEqual('c', m.getChar("char")); - - // Double - assertEqual(Double.MAX_VALUE, m.getDouble("double")); - assertEqual("" + Double.MAX_VALUE, m.getString("double")); - - // Float - assertEqual(Float.MAX_VALUE, m.getFloat("float")); - assertEqual(_smallfloat, (float) m.getDouble("smallfloat")); - assertEqual("" + Float.MAX_VALUE, m.getString("float")); - - // Integer - assertEqual(Integer.MAX_VALUE, m.getInt("int")); - assertEqual("" + Integer.MAX_VALUE, m.getString("int")); - assertEqual(count, m.getInt("messageNumber")); - - // long - assertEqual(Long.MAX_VALUE, m.getLong("long")); - assertEqual("" + Long.MAX_VALUE, m.getString("long")); - - // Short - assertEqual(Short.MAX_VALUE, m.getShort("short")); - assertEqual("" + Short.MAX_VALUE, m.getString("short")); - assertEqual((int) Short.MAX_VALUE, m.getInt("short")); - - // String - assertEqual(MESSAGE + count, m.getString("message")); - - // Test getObjects - assertEqual(true, m.getObject("object-bool")); - assertEqual(Byte.MAX_VALUE, m.getObject("object-byte")); - assertBytesEqual(_bytes, (byte[]) m.getObject("object-bytes")); - assertEqual('c', m.getObject("object-char")); - assertEqual(Double.MAX_VALUE, m.getObject("object-double")); - assertEqual(Float.MAX_VALUE, m.getObject("object-float")); - assertEqual(Integer.MAX_VALUE, m.getObject("object-int")); - assertEqual(Long.MAX_VALUE, m.getObject("object-long")); - assertEqual(Short.MAX_VALUE, m.getObject("object-short")); - - // Check Special values - assertTrue(m.getString("nullString") == null); - assertEqual("", m.getString("emptyString")); - } - - private void assertBytesEqual(byte[] expected, byte[] actual) - { - Assert.assertEquals(expected.length, actual.length); - - for (int index = 0; index < expected.length; index++) - { - Assert.assertEquals(expected[index], actual[index]); - } - } - - private static void assertEqual(Iterator expected, Iterator actual) - { - List errors = new ArrayList(); - while (expected.hasNext() && actual.hasNext()) - { - try - { - assertEqual(expected.next(), actual.next()); - } - catch (Exception e) - { - errors.add(e.getMessage()); - } - } - while (expected.hasNext()) - { - errors.add("Expected " + expected.next() + " but no more actual values."); - } - while (actual.hasNext()) - { - errors.add("Found " + actual.next() + " but no more expected values."); - } - - if (!errors.isEmpty()) - { - throw new RuntimeException(errors.toString()); - } - } - - private static void assertEqual(Object expected, Object actual) - { - if (!expected.equals(actual)) - { - throw new RuntimeException("Expected '" + expected + "' found '" + actual + "'"); - } - } - - public void onMessage(Message message) - { - synchronized (received) - { - _logger.info("****************** Recevied Messgage:" + message); - received.add((JMSMapMessage) message); - received.notify(); - } - } - - private static String randomize(String in) - { - return in + System.currentTimeMillis(); - } - - public static void main(String[] argv) throws Exception - { - MapMessageTest test = new MapMessageTest(); - test._connectionString = (argv.length == 0) ? "vm://:1" : argv[0]; - test.setUp(); - if (argv.length > 1) - { - test._count = Integer.parseInt(argv[1]); - } - - test.test(); - } - - public static junit.framework.Test suite() - { - return new junit.framework.TestSuite(MapMessageTest.class); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java deleted file mode 100644 index 2d8847ea33..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.basic; - -import org.apache.qpid.framing.AMQShortString; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQDestination; -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; - -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageListener; -import javax.jms.MessageProducer; -import javax.jms.Session; - -public class MultipleConnectionTest extends QpidBrokerTestCase -{ - private static final Logger _logger = LoggerFactory.getLogger(MultipleConnectionTest.class); - - public static final String _defaultBroker = "vm://:1"; - public String _connectionString = _defaultBroker; - - private class Receiver - { - private AMQConnection _connection; - private Session[] _sessions; - private MessageCounter[] _counters; - - Receiver(String broker, AMQDestination dest, int sessions) throws Exception - { - this((AMQConnection) getConnection("guest", "guest"), dest, sessions); - } - - Receiver(AMQConnection connection, AMQDestination dest, int sessions) throws Exception - { - _connection = connection; - _sessions = new AMQSession[sessions]; - _counters = new MessageCounter[sessions]; - for (int i = 0; i < sessions; i++) - { - _sessions[i] = _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); - _counters[i] = new MessageCounter(_sessions[i].toString()); - _sessions[i].createConsumer(dest).setMessageListener(_counters[i]); - } - - _connection.start(); - } - - void close() throws JMSException - { - _connection.close(); - } - - public MessageCounter[] getCounters() - { - return _counters; - } - } - - private class Publisher - { - private AMQConnection _connection; - private Session _session; - private MessageProducer _producer; - - Publisher(String broker, AMQDestination dest) throws Exception - { - this((AMQConnection) getConnection("guest", "guest"), dest); - } - - Publisher(AMQConnection connection, AMQDestination dest) throws Exception - { - _connection = connection; - _session = _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); - _producer = _session.createProducer(dest); - } - - void send(String msg) throws JMSException - { - _producer.send(_session.createTextMessage(msg)); - } - - void close() throws JMSException - { - _connection.close(); - } - } - - private static class MessageCounter implements MessageListener - { - private final String _name; - private int _count; - - MessageCounter(String name) - { - _name = name; - } - - public synchronized void onMessage(Message message) - { - _count++; - notify(); - } - - synchronized boolean waitUntil(int expected, long maxWait) throws InterruptedException - { - long start = System.currentTimeMillis(); - while (expected > _count) - { - long timeLeft = maxWait - timeSince(start); - if (timeLeft <= 0) - { - break; - } - - wait(timeLeft); - } - - return expected <= _count; - } - - private long timeSince(long start) - { - return System.currentTimeMillis() - start; - } - - public synchronized String toString() - { - return _name + ": " + _count; - } - } - - private static void waitForCompletion(int expected, long wait, Receiver[] receivers) throws InterruptedException - { - for (int i = 0; i < receivers.length; i++) - { - waitForCompletion(expected, wait, receivers[i].getCounters()); - } - } - - private static void waitForCompletion(int expected, long wait, MessageCounter[] counters) throws InterruptedException - { - for (int i = 0; i < counters.length; i++) - { - if (!counters[i].waitUntil(expected, wait)) - { - throw new RuntimeException("Expected: " + expected + " got " + counters[i]); - } - } - } - - private static String randomize(String in) - { - return in + System.currentTimeMillis(); - } - - public static void main(String[] argv) throws Exception - { - String broker = (argv.length > 0) ? argv[0] : _defaultBroker; - - MultipleConnectionTest test = new MultipleConnectionTest(); - test._connectionString = broker; - test.test(); - } - - public void test() throws Exception - { - String broker = _connectionString; - int messages = 10; - - AMQTopic topic = new AMQTopic(AMQShortString.valueOf(ExchangeDefaults.TOPIC_EXCHANGE_NAME), "amq.topic"); - - Receiver[] receivers = new Receiver[] { new Receiver(broker, topic, 2), new Receiver(broker, topic, 14) }; - - Publisher publisher = new Publisher(broker, topic); - for (int i = 0; i < messages; i++) - { - publisher.send("Message " + (i + 1)); - } - - try - { - waitForCompletion(messages, 5000, receivers); - _logger.info("All receivers received all expected messages"); - } - finally - { - publisher.close(); - for (int i = 0; i < receivers.length; i++) - { - receivers[i].close(); - } - } - } - - public static junit.framework.Test suite() - { - return new junit.framework.TestSuite(MultipleConnectionTest.class); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/ObjectMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/ObjectMessageTest.java deleted file mode 100644 index 4b5922902d..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/ObjectMessageTest.java +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.basic; - -import org.junit.Assert; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.message.JMSObjectMessage; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageListener; -import javax.jms.MessageNotWriteableException; -import javax.jms.MessageProducer; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -public class ObjectMessageTest extends QpidBrokerTestCase implements MessageListener -{ - private static final Logger _logger = LoggerFactory.getLogger(ObjectMessageTest.class); - - private AMQConnection _connection; - private AMQDestination _destination; - private AMQSession _session; - private final List received = new ArrayList(); - private final List messages = new ArrayList(); - private int _count = 100; - public String _connectionString = "vm://:1"; - - protected void setUp() throws Exception - { - super.setUp(); - try - { - init( (AMQConnection) getConnection("guest", "guest")); - } - catch (Exception e) - { - fail("Uable to initialise: " + e); - } - } - - protected void tearDown() throws Exception - { - super.tearDown(); - } - - private void init(AMQConnection connection) throws Exception - { - init(connection, new AMQQueue(connection, randomize("ObjectMessageTest"), true)); - } - - private void init(AMQConnection connection, AMQDestination destination) throws Exception - { - _connection = connection; - _destination = destination; - _session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); - - // set up a slow consumer - _session.createConsumer(destination).setMessageListener(this); - connection.start(); - } - - public void test() throws Exception - { - int count = _count; - send(count); - waitFor(count); - check(); - _logger.info("Completed without failure"); - _connection.close(); - } - - void send(int count) throws JMSException - { - // create a publisher - MessageProducer producer = _session.createProducer(_destination); - for (int i = 0; i < count; i++) - { - Payload payload = new Payload("Message " + i); - messages.add(payload); - producer.send(_session.createObjectMessage(payload)); - } - } - - void waitFor(int count) throws InterruptedException - { - synchronized (received) - { - long endTime = System.currentTimeMillis() + 30000L; - while (received.size() < count) - { - received.wait(30000); - if(received.size() < count && System.currentTimeMillis() > endTime) - { - throw new RuntimeException("Only received " + received.size() + " messages, was expecting " + count); - } - } - } - } - - void check() throws JMSException - { - List actual = new ArrayList(); - for (JMSObjectMessage m : received) - { - actual.add(m.getObject()); - - try - { - m.setObject("Test text"); - Assert.fail("Message should not be writeable"); - } - catch (MessageNotWriteableException mnwe) - { - // normal execution - } - - m.clearBody(); - - try - { - m.setObject("Test text"); - } - catch (MessageNotWriteableException mnwe) - { - Assert.fail("Message should be writeable"); - } - - // Check property write status - try - { - m.setStringProperty("test", "test"); - Assert.fail("Message should not be writeable"); - } - catch (MessageNotWriteableException mnwe) - { - // normal execution - } - - m.clearProperties(); - - try - { - m.setStringProperty("test", "test"); - } - catch (MessageNotWriteableException mnwe) - { - Assert.fail("Message should be writeable"); - } - - } - - assertEqual(messages.iterator(), actual.iterator()); - - } - - private static void assertEqual(Iterator expected, Iterator actual) - { - List errors = new ArrayList(); - while (expected.hasNext() && actual.hasNext()) - { - try - { - assertEqual(expected.next(), actual.next()); - } - catch (Exception e) - { - errors.add(e.getMessage()); - } - } - while (expected.hasNext()) - { - errors.add("Expected " + expected.next() + " but no more actual values."); - } - while (actual.hasNext()) - { - errors.add("Found " + actual.next() + " but no more expected values."); - } - - if (!errors.isEmpty()) - { - throw new RuntimeException(errors.toString()); - } - } - - private static void assertEqual(Object expected, Object actual) - { - if (!expected.equals(actual)) - { - throw new RuntimeException("Expected '" + expected + "' found '" + actual + "'"); - } - } - - public void onMessage(Message message) - { - synchronized (received) - { - received.add((JMSObjectMessage) message); - received.notify(); - } - } - - private static String randomize(String in) - { - return in + System.currentTimeMillis(); - } - - private static class Payload implements Serializable - { - private final String data; - - Payload(String data) - { - this.data = data; - } - - public int hashCode() - { - return data.hashCode(); - } - - public boolean equals(Object o) - { - return (o instanceof Payload) && ((Payload) o).data.equals(data); - } - - public String toString() - { - return "Payload[" + data + "]"; - } - } - - public static void main(String[] argv) throws Exception - { - ObjectMessageTest test = new ObjectMessageTest(); - test._connectionString = (argv.length == 0) ? "vm://:1" : argv[0]; - test.setUp(); - if (argv.length > 1) - { - test._count = Integer.parseInt(argv[1]); - } - - test.test(); - } - - public static junit.framework.Test suite() - { - return new junit.framework.TestSuite(ObjectMessageTest.class); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/PropertyValueTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/PropertyValueTest.java deleted file mode 100644 index c7ff564beb..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/PropertyValueTest.java +++ /dev/null @@ -1,386 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.basic; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageFormatException; -import javax.jms.MessageListener; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.Session; - -import org.junit.Assert; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.message.JMSTextMessage; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class PropertyValueTest extends QpidBrokerTestCase implements MessageListener -{ - private static final Logger _logger = LoggerFactory.getLogger(PropertyValueTest.class); - - private AMQConnection _connection; - private Destination _destination; - private AMQSession _session; - private final List received = new ArrayList(); - private final List messages = new ArrayList(); - private Map _replyToDestinations; - private int _count = 1; - public String _connectionString = "vm://:1"; - private static final String USERNAME = "guest"; - - protected void setUp() throws Exception - { - _replyToDestinations = new HashMap(); - super.setUp(); - } - - protected void tearDown() throws Exception - { - super.tearDown(); - } - - private void init(AMQConnection connection) throws Exception - { - Destination destination = new AMQQueue(connection, randomize("PropertyValueTest"), true); - init(connection, destination); - } - - private void init(AMQConnection connection, Destination destination) throws Exception - { - _connection = connection; - _destination = destination; - _session = (AMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - // set up a slow consumer - _session.createConsumer(destination).setMessageListener(this); - connection.start(); - } - - private Message getTestMessage() throws Exception - { - Connection conn = getConnection(); - Session ssn = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - return ssn.createTextMessage(); - } - - public void testGetNonexistent() throws Exception - { - Message m = getTestMessage(); - String s = m.getStringProperty("nonexistent"); - assertNull(s); - } - - private static final String[] NAMES = { - "setBooleanProperty", "setByteProperty", "setShortProperty", - "setIntProperty", "setLongProperty", "setFloatProperty", - "setDoubleProperty", "setObjectProperty" - }; - - private static final Class[] TYPES = { - boolean.class, byte.class, short.class, int.class, long.class, - float.class, double.class, Object.class - }; - - private static final Object[] VALUES = { - true, (byte) 0, (short) 0, 0, (long) 0, (float) 0, (double) 0, - new Object() - }; - - public void testSetEmptyPropertyName() throws Exception - { - Message m = getTestMessage(); - - for (int i = 0; i < NAMES.length; i++) - { - Method meth = m.getClass().getMethod(NAMES[i], String.class, TYPES[i]); - try - { - meth.invoke(m, "", VALUES[i]); - fail("expected illegal argument exception"); - } - catch (InvocationTargetException e) - { - assertEquals(e.getCause().getClass(), IllegalArgumentException.class); - } - } - } - - public void testSetDisallowedClass() throws Exception - { - Message m = getTestMessage(); - try - { - m.setObjectProperty("foo", new Object()); - fail("expected a MessageFormatException"); - } - catch (MessageFormatException e) - { - // pass - } - } - - public void testOnce() - { - runBatch(1); - } - - public void test50() - { - runBatch(50); - } - - private void runBatch(int runSize) - { - try - { - int run = 0; - while (run < runSize) - { - _logger.error("Run Number:" + run++); - try - { - init( (AMQConnection) getConnection("guest", "guest")); - } - catch (Exception e) - { - _logger.error("exception:", e); - fail("Unable to initialilse connection: " + e); - } - - int count = _count; - send(count); - waitFor(count); - check(); - _logger.info("Completed without failure"); - - Thread.sleep(10); - _connection.close(); - - _logger.error("End Run Number:" + (run - 1)); - } - } - catch (Exception e) - { - _logger.error(e.getMessage(), e); - } - } - - void send(int count) throws JMSException - { - // create a publisher - MessageProducer producer = _session.createProducer(_destination); - for (int i = 0; i < count; i++) - { - String text = "Message " + i; - messages.add(text); - Message m = _session.createTextMessage(text); - - m.setBooleanProperty("Bool", true); - - m.setByteProperty("Byte", (byte) Byte.MAX_VALUE); - m.setDoubleProperty("Double", (double) Double.MAX_VALUE); - m.setFloatProperty("Float", (float) Float.MAX_VALUE); - m.setIntProperty("Int", (int) Integer.MAX_VALUE); - - m.setJMSCorrelationID("Correlation"); - // fixme the m.setJMSMessage has no effect - producer.setPriority(8); - m.setJMSPriority(3); - - // Queue - Queue q; - - if ((i / 2) == 0) - { - q = _session.createTemporaryQueue(); - } - else - { - q = new AMQQueue(_connection, "TestReply"); - } - - m.setJMSReplyTo(q); - - m.setStringProperty("ReplyToIndex", String.valueOf(i)); - _replyToDestinations.put(String.valueOf(i), q); - - _logger.debug("Message:" + m); - - m.setJMSType("Test"); - m.setLongProperty("UnsignedInt", (long) 4294967295L); - m.setLongProperty("Long", (long) Long.MAX_VALUE); - - m.setShortProperty("Short", (short) Short.MAX_VALUE); - m.setStringProperty("String", "Test"); - - _logger.debug("Sending Msg:" + m); - producer.send(m); - } - } - - void waitFor(int count) throws InterruptedException - { - synchronized (received) - { - while (received.size() < count) - { - received.wait(); - } - } - } - - void check() throws JMSException, URISyntaxException - { - List actual = new ArrayList(); - for (JMSTextMessage m : received) - { - actual.add(m.getText()); - - // Check Properties - - Assert.assertEquals("Check Boolean properties are correctly transported", true, m.getBooleanProperty("Bool")); - Assert.assertEquals("Check Byte properties are correctly transported", Byte.MAX_VALUE, - m.getByteProperty("Byte")); - Assert.assertEquals("Check Double properties are correctly transported", Double.MAX_VALUE, - m.getDoubleProperty("Double"), 0d); - Assert.assertEquals("Check Float properties are correctly transported", Float.MAX_VALUE, - m.getFloatProperty("Float"), 0f); - Assert.assertEquals("Check Int properties are correctly transported", Integer.MAX_VALUE, - m.getIntProperty("Int")); - Assert.assertEquals("Check CorrelationID properties are correctly transported", "Correlation", - m.getJMSCorrelationID()); - Assert.assertEquals("Check Priority properties are correctly transported", 8, m.getJMSPriority()); - - // Queue - String replyToIndex = m.getStringProperty("ReplyToIndex"); - Assert.assertEquals("Check ReplyTo properties are correctly transported", _replyToDestinations.get(replyToIndex), m.getJMSReplyTo()); - - Assert.assertEquals("Check Type properties are correctly transported", "Test", m.getJMSType()); - - Assert.assertEquals("Check Short properties are correctly transported", (short) Short.MAX_VALUE, - m.getShortProperty("Short")); - Assert.assertEquals("Check UnsignedInt properties are correctly transported", (long) 4294967295L, - m.getLongProperty("UnsignedInt")); - Assert.assertEquals("Check Long properties are correctly transported", (long) Long.MAX_VALUE, - m.getLongProperty("Long")); - Assert.assertEquals("Check String properties are correctly transported", "Test", m.getStringProperty("String")); - - //JMSXUserID - if (m.getStringProperty("JMSXUserID") != null) - { - Assert.assertEquals("Check 'JMSXUserID' is supported ", USERNAME, - m.getStringProperty("JMSXUserID")); - } - } - - received.clear(); - - assertEqual(messages.iterator(), actual.iterator()); - - messages.clear(); - } - - private static void assertEqual(Iterator expected, Iterator actual) - { - List errors = new ArrayList(); - while (expected.hasNext() && actual.hasNext()) - { - try - { - assertEqual(expected.next(), actual.next()); - } - catch (Exception e) - { - errors.add(e.getMessage()); - } - } - while (expected.hasNext()) - { - errors.add("Expected " + expected.next() + " but no more actual values."); - } - while (actual.hasNext()) - { - errors.add("Found " + actual.next() + " but no more expected values."); - } - - if (!errors.isEmpty()) - { - throw new RuntimeException(errors.toString()); - } - } - - private static void assertEqual(Object expected, Object actual) - { - if (!expected.equals(actual)) - { - throw new RuntimeException("Expected '" + expected + "' found '" + actual + "'"); - } - } - - public void onMessage(Message message) - { - synchronized (received) - { - received.add((JMSTextMessage) message); - received.notify(); - } - } - - private static String randomize(String in) - { - return in + System.currentTimeMillis(); - } - - public static void main(String[] argv) throws Exception - { - PropertyValueTest test = new PropertyValueTest(); - test._connectionString = (argv.length == 0) ? "vm://:1" : argv[0]; - test.setUp(); - if (argv.length > 1) - { - test._count = Integer.parseInt(argv[1]); - } - - test.testOnce(); - } - - public static junit.framework.Test suite() - { - return new junit.framework.TestSuite(PropertyValueTest.class); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/PubSubTwoConnectionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/PubSubTwoConnectionTest.java deleted file mode 100644 index 3ef8524656..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/PubSubTwoConnectionTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.basic; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.TextMessage; -import javax.jms.Topic; - -/** - * @author Apache Software Foundation - */ -public class PubSubTwoConnectionTest extends QpidBrokerTestCase -{ - protected void setUp() throws Exception - { - super.setUp(); - } - - protected void tearDown() throws Exception - { - super.tearDown(); - } - - /** - * This tests that a consumer is set up synchronously - * @throws Exception - */ - public void testTwoConnections() throws Exception - { - - AMQConnection con1 = (AMQConnection) getConnection("guest", "guest"); - - Topic topic = new AMQTopic(con1, "MyTopic"); - - Session session1 = con1.createSession(false, AMQSession.NO_ACKNOWLEDGE); - MessageProducer producer = session1.createProducer(topic); - - Connection con2 = (AMQConnection) getConnection("guest", "guest") ; - Session session2 = con2.createSession(false, AMQSession.NO_ACKNOWLEDGE); - MessageConsumer consumer = session2.createConsumer(topic); - con2.start(); - producer.send(session1.createTextMessage("Hello")); - TextMessage tm1 = (TextMessage) consumer.receive(2000); - assertNotNull(tm1); - assertEquals("Hello", tm1.getText()); - con1.close(); - con2.close(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SessionStartTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SessionStartTest.java deleted file mode 100644 index cc64dbb125..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SessionStartTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.basic; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageListener; - -public class SessionStartTest extends QpidBrokerTestCase implements MessageListener -{ - private static final Logger _logger = LoggerFactory.getLogger(SessionStartTest.class); - - private AMQConnection _connection; - private AMQDestination _destination; - private AMQSession _session; - private int count; - public String _connectionString = "vm://:1"; - - protected void setUp() throws Exception - { - super.setUp(); - init((AMQConnection) getConnection("guest", "guest")); - } - - protected void tearDown() throws Exception - { - super.tearDown(); - } - - private void init(AMQConnection connection) throws Exception - { - init(connection, - new AMQQueue(connection.getDefaultQueueExchangeName(), new AMQShortString(randomize("SessionStartTest")), true)); - } - - private void init(AMQConnection connection, AMQDestination destination) throws Exception - { - _connection = connection; - _destination = destination; - connection.start(); - - _session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); - _session.createConsumer(destination).setMessageListener(this); - } - - public synchronized void test() throws JMSException, InterruptedException - { - try - { - _session.createProducer(_destination).send(_session.createTextMessage("Message")); - _logger.info("Message sent, waiting for response..."); - wait(1000); - if (count > 0) - { - _logger.info("Got message"); - } - else - { - throw new RuntimeException("Did not get message!"); - } - } - finally - { - _session.close(); - _connection.close(); - } - } - - public synchronized void onMessage(Message message) - { - count++; - notify(); - } - - private static String randomize(String in) - { - return in + System.currentTimeMillis(); - } - - public static void main(String[] argv) throws Exception - { - SessionStartTest test = new SessionStartTest(); - test._connectionString = (argv.length == 0) ? "localhost:5672" : argv[0]; - test.setUp(); - test.test(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/TextMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/TextMessageTest.java deleted file mode 100644 index d4081817ee..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/TextMessageTest.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.basic; - -import org.junit.Assert; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.message.JMSTextMessage; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageListener; -import javax.jms.MessageNotWriteableException; -import javax.jms.MessageProducer; -import javax.jms.Session; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -public class TextMessageTest extends QpidBrokerTestCase implements MessageListener -{ - private static final Logger _logger = LoggerFactory.getLogger(TextMessageTest.class); - - private AMQConnection _connection; - private Destination _destination; - private AMQSession _session; - private final List received = new ArrayList(); - private final List messages = new ArrayList(); - private int _count = 100; - public String _connectionString = "vm://:1"; - private CountDownLatch _waitForCompletion; - - protected void setUp() throws Exception - { - super.setUp(); - try - { - init((AMQConnection) getConnection("guest", "guest")); - } - catch (Exception e) - { - fail("Unable to initialilse connection: " + e); - } - } - - protected void tearDown() throws Exception - { - super.tearDown(); - } - - private void init(AMQConnection connection) throws Exception - { - Destination destination = - new AMQQueue(connection.getDefaultQueueExchangeName(), new AMQShortString(randomize("TextMessageTest")), true); - init(connection, destination); - } - - private void init(AMQConnection connection, Destination destination) throws Exception - { - _connection = connection; - _destination = destination; - _session = (AMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - // set up a slow consumer - try - { - _session.createConsumer(destination).setMessageListener(this); - } - catch (Throwable e) - { - _logger.error("Error creating consumer", e); - } - connection.start(); - } - - public void test() throws Exception - { - int count = _count; - _waitForCompletion = new CountDownLatch(_count); - send(count); - _waitForCompletion.await(20, TimeUnit.SECONDS); - check(); - _logger.info("Completed without failure"); - _connection.close(); - } - - void send(int count) throws JMSException - { - // create a publisher - MessageProducer producer = _session.createProducer(_destination); - for (int i = 0; i < count; i++) - { - String text = "Message " + i; - messages.add(text); - Message m = _session.createTextMessage(text); - //m.setStringProperty("String", "hello"); - - _logger.info("Sending Msg:" + m); - producer.send(m); - } - _logger.info("sent " + count + " mesages"); - } - - - void check() throws JMSException - { - List actual = new ArrayList(); - for (JMSTextMessage m : received) - { - actual.add(m.getText()); - - // Check body write status - try - { - m.setText("Test text"); - Assert.fail("Message should not be writeable"); - } - catch (MessageNotWriteableException mnwe) - { - // normal execution - } - - m.clearBody(); - - try - { - m.setText("Test text"); - } - catch (MessageNotWriteableException mnwe) - { - Assert.fail("Message should be writeable"); - } - - // Check property write status - try - { - m.setStringProperty("test", "test"); - Assert.fail("Message should not be writeable"); - } - catch (MessageNotWriteableException mnwe) - { - // normal execution - } - - m.clearProperties(); - - try - { - m.setStringProperty("test", "test"); - } - catch (MessageNotWriteableException mnwe) - { - Assert.fail("Message should be writeable"); - } - - } - - assertEqual(messages.iterator(), actual.iterator()); - } - - private static void assertEqual(Iterator expected, Iterator actual) - { - List errors = new ArrayList(); - while (expected.hasNext() && actual.hasNext()) - { - try - { - assertEqual(expected.next(), actual.next()); - } - catch (Exception e) - { - errors.add(e.getMessage()); - } - } - while (expected.hasNext()) - { - errors.add("Expected " + expected.next() + " but no more actual values."); - } - while (actual.hasNext()) - { - errors.add("Found " + actual.next() + " but no more expected values."); - } - - if (!errors.isEmpty()) - { - throw new RuntimeException(errors.toString()); - } - } - - private static void assertEqual(Object expected, Object actual) - { - if (!expected.equals(actual)) - { - throw new RuntimeException("Expected '" + expected + "' found '" + actual + "'"); - } - } - - public void onMessage(Message message) - { - synchronized (received) - { - _logger.info("===== received one message"); - received.add((JMSTextMessage) message); - _waitForCompletion.countDown(); - } - } - - private static String randomize(String in) - { - return in + System.currentTimeMillis(); - } - - - - public static junit.framework.Test suite() - { - return new junit.framework.TestSuite(TextMessageTest.class); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/close/CloseTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/close/CloseTest.java deleted file mode 100644 index 48d290c986..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/basic/close/CloseTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.test.unit.basic.close; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.Session; - -public class CloseTest extends QpidBrokerTestCase -{ - private static final Logger _logger = LoggerFactory.getLogger(CloseTest.class); - - public void testCloseQueueReceiver() throws Exception - { - AMQConnection connection = (AMQConnection) getConnection("guest", "guest"); - - Session session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); - - Queue queue = session.createQueue("test-queue"); - MessageConsumer consumer = session.createConsumer(queue); - - MessageProducer producer_not_used_but_created_for_testing = session.createProducer(queue); - - connection.start(); - - _logger.info("About to close consumer"); - - consumer.close(); - - _logger.info("Closed Consumer"); - connection.close(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQSessionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQSessionTest.java deleted file mode 100644 index 0d81b66be0..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQSessionTest.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.client; - -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.test.utils.QpidBrokerTestCase; - -import javax.jms.JMSException; -import javax.jms.QueueReceiver; -import javax.jms.TopicSubscriber; - -/** - * Tests for QueueReceiver and TopicSubscriber creation methods on AMQSession - */ -public class AMQSessionTest extends QpidBrokerTestCase -{ - - private static AMQSession _session; - private static AMQTopic _topic; - private static AMQQueue _queue; - private static AMQConnection _connection; - - protected void setUp() throws Exception - { - super.setUp(); - _connection = (AMQConnection) getConnection("guest", "guest"); - _topic = new AMQTopic(_connection,"mytopic"); - _queue = new AMQQueue(_connection,"myqueue"); - _session = (AMQSession) _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); - } - - protected void tearDown() throws Exception - { - try - { - _connection.close(); - } - catch (JMSException e) - { - //just close - } - super.tearDown(); - } - - public void testCreateSubscriber() throws JMSException - { - TopicSubscriber subscriber = _session.createSubscriber(_topic); - assertEquals("Topic names should match from TopicSubscriber", _topic.getTopicName(), subscriber.getTopic().getTopicName()); - - subscriber = _session.createSubscriber(_topic, "abc", false); - assertEquals("Topic names should match from TopicSubscriber with selector", _topic.getTopicName(), subscriber.getTopic().getTopicName()); - } - - public void testCreateDurableSubscriber() throws JMSException - { - TopicSubscriber subscriber = _session.createDurableSubscriber(_topic, "mysubname"); - assertEquals("Topic names should match from durable TopicSubscriber", _topic.getTopicName(), subscriber.getTopic().getTopicName()); - - subscriber = _session.createDurableSubscriber(_topic, "mysubname2", "abc", false); - assertEquals("Topic names should match from durable TopicSubscriber with selector", _topic.getTopicName(), subscriber.getTopic().getTopicName()); - _session.unsubscribe("mysubname"); - _session.unsubscribe("mysubname2"); - } - - public void testCreateQueueReceiver() throws JMSException - { - QueueReceiver receiver = _session.createQueueReceiver(_queue); - assertEquals("Queue names should match from QueueReceiver", _queue.getQueueName(), receiver.getQueue().getQueueName()); - - receiver = _session.createQueueReceiver(_queue, "abc"); - assertEquals("Queue names should match from QueueReceiver with selector", _queue.getQueueName(), receiver.getQueue().getQueueName()); - } - - public void testCreateReceiver() throws JMSException - { - QueueReceiver receiver = _session.createReceiver(_queue); - assertEquals("Queue names should match from QueueReceiver", _queue.getQueueName(), receiver.getQueue().getQueueName()); - - receiver = _session.createReceiver(_queue, "abc"); - assertEquals("Queue names should match from QueueReceiver with selector", _queue.getQueueName(), receiver.getQueue().getQueueName()); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java deleted file mode 100644 index 77df6c58d9..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.client; - -import java.io.IOException; - -import org.apache.qpid.AMQException; -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.management.common.mbeans.ManagedExchange; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.url.BindingURL; - -import javax.jms.Connection; -import javax.jms.InvalidDestinationException; -import javax.jms.JMSException; -import javax.jms.Queue; -import javax.jms.Session; - -public class DynamicQueueExchangeCreateTest extends QpidBrokerTestCase -{ - private JMXTestUtils _jmxUtils; - - @Override - public void setUp() throws Exception - { - getBrokerConfiguration().addJmxManagementConfiguration(); - - _jmxUtils = new JMXTestUtils(this); - - super.setUp(); - _jmxUtils.open(); - } - - @Override - public void tearDown() throws Exception - { - try - { - if (_jmxUtils != null) - { - _jmxUtils.close(); - } - } - finally - { - super.tearDown(); - } - } - - /* - * Tests to validate that setting the respective qpid.declare_queues, - * qpid.declare_exchanges system properties functions as expected. - */ - - public void testQueueNotDeclaredDuringConsumerCreation() throws Exception - { - setSystemProperty(ClientProperties.QPID_DECLARE_QUEUES_PROP_NAME, "false"); - - Connection connection = getConnection(); - - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - Queue queue = session.createQueue(getTestQueueName()); - - try - { - session.createConsumer(queue); - fail("JMSException should be thrown as the queue does not exist"); - } - catch (JMSException e) - { - checkExceptionErrorCode(e, AMQConstant.NOT_FOUND); - } - } - - public void testExchangeNotDeclaredDuringConsumerCreation() throws Exception - { - setSystemProperty(ClientProperties.QPID_DECLARE_EXCHANGES_PROP_NAME, "false"); - - Connection connection = getConnection(); - - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - String exchangeName = getTestQueueName(); - Queue queue = session.createQueue("direct://" + exchangeName + "/queue/queue"); - - try - { - session.createConsumer(queue); - fail("JMSException should be thrown as the exchange does not exist"); - } - catch (JMSException e) - { - checkExceptionErrorCode(e, AMQConstant.NOT_FOUND); - } - - //verify the exchange was not declared - String exchangeObjectName = _jmxUtils.getExchangeObjectName("test", exchangeName); - assertFalse("exchange should not exist", _jmxUtils.doesManagedObjectExist(exchangeObjectName)); - } - - /** - * Checks that setting {@value ClientProperties#QPID_DECLARE_EXCHANGES_PROP_NAME} false results in - * disabling implicit ExchangeDeclares during producer creation when using a {@link BindingURL} - */ - public void testExchangeNotDeclaredDuringProducerCreation() throws Exception - { - Connection connection = getConnection(); - Session session1 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - String exchangeName1 = getTestQueueName() + "1"; - - - Queue queue = session1.createQueue("direct://" + exchangeName1 + "/queue/queue"); - session1.createProducer(queue); - - //close the session to ensure any previous commands were fully processed by - //the broker before observing their effect - session1.close(); - - //verify the exchange was declared - String exchangeObjectName = _jmxUtils.getExchangeObjectName("test", exchangeName1); - assertTrue("exchange should exist", _jmxUtils.doesManagedObjectExist(exchangeObjectName)); - - //Now disable the implicit exchange declares and try again - setSystemProperty(ClientProperties.QPID_DECLARE_EXCHANGES_PROP_NAME, "false"); - - Session session2 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - String exchangeName2 = getTestQueueName() + "2"; - - Queue queue2 = session2.createQueue("direct://" + exchangeName2 + "/queue/queue"); - session2.createProducer(queue2); - - //close the session to ensure any previous commands were fully processed by - //the broker before observing their effect - session2.close(); - - //verify the exchange was not declared - String exchangeObjectName2 = _jmxUtils.getExchangeObjectName("test", exchangeName2); - assertFalse("exchange should not exist", _jmxUtils.doesManagedObjectExist(exchangeObjectName2)); - } - - public void testQueueNotBoundDuringConsumerCreation() throws Exception - { - setSystemProperty(ClientProperties.QPID_BIND_QUEUES_PROP_NAME, "false"); - setSystemProperty(ClientProperties.VERIFY_QUEUE_ON_SEND, "true"); - - Connection connection = getConnection(); - - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - Queue queue = session.createQueue(getTestQueueName()); - session.createConsumer(queue); - - try - { - session.createProducer(queue).send(session.createMessage()); - fail("JMSException should be thrown as the queue does not exist"); - } - catch (InvalidDestinationException ide) - { - //PASS - } - } - private void checkExceptionErrorCode(JMSException original, AMQConstant code) - { - Exception linked = original.getLinkedException(); - assertNotNull("Linked exception should have been set", linked); - assertTrue("Linked exception should be an AMQException", linked instanceof AMQException); - assertEquals("Error code should be " + code.getCode(), code, ((AMQException) linked).getErrorCode()); - } - - /* - * Tests to validate that the custom exchanges declared by the client during - * consumer and producer creation have the expected properties. - */ - - public void testPropertiesOfCustomExchangeDeclaredDuringProducerCreation() throws Exception - { - implTestPropertiesOfCustomExchange(true, false); - } - - public void testPropertiesOfCustomExchangeDeclaredDuringConsumerCreation() throws Exception - { - implTestPropertiesOfCustomExchange(false, true); - } - - private void implTestPropertiesOfCustomExchange(boolean createProducer, boolean createConsumer) throws Exception - { - Connection connection = getConnection(); - - Session session1 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - String exchangeName1 = getTestQueueName() + "1"; - String queueName1 = getTestQueueName() + "1"; - - Queue queue = session1.createQueue("direct://" + exchangeName1 + "/" + queueName1 + "/" + queueName1 + "?" + BindingURL.OPTION_EXCHANGE_AUTODELETE + "='true'"); - if(createProducer) - { - session1.createProducer(queue); - } - - if(createConsumer) - { - session1.createConsumer(queue); - } - session1.close(); - - //verify the exchange was declared to expectation - verifyDeclaredExchange(exchangeName1, true, false); - - Session session2 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - String exchangeName2 = getTestQueueName() + "2"; - String queueName2 = getTestQueueName() + "2"; - - Queue queue2 = session2.createQueue("direct://" + exchangeName2 + "/" + queueName2 + "/" + queueName2 + "?" + BindingURL.OPTION_EXCHANGE_DURABLE + "='true'"); - if(createProducer) - { - session2.createProducer(queue2); - } - - if(createConsumer) - { - session2.createConsumer(queue2); - } - session2.close(); - - //verify the exchange was declared to expectation - verifyDeclaredExchange(exchangeName2, false, true); - } - - private void verifyDeclaredExchange(String exchangeName, boolean isAutoDelete, boolean isDurable) throws IOException - { - String exchangeObjectName = _jmxUtils.getExchangeObjectName("test", exchangeName); - assertTrue("exchange should exist", _jmxUtils.doesManagedObjectExist(exchangeObjectName)); - ManagedExchange exchange = _jmxUtils.getManagedExchange(exchangeName); - assertEquals(isAutoDelete, exchange.isAutoDelete()); - assertEquals(isDurable,exchange.isDurable()); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/MaxDeliveryCountTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/MaxDeliveryCountTest.java deleted file mode 100644 index 5e1e38106a..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/MaxDeliveryCountTest.java +++ /dev/null @@ -1,660 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.client; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import javax.jms.Connection; -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.TextMessage; -import javax.jms.Topic; - -import org.apache.log4j.Logger; - -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.RejectBehaviour; -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.server.virtualhost.AbstractVirtualHost; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -/** - * Test that the MaxRedelivery feature works as expected, allowing the client to reject - * messages during rollback/recover whilst specifying they not be requeued if delivery - * to an application has been attempted a specified number of times. - * - * General approach: specify a set of messages which will cause the test client to then - * deliberately rollback/recover the session after consuming, and monitor that they are - * re-delivered the specified number of times before the client rejects them without requeue - * and then verify that they are not subsequently redelivered. - * - * Additionally, the queue used in the test is configured for DLQ'ing, and the test verifies - * that the messages rejected without requeue are then present on the appropriate DLQ. - */ -public class MaxDeliveryCountTest extends QpidBrokerTestCase -{ - private static final Logger _logger = Logger.getLogger(MaxDeliveryCountTest.class); - private boolean _failed; - private String _failMsg; - private static final int MSG_COUNT = 15; - private static final int MAX_DELIVERY_COUNT = 2; - private CountDownLatch _awaitCompletion; - - /** index numbers of messages to be redelivered */ - private final List _redeliverMsgs = Arrays.asList(1, 2, 5, 14); - - public void setUp() throws Exception - { - //enable DLQ/maximumDeliveryCount support for all queues at the vhost level - - TestBrokerConfiguration brokerConfiguration = getBrokerConfiguration(); - setTestSystemProperty("queue.deadLetterQueueEnabled","true"); - setTestSystemProperty("queue.maximumDeliveryAttempts", String.valueOf(MAX_DELIVERY_COUNT)); - - //Ensure management is on - brokerConfiguration.addJmxManagementConfiguration(); - - // Set client-side flag to allow the server to determine if messages - // dead-lettered or requeued. - if (!isBroker010()) - { - setTestClientSystemProperty(ClientProperties.REJECT_BEHAVIOUR_PROP_NAME, RejectBehaviour.SERVER.toString()); - } - super.setUp(); - - boolean durableSub = isDurSubTest(); - - //declare the test queue - Connection consumerConnection = getConnection(); - Session consumerSession = consumerConnection.createSession(false,Session.AUTO_ACKNOWLEDGE); - Destination destination = getDestination(consumerSession, durableSub); - if(durableSub) - { - consumerSession.createDurableSubscriber((Topic)destination, getName()).close(); - } - else - { - consumerSession.createConsumer(destination).close(); - } - - consumerConnection.close(); - - //Create Producer put some messages on the queue - Connection producerConnection = getConnection(); - producerConnection.start(); - Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageProducer producer = producerSession.createProducer(getDestination(producerSession, durableSub)); - - for (int count = 1; count <= MSG_COUNT; count++) - { - Message msg = producerSession.createTextMessage(generateContent(count)); - msg.setIntProperty("count", count); - producer.send(msg); - } - - producerConnection.close(); - - _failed = false; - _awaitCompletion = new CountDownLatch(1); - } - - private Destination getDestination(Session consumerSession, boolean durableSub) throws JMSException - { - if(durableSub) - { - return consumerSession.createTopic(getTestQueueName()); - } - else - { - return consumerSession.createQueue(getTestQueueName()); - } - } - - private String generateContent(int count) - { - return "Message " + count + " content."; - } - - /** - * Test that Max Redelivery is enforced when using onMessage() on a - * Client-Ack session. - */ - public void testAsynchronousClientAckSession() throws Exception - { - doTest(Session.CLIENT_ACKNOWLEDGE, _redeliverMsgs, false, false); - } - - /** - * Test that Max Redelivery is enforced when using onMessage() on a - * transacted session. - */ - public void testAsynchronousTransactedSession() throws Exception - { - doTest(Session.SESSION_TRANSACTED, _redeliverMsgs, false, false); - } - - /** - * Test that Max Redelivery is enforced when using onMessage() on an - * Auto-Ack session. - */ - public void testAsynchronousAutoAckSession() throws Exception - { - doTest(Session.AUTO_ACKNOWLEDGE, _redeliverMsgs, false, false); - } - - /** - * Test that Max Redelivery is enforced when using onMessage() on a - * Dups-OK session. - */ - public void testAsynchronousDupsOkSession() throws Exception - { - doTest(Session.DUPS_OK_ACKNOWLEDGE, _redeliverMsgs, false, false); - } - - /** - * Test that Max Redelivery is enforced when using recieve() on a - * Client-Ack session. - */ - public void testSynchronousClientAckSession() throws Exception - { - doTest(Session.CLIENT_ACKNOWLEDGE, _redeliverMsgs, true, false); - } - - /** - * Test that Max Redelivery is enforced when using recieve() on a - * transacted session. - */ - public void testSynchronousTransactedSession() throws Exception - { - doTest(Session.SESSION_TRANSACTED, _redeliverMsgs, true, false); - } - - public void testDurableSubscription() throws Exception - { - doTest(Session.SESSION_TRANSACTED, _redeliverMsgs, false, true); - } - - public void testWhenBrokerIsRestartedAfterEnqeuingMessages() throws Exception - { - restartBroker(); - - doTest(Session.SESSION_TRANSACTED, _redeliverMsgs, true, false); - } - - private void doTest(final int deliveryMode, final List redeliverMsgs, final boolean synchronous, final boolean durableSub) throws Exception - { - final Connection clientConnection = getConnection(); - - final boolean transacted = deliveryMode == Session.SESSION_TRANSACTED ? true : false; - final Session clientSession = clientConnection.createSession(transacted, deliveryMode); - - MessageConsumer consumer; - Destination dest = getDestination(clientSession, durableSub); - AMQQueue checkQueue; - if(durableSub) - { - consumer = clientSession.createDurableSubscriber((Topic)dest, getName()); - checkQueue = new AMQQueue("amq.topic", "clientid" + ":" + getName()); - } - else - { - consumer = clientSession.createConsumer(dest); - checkQueue = (AMQQueue) dest; - } - - assertEquals("The queue should have " + MSG_COUNT + " msgs at start", - MSG_COUNT, ((AMQSession) clientSession).getQueueDepth(checkQueue)); - - clientConnection.start(); - - int expectedDeliveries = MSG_COUNT + ((MAX_DELIVERY_COUNT -1) * redeliverMsgs.size()); - - if(synchronous) - { - doSynchronousTest(clientSession, consumer, clientSession.getAcknowledgeMode(), - MAX_DELIVERY_COUNT, expectedDeliveries, redeliverMsgs); - } - else - { - addMessageListener(clientSession, consumer, clientSession.getAcknowledgeMode(), - MAX_DELIVERY_COUNT, expectedDeliveries, redeliverMsgs); - - try - { - if (!_awaitCompletion.await(20, TimeUnit.SECONDS)) - { - fail("Test did not complete in 20 seconds."); - } - } - catch (InterruptedException e) - { - fail("Unable to wait for test completion"); - throw e; - } - - if(_failed) - { - fail(_failMsg); - } - } - consumer.close(); - - //check the source queue is now empty - assertEquals("The queue should have 0 msgs left", 0, ((AMQSession) clientSession).getQueueDepth(checkQueue, true)); - - //check the DLQ has the required number of rejected-without-requeue messages - verifyDLQdepth(redeliverMsgs.size(), clientSession, durableSub); - - if(isBrokerStorePersistent()) - { - //restart the broker to verify persistence of the DLQ and the messages on it - clientConnection.close(); - - restartBroker(); - - final Connection clientConnection2 = getConnection(); - clientConnection2.start(); - - //verify the messages on the DLQ - verifyDLQcontent(clientConnection2, redeliverMsgs, getTestQueueName(), durableSub); - clientConnection2.close(); - } - else - { - - //verify the messages on the DLQ - verifyDLQcontent(clientConnection, redeliverMsgs, getTestQueueName(), durableSub); - clientConnection.close(); - } - - } - - private void verifyDLQdepth(int expected, Session clientSession, boolean durableSub) throws AMQException - { - AMQDestination checkQueueDLQ; - if(durableSub) - { - checkQueueDLQ = new AMQQueue("amq.topic", "clientid" + ":" + getName() + AbstractVirtualHost.DEFAULT_DLQ_NAME_SUFFIX); - } - else - { - checkQueueDLQ = new AMQQueue("amq.direct", getTestQueueName() + AbstractVirtualHost.DEFAULT_DLQ_NAME_SUFFIX); - } - - assertEquals("The DLQ should have " + expected + " msgs on it", expected, - ((AMQSession) clientSession).getQueueDepth(checkQueueDLQ, true)); - } - - private void verifyDLQcontent(Connection clientConnection, List redeliverMsgs, String destName, boolean durableSub) throws JMSException - { - Session clientSession = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - MessageConsumer consumer; - if(durableSub) - { - consumer = clientSession.createConsumer(clientSession.createQueue("clientid:" +getName() + AbstractVirtualHost.DEFAULT_DLQ_NAME_SUFFIX)); - } - else - { - consumer = clientSession.createConsumer( - clientSession.createQueue(destName + AbstractVirtualHost.DEFAULT_DLQ_NAME_SUFFIX)); - } - - //keep track of the message we expect to still be on the DLQ - List outstandingMessages = new ArrayList(redeliverMsgs); - int numMsg = outstandingMessages.size(); - - for(int i = 0; i < numMsg; i++) - { - Message message = consumer.receive(250); - - assertNotNull("failed to consume expected message " + i + " from DLQ", message); - assertTrue("message " + i + " was the wrong type", message instanceof TextMessage); - - //using Integer here to allow removing the value from the list, using int - //would instead result in removal of the element at that index - Integer msgId = message.getIntProperty("count"); - - TextMessage txt = (TextMessage) message; - _logger.info("Received message " + msgId + " at " + i + " from the DLQ: " + txt.getText()); - - assertTrue("message " + i + " was not one of those which should have been on the DLQ", - redeliverMsgs.contains(msgId)); - assertTrue("message " + i + " was not one of those expected to still be on the DLQ", - outstandingMessages.contains(msgId)); - assertEquals("Message " + i + " content was not as expected", generateContent(msgId), txt.getText()); - - //remove from the list of outstanding msgs - outstandingMessages.remove(msgId); - } - - if(outstandingMessages.size() > 0) - { - String failures = ""; - for(Integer msg : outstandingMessages) - { - failures = failures.concat(msg + " "); - } - fail("some DLQ'd messages were not found on the DLQ: " + failures); - } - } - - private void addMessageListener(final Session session, final MessageConsumer consumer, final int deliveryMode, final int maxDeliveryCount, - final int expectedTotalNumberOfDeliveries, final List redeliverMsgs) throws JMSException - { - if(deliveryMode == org.apache.qpid.jms.Session.NO_ACKNOWLEDGE - || deliveryMode == org.apache.qpid.jms.Session.PRE_ACKNOWLEDGE) - { - failAsyncTest("Max Delivery feature is not supported with this acknowledgement mode" + - "when using asynchronous message delivery."); - } - - consumer.setMessageListener(new MessageListener() - { - private int _deliveryAttempts = 0; //number of times given message(s) have been seen - private int _numMsgsToBeRedelivered = 0; //number of messages to rollback/recover - private int _totalNumDeliveries = 0; - private int _expectedMessage = 1; - - public void onMessage(Message message) - { - if(_failed || _awaitCompletion.getCount() == 0L) - { - //don't process anything else - return; - } - - _totalNumDeliveries++; - - if (message == null) - { - failAsyncTest("Should not get null messages"); - return; - } - - try - { - int msgId = message.getIntProperty("count"); - - _logger.info("Received message: " + msgId); - - //check the message is the one we expected - if(_expectedMessage != msgId) - { - failAsyncTest("Expected message " + _expectedMessage + " , got message " + msgId); - return; - } - - _expectedMessage++; - - //keep track of the overall deliveries to ensure we don't see more than expected - if(_totalNumDeliveries > expectedTotalNumberOfDeliveries) - { - failAsyncTest("Expected total of " + expectedTotalNumberOfDeliveries + - " message deliveries, reached " + _totalNumDeliveries); - } - - //check if this message is one chosen to be rolled back / recovered - if(redeliverMsgs.contains(msgId)) - { - _numMsgsToBeRedelivered++; - - //check if next message is going to be rolled back / recovered too - if(redeliverMsgs.contains(msgId +1)) - { - switch(deliveryMode) - { - case Session.SESSION_TRANSACTED: - //skip on to next message immediately - return; - case Session.CLIENT_ACKNOWLEDGE: - //skip on to next message immediately - return; - case Session.DUPS_OK_ACKNOWLEDGE: - //fall through - case Session.AUTO_ACKNOWLEDGE: - //must recover session now or onMessage will ack, so - //just fall through the if - break; - } - } - - _deliveryAttempts++; //increment count of times the current rolled back/recovered message(s) have been seen - - _logger.debug("ROLLBACK/RECOVER"); - switch(deliveryMode) - { - case Session.SESSION_TRANSACTED: - session.rollback(); - break; - case Session.CLIENT_ACKNOWLEDGE: - //fall through - case Session.DUPS_OK_ACKNOWLEDGE: - //fall through - case Session.AUTO_ACKNOWLEDGE: - session.recover(); - break; - } - - if( _deliveryAttempts >= maxDeliveryCount) - { - //the client should have rejected the latest messages upon then - //above recover/rollback, adjust counts to compensate - _deliveryAttempts = 0; - } - else - { - //the message(s) should be redelivered, adjust expected message - _expectedMessage -= _numMsgsToBeRedelivered; - } - _logger.debug("XXX _expectedMessage: " + _expectedMessage + " _deliveryAttempts : " + _deliveryAttempts + " _numMsgsToBeRedelivered=" + _numMsgsToBeRedelivered); - //reset count of messages expected to be redelivered - _numMsgsToBeRedelivered = 0; - } - else - { - //consume the message - switch(deliveryMode) - { - case Session.SESSION_TRANSACTED: - session.commit(); - break; - case Session.CLIENT_ACKNOWLEDGE: - message.acknowledge(); - break; - case Session.DUPS_OK_ACKNOWLEDGE: - //fall-through - case Session.AUTO_ACKNOWLEDGE: - //do nothing, onMessage will ack on exit. - break; - } - } - - if (msgId == MSG_COUNT) - { - //if this is the last message let the test complete. - if (expectedTotalNumberOfDeliveries == _totalNumDeliveries) - { - _awaitCompletion.countDown(); - } - else - { - failAsyncTest("Last message received, but we have not had the " + - "expected number of total delivieres. Received " + _totalNumDeliveries + " Expecting : " + expectedTotalNumberOfDeliveries); - } - } - } - catch (JMSException e) - { - failAsyncTest(e.getMessage()); - } - } - }); - } - - private void failAsyncTest(String msg) - { - _logger.error("Failing test because: " + msg); - _failMsg = msg; - _failed = true; - _awaitCompletion.countDown(); - } - - private void doSynchronousTest(final Session session, final MessageConsumer consumer, final int deliveryMode, final int maxDeliveryCount, - final int expectedTotalNumberOfDeliveries, final List redeliverMsgs) throws JMSException, AMQException, InterruptedException - { - if(deliveryMode == Session.AUTO_ACKNOWLEDGE - || deliveryMode == Session.DUPS_OK_ACKNOWLEDGE - || deliveryMode == org.apache.qpid.jms.Session.PRE_ACKNOWLEDGE - || deliveryMode == org.apache.qpid.jms.Session.NO_ACKNOWLEDGE) - { - fail("Max Delivery feature is not supported with this acknowledgement mode" + - "when using synchronous message delivery."); - } - - int _deliveryAttempts = 0; //number of times given message(s) have been seen - int _numMsgsToBeRedelivered = 0; //number of messages to rollback/recover - int _totalNumDeliveries = 0; - int _expectedMessage = 1; - - while(!_failed) - { - Message message = consumer.receive(1000); - - _totalNumDeliveries++; - - if (message == null) - { - fail("Should not get null messages"); - return; - } - - try - { - int msgId = message.getIntProperty("count"); - - _logger.info("Received message: " + msgId); - - //check the message is the one we expected - assertEquals("Unexpected message.", _expectedMessage, msgId); - - _expectedMessage++; - - //keep track of the overall deliveries to ensure we don't see more than expected - assertTrue("Exceeded expected total number of deliveries.", - _totalNumDeliveries <= expectedTotalNumberOfDeliveries ); - - //check if this message is one chosen to be rolled back / recovered - if(redeliverMsgs.contains(msgId)) - { - //keep track of the number of messages we will have redelivered - //upon rollback/recover - _numMsgsToBeRedelivered++; - - if(redeliverMsgs.contains(msgId +1)) - { - //next message is going to be rolled back / recovered too. - //skip ahead to it - continue; - } - - _deliveryAttempts++; //increment count of times the current rolled back/recovered message(s) have been seen - - switch(deliveryMode) - { - case Session.SESSION_TRANSACTED: - session.rollback(); - break; - case Session.CLIENT_ACKNOWLEDGE: - session.recover(); - - //sleep then do a synchronous op to give the broker - //time to resend all the messages - Thread.sleep(500); - ((AMQSession) session).sync(); - break; - } - - if( _deliveryAttempts >= maxDeliveryCount) - { - //the client should have rejected the latest messages upon then - //above recover/rollback, adjust counts to compensate - _deliveryAttempts = 0; - } - else - { - //the message(s) should be redelivered, adjust expected message - _expectedMessage -= _numMsgsToBeRedelivered; - } - - //As we just rolled back / recovered, we must reset the - //count of messages expected to be redelivered - _numMsgsToBeRedelivered = 0; - } - else - { - //consume the message - switch(deliveryMode) - { - case Session.SESSION_TRANSACTED: - session.commit(); - break; - case Session.CLIENT_ACKNOWLEDGE: - message.acknowledge(); - break; - } - } - - if (msgId == MSG_COUNT) - { - //if this is the last message let the test complete. - assertTrue("Last message received, but we have not had the " + - "expected number of total delivieres", - expectedTotalNumberOfDeliveries == _totalNumDeliveries); - - break; - } - } - catch (JMSException e) - { - fail(e.getMessage()); - } - } - } - - private boolean isDurSubTest() - { - return getTestQueueName().contains("DurableSubscription"); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/QueueSessionFactoryTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/QueueSessionFactoryTest.java deleted file mode 100644 index 370e44b3d5..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/QueueSessionFactoryTest.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.client; - -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.QueueConnection; -import javax.jms.QueueSession; -import javax.jms.Session; -import javax.jms.Topic; -import javax.jms.TopicSession; - -/** - * Ensures that queue specific session factory method {@link QueueConnection#createQueueSession()} create sessions - * of type {@link QueueSession} and that those sessions correctly restrict the available JMS operations - * operations to exclude those applicable to only topics. - * - * @see TopicSessionFactoryTest - */ -public class QueueSessionFactoryTest extends QpidBrokerTestCase -{ - public void testQueueSessionIsNotATopicSession() throws Exception - { - QueueSession queueSession = getQueueSession(); - assertFalse(queueSession instanceof TopicSession); - } - - public void testQueueSessionCannotCreateTemporaryTopics() throws Exception - { - QueueSession queueSession = getQueueSession(); - try - { - queueSession.createTemporaryTopic(); - fail("expected exception did not occur"); - } - catch (javax.jms.IllegalStateException s) - { - // PASS - assertEquals("Cannot call createTemporaryTopic from QueueSession", s.getMessage()); - } - } - - public void testQueueSessionCannotCreateTopics() throws Exception - { - QueueSession queueSession = getQueueSession(); - try - { - queueSession.createTopic("abc"); - fail("expected exception did not occur"); - } - catch (javax.jms.IllegalStateException s) - { - // PASS - assertEquals("Cannot call createTopic from QueueSession", s.getMessage()); - } - } - - public void testQueueSessionCannotCreateDurableSubscriber() throws Exception - { - QueueSession queueSession = getQueueSession(); - Topic topic = getTestTopic(); - - try - { - queueSession.createDurableSubscriber(topic, "abc"); - fail("expected exception did not occur"); - } - catch (javax.jms.IllegalStateException s) - { - // PASS - assertEquals("Cannot call createDurableSubscriber from QueueSession", s.getMessage()); - } - } - - public void testQueueSessionCannoutUnsubscribe() throws Exception - { - QueueSession queueSession = getQueueSession(); - try - { - queueSession.unsubscribe("abc"); - fail("expected exception did not occur"); - } - catch (javax.jms.IllegalStateException s) - { - // PASS - assertEquals("Cannot call unsubscribe from QueueSession", s.getMessage()); - } - } - - private QueueSession getQueueSession() throws Exception - { - QueueConnection queueConnection = (QueueConnection)getConnection(); - return queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/TopicSessionFactoryTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/TopicSessionFactoryTest.java deleted file mode 100644 index ce15d452ab..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/TopicSessionFactoryTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.client; - -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Queue; -import javax.jms.QueueSession; -import javax.jms.Session; -import javax.jms.TopicConnection; -import javax.jms.TopicSession; - -/** - * Ensures that topic specific session factory method {@link TopicConnection#createTopicSession()} create sessions - * of type {@link TopicSession} and that those sessions correctly restrict the available JMS operations - * operations to exclude those applicable to only queues. - * - * @see QueueSessionFactoryTest - */ -public class TopicSessionFactoryTest extends QpidBrokerTestCase -{ - public void testTopicSessionIsNotAQueueSession() throws Exception - { - TopicSession topicSession = getTopicSession(); - assertFalse(topicSession instanceof QueueSession); - } - - public void testTopicSessionCannotCreateCreateBrowser() throws Exception - { - TopicSession topicSession = getTopicSession(); - Queue queue = getTestQueue(); - try - { - topicSession.createBrowser(queue); - fail("expected exception did not occur"); - } - catch (javax.jms.IllegalStateException s) - { - // PASS - assertEquals("Cannot call createBrowser from TopicSession", s.getMessage()); - } - } - - public void testTopicSessionCannotCreateQueues() throws Exception - { - TopicSession topicSession = getTopicSession(); - try - { - topicSession.createQueue("abc"); - fail("expected exception did not occur"); - } - catch (javax.jms.IllegalStateException s) - { - // PASS - assertEquals("Cannot call createQueue from TopicSession", s.getMessage()); - } - } - - public void testTopicSessionCannotCreateTemporaryQueues() throws Exception - { - TopicSession topicSession = getTopicSession(); - try - { - topicSession.createTemporaryQueue(); - fail("expected exception did not occur"); - } - catch (javax.jms.IllegalStateException s) - { - // PASS - assertEquals("Cannot call createTemporaryQueue from TopicSession", s.getMessage()); - } - } - - private TopicSession getTopicSession() throws Exception - { - TopicConnection topicConnection = (TopicConnection)getConnection(); - return topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/CloseWithBlockingReceiveTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/CloseWithBlockingReceiveTest.java deleted file mode 100644 index 58f1bfe372..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/CloseWithBlockingReceiveTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.client.channelclose; - -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.MessageConsumer; -import javax.jms.Session; - -/** - * @author Apache Software Foundation - */ -public class CloseWithBlockingReceiveTest extends QpidBrokerTestCase -{ - - - public void testReceiveReturnsNull() throws Exception - { - final Connection connection = getConnection(); - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Destination destination = session.createQueue(getTestQueueName()); - MessageConsumer consumer = session.createConsumer(destination); - connection.start(); - - Runnable r = new Runnable() - { - - public void run() - { - try - { - Thread.sleep(1000); - connection.close(); - } - catch (Exception e) - { - } - } - }; - long startTime = System.currentTimeMillis(); - Thread thread = new Thread(r); - thread.start(); - try - { - consumer.receive(10000); - assertTrue(System.currentTimeMillis() - startTime < 10000); - } - finally - { - thread.join(); - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/BrokerClosesClientConnectionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/BrokerClosesClientConnectionTest.java deleted file mode 100644 index 4a92728d82..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/BrokerClosesClientConnectionTest.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.client.connection; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageListener; -import javax.jms.MessageProducer; -import javax.naming.NamingException; -import org.apache.qpid.AMQConnectionClosedException; -import org.apache.qpid.AMQDisconnectedException; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.transport.ConnectionException; - -import javax.jms.Connection; -import javax.jms.ExceptionListener; -import javax.jms.JMSException; -import javax.jms.Session; - -/** - * Tests the behaviour of the client when the Broker terminates client connection - * by the Broker being shutdown gracefully or otherwise. - * - * @see ManagedConnectionMBeanTest - */ -public class BrokerClosesClientConnectionTest extends QpidBrokerTestCase -{ - private Connection _connection; - private boolean _isExternalBroker; - private final RecordingExceptionListener _recordingExceptionListener = new RecordingExceptionListener(); - private Session _session; - - @Override - protected void setUp() throws Exception - { - super.setUp(); - - _connection = getConnection(); - _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - _connection.setExceptionListener(_recordingExceptionListener); - - _isExternalBroker = isExternalBroker(); - } - - public void testClientCloseOnNormalBrokerShutdown() throws Exception - { - final Class expectedLinkedException = isBroker010() ? ConnectionException.class : AMQConnectionClosedException.class; - - assertConnectionOpen(); - - stopBroker(); - - JMSException exception = _recordingExceptionListener.awaitException(10000); - assertConnectionCloseWasReported(exception, expectedLinkedException); - assertConnectionClosed(); - - ensureCanCloseWithoutException(); - } - - public void testClientCloseOnBrokerKill() throws Exception - { - final Class expectedLinkedException = isBroker010() ? ConnectionException.class : AMQDisconnectedException.class; - - if (!_isExternalBroker) - { - return; - } - - assertConnectionOpen(); - - killBroker(); - - JMSException exception = _recordingExceptionListener.awaitException(10000); - assertConnectionCloseWasReported(exception, expectedLinkedException); - assertConnectionClosed(); - - ensureCanCloseWithoutException(); - } - - private void ensureCanCloseWithoutException() - { - try - { - _connection.close(); - } - catch (JMSException e) - { - fail("Connection should close without exception" + e.getMessage()); - } - } - - private void assertConnectionCloseWasReported(JMSException exception, Class linkedExceptionClass) - { - assertNotNull("Broker shutdown should be reported to the client via the ExceptionListener", exception); - assertNotNull("JMXException should have linked exception", exception.getLinkedException()); - - assertEquals("Unexpected linked exception", linkedExceptionClass, exception.getLinkedException().getClass()); - } - - private void assertConnectionClosed() - { - assertTrue("Connection should be marked as closed", ((AMQConnection)_connection).isClosed()); - } - - private void assertConnectionOpen() - { - assertFalse("Connection should not be marked as closed", ((AMQConnection)_connection).isClosed()); - } - - private final class RecordingExceptionListener implements ExceptionListener - { - private final CountDownLatch _exceptionReceivedLatch = new CountDownLatch(1); - private volatile JMSException _exception; - - @Override - public void onException(JMSException exception) - { - _exception = exception; - } - - public JMSException awaitException(long timeoutInMillis) throws InterruptedException - { - _exceptionReceivedLatch.await(timeoutInMillis, TimeUnit.MILLISECONDS); - return _exception; - } - } - - - private class Listener implements MessageListener - { - int _messageCount; - - @Override - public synchronized void onMessage(Message message) - { - _messageCount++; - } - - public synchronized int getCount() - { - return _messageCount; - } - } - - public void testNoDeliveryAfterBrokerClose() throws JMSException, NamingException, InterruptedException - { - - Listener listener = new Listener(); - - Session session = _connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); - MessageConsumer consumer1 = session.createConsumer(getTestQueue()); - consumer1.setMessageListener(listener); - - MessageProducer producer = _session.createProducer(getTestQueue()); - producer.send(_session.createTextMessage("test message")); - - _connection.start(); - - - synchronized (listener) - { - long currentTime = System.currentTimeMillis(); - long until = currentTime + 2000l; - while(listener.getCount() == 0 && currentTime < until) - { - listener.wait(until - currentTime); - currentTime = System.currentTimeMillis(); - } - } - assertEquals(1, listener.getCount()); - - Connection connection2 = getConnection(); - Session session2 = connection2.createSession(false, Session.CLIENT_ACKNOWLEDGE); - MessageConsumer consumer2 = session2.createConsumer(getTestQueue()); - consumer2.setMessageListener(listener); - connection2.start(); - - - Connection connection3 = getConnection(); - Session session3 = connection3.createSession(false, Session.CLIENT_ACKNOWLEDGE); - MessageConsumer consumer3 = session3.createConsumer(getTestQueue()); - consumer3.setMessageListener(listener); - connection3.start(); - - assertEquals(1, listener.getCount()); - - stopBroker(); - - assertEquals(1, listener.getCount()); - - - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionFactoryTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionFactoryTest.java deleted file mode 100644 index bf1fbbf1a3..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionFactoryTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.client.connection; - -import javax.jms.Connection; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQConnectionFactory; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class ConnectionFactoryTest extends QpidBrokerTestCase -{ - - /** - * The username & password specified should not override the default - * specified in the URL. - */ - public void testCreateConnectionWithUsernamePassword() throws Exception - { - - String brokerUrl = getBroker().toString(); - String URL = "amqp://guest:guest@clientID/test?brokerlist='" + brokerUrl + "'"; - AMQConnectionFactory factory = new AMQConnectionFactory(URL); - - AMQConnection con = (AMQConnection)factory.createConnection(); - assertEquals("Usernames used is different from the one in URL","guest",con.getConnectionURL().getUsername()); - assertEquals("Password used is different from the one in URL","guest",con.getConnectionURL().getPassword()); - - try - { - AMQConnection con2 = (AMQConnection)factory.createConnection("user","pass"); - assertEquals("Usernames used is different from the one in URL","user",con2.getConnectionURL().getUsername()); - assertEquals("Password used is different from the one in URL","pass",con2.getConnectionURL().getPassword()); - } - catch(Exception e) - { - // ignore - } - - AMQConnection con3 = (AMQConnection)factory.createConnection(); - assertEquals("Usernames used is different from the one in URL","guest",con3.getConnectionURL().getUsername()); - assertEquals("Password used is different from the one in URL","guest",con3.getConnectionURL().getPassword()); - } - - /** - * Verifies that a connection can be made using an instance of AMQConnectionFactory created with the - * default constructor and provided with the connection url via setter. - */ - public void testCreatingConnectionWithInstanceMadeUsingDefaultConstructor() throws Exception - { - String broker = getBroker().toString(); - String url = "amqp://guest:guest@clientID/test?brokerlist='" + broker + "'"; - - AMQConnectionFactory factory = new AMQConnectionFactory(); - factory.setConnectionURLString(url); - - Connection con = factory.createConnection(); - con.close(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.java deleted file mode 100644 index 6ea1582bb8..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.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.test.unit.client.connection; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -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.TextMessage; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -public class ConnectionStartTest extends QpidBrokerTestCase -{ - - private String _broker = "vm://:1"; - - private AMQConnection _connection; - private Session _consumerSess; - private MessageConsumer _consumer; - - protected void setUp() throws Exception - { - super.setUp(); - try - { - - - AMQConnection pubCon = (AMQConnection) getConnection("guest", "guest"); - - AMQQueue queue = new AMQQueue(pubCon,"ConnectionStartTest"); - - Session pubSess = pubCon.createSession(false, AMQSession.AUTO_ACKNOWLEDGE); - - MessageProducer pub = pubSess.createProducer(queue); - - _connection = (AMQConnection) getConnection("guest", "guest"); - - _consumerSess = _connection.createSession(false, AMQSession.AUTO_ACKNOWLEDGE); - - _consumer = _consumerSess.createConsumer(queue); - - //publish after queue is created to ensure it can be routed as expected - pub.send(pubSess.createTextMessage("Initial Message")); - - pubCon.close(); - - } - catch (Exception e) - { - _logger.error("Connection to " + _broker + " should succeed.", e); - fail("Connection to " + _broker + " should succeed. Reason: " + e); - } - } - - protected void tearDown() throws Exception - { - _connection.close(); - super.tearDown(); - } - - public void testSimpleReceiveConnection() - { - try - { - assertTrue("Connection should not be started", !_connection.started()); - //Note that this next line will start the dispatcher in the session - // should really not be called before _connection start - //assertTrue("There should not be messages waiting for the consumer", _consumer.receiveNoWait() == null); - _connection.start(); - assertTrue("There should be messages waiting for the consumer", _consumer.receive(10*1000) != null); - assertTrue("Connection should be started", _connection.started()); - - } - catch (JMSException e) - { - fail("An error occured during test because:" + e); - } - - } - - public void testMessageListenerConnection() - { - final CountDownLatch _gotMessage = new CountDownLatch(1); - - try - { - assertTrue("Connection should not be started", !_connection.started()); - _consumer.setMessageListener(new MessageListener() - { - public void onMessage(Message message) - { - try - { - assertTrue("Connection should be started", _connection.started()); - assertEquals("Mesage Received", "Initial Message", ((TextMessage) message).getText()); - _gotMessage.countDown(); - } - catch (JMSException e) - { - fail("Couldn't get message text because:" + e.getCause()); - } - } - }); - - assertTrue("Connection should not be started", !_connection.started()); - _connection.start(); - assertTrue("Connection should be started", _connection.started()); - - try - { - assertTrue("Listener was never called", _gotMessage.await(10 * 1000, TimeUnit.MILLISECONDS)); - } - catch (InterruptedException e) - { - fail("Timed out awaiting message via onMessage"); - } - - } - catch (JMSException e) - { - fail("Failed because:" + e.getCause()); - } - - } - - - public static junit.framework.Test suite() - { - return new junit.framework.TestSuite(ConnectionStartTest.class); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java deleted file mode 100644 index ed03e83292..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java +++ /dev/null @@ -1,378 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.client.connection; - -import javax.jms.Connection; -import javax.jms.QueueSession; -import javax.jms.TopicSession; - -import org.apache.qpid.AMQConnectionFailureException; -import org.apache.qpid.AMQException; -import org.apache.qpid.AMQUnresolvedAddressException; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQConnectionURL; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.jms.BrokerDetails; -import org.apache.qpid.jms.ConnectionURL; -import org.apache.qpid.jms.Session; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class ConnectionTest extends QpidBrokerTestCase -{ - - private String _broker_NotRunning = "tcp://localhost:" + findFreePort(); - - private String _broker_BadDNS = "tcp://hg3sgaaw4lgihjs"; - - public void testSimpleConnection() throws Exception - { - AMQConnection conn = null; - try - { - conn = new AMQConnection(getBroker().toString(), "guest", "guest", "fred", "test"); - } - catch (Exception e) - { - fail("Connection to " + getBroker() + " should succeed. Reason: " + e); - } - finally - { - if(conn != null) - { - conn.close(); - } - } - } - - public void testDefaultExchanges() throws Exception - { - AMQConnection conn = null; - try - { - BrokerDetails broker = getBroker(); - broker.setProperty(BrokerDetails.OPTIONS_RETRY, "1"); - ConnectionURL url = new AMQConnectionURL("amqp://guest:guest@clientid/test?brokerlist='" - + broker - + "'&defaultQueueExchange='test.direct'" - + "&defaultTopicExchange='test.topic'" - + "&temporaryQueueExchange='tmp.direct'" - + "&temporaryTopicExchange='tmp.topic'"); - - System.err.println(url.toString()); - conn = new AMQConnection(url); - - - AMQSession sess = (AMQSession) conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - - sess.declareExchange(new AMQShortString("test.direct"), - AMQShortString.valueOf(ExchangeDefaults.DIRECT_EXCHANGE_CLASS), false); - - sess.declareExchange(new AMQShortString("tmp.direct"), - AMQShortString.valueOf(ExchangeDefaults.DIRECT_EXCHANGE_CLASS), false); - - sess.declareExchange(new AMQShortString("tmp.topic"), - AMQShortString.valueOf(ExchangeDefaults.TOPIC_EXCHANGE_CLASS), false); - - sess.declareExchange(new AMQShortString("test.topic"), - AMQShortString.valueOf(ExchangeDefaults.TOPIC_EXCHANGE_CLASS), false); - - QueueSession queueSession = conn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); - - AMQQueue queue = (AMQQueue) queueSession.createQueue("MyQueue"); - - assertEquals(queue.getExchangeName().toString(), "test.direct"); - - AMQQueue tempQueue = (AMQQueue) queueSession.createTemporaryQueue(); - - assertEquals(tempQueue.getExchangeName().toString(), "tmp.direct"); - - queueSession.close(); - - TopicSession topicSession = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - - AMQTopic topic = (AMQTopic) topicSession.createTopic("silly.topic"); - - assertEquals(topic.getExchangeName().toString(), "test.topic"); - - AMQTopic tempTopic = (AMQTopic) topicSession.createTemporaryTopic(); - - assertEquals(tempTopic.getExchangeName().toString(), "tmp.topic"); - - topicSession.close(); - - } - catch (Exception e) - { - fail("Connection to " + getBroker() + " should succeed. Reason: " + e); - } - finally - { - conn.close(); - } - } - - public void testPasswordFailureConnection() throws Exception - { - AMQConnection conn = null; - try - { - BrokerDetails broker = getBroker(); - broker.setProperty(BrokerDetails.OPTIONS_RETRY, "0"); - conn = new AMQConnection("amqp://guest:rubbishpassword@clientid/test?brokerlist='" + broker + "'"); - fail("Connection should not be established password is wrong."); - } - catch (AMQConnectionFailureException amqe) - { - assertNotNull("No cause set:" + amqe.getMessage(), amqe.getCause()); - assertTrue("Exception was wrong type", amqe.getCause() instanceof AMQException); - } - finally - { - if (conn != null) - { - conn.close(); - } - } - } - - public void testConnectionFailure() throws Exception - { - AMQConnection conn = null; - try - { - conn = new AMQConnection("amqp://guest:guest@clientid/testpath?brokerlist='" + _broker_NotRunning + "?retries='0''"); - fail("Connection should not be established"); - } - catch (AMQException amqe) - { - if (!(amqe instanceof AMQConnectionFailureException)) - { - fail("Correct exception not thrown. Excpected 'AMQConnectionException' got: " + amqe); - } - } - finally - { - if (conn != null) - { - conn.close(); - } - } - - } - - public void testUnresolvedHostFailure() throws Exception - { - AMQConnection conn = null; - try - { - conn = new AMQConnection("amqp://guest:guest@clientid/testpath?brokerlist='" + _broker_BadDNS + "?retries='0''"); - fail("Connection should not be established"); - } - catch (AMQException amqe) - { - if (!(amqe instanceof AMQUnresolvedAddressException)) - { - fail("Correct exception not thrown. Excpected 'AMQUnresolvedAddressException' got: " + amqe); - } - } - finally - { - if (conn != null) - { - conn.close(); - } - } - - } - - public void testUnresolvedVirtualHostFailure() throws Exception - { - AMQConnection conn = null; - try - { - BrokerDetails broker = getBroker(); - broker.setProperty(BrokerDetails.OPTIONS_RETRY, "0"); - conn = new AMQConnection("amqp://guest:guest@clientid/rubbishhost?brokerlist='" + broker + "'"); - fail("Connection should not be established"); - } - catch (AMQException amqe) - { - if (!(amqe instanceof AMQConnectionFailureException)) - { - fail("Correct exception not thrown. Excpected 'AMQConnectionFailureException' got: " + amqe); - } - } - finally - { - if (conn != null) - { - conn.close(); - } - } - } - - public void testClientIdCannotBeChanged() throws Exception - { - Connection connection = new AMQConnection(getBroker().toString(), "guest", "guest", - "fred", "test"); - try - { - connection.setClientID("someClientId"); - fail("No IllegalStateException thrown when resetting clientid"); - } - catch (javax.jms.IllegalStateException e) - { - // PASS - } - finally - { - if (connection != null) - { - connection.close(); - } - } - } - - public void testClientIdIsPopulatedAutomatically() throws Exception - { - Connection connection = new AMQConnection(getBroker().toString(), "guest", "guest", - null, "test"); - try - { - assertNotNull(connection.getClientID()); - } - finally - { - connection.close(); - } - connection.close(); - } - - public void testUnsupportedSASLMechanism() throws Exception - { - BrokerDetails broker = getBroker(); - broker.setProperty(BrokerDetails.OPTIONS_SASL_MECHS, "MY_MECH"); - - try - { - Connection connection = new AMQConnection(broker.toString(), "guest", "guest", - null, "test"); - connection.close(); - fail("The client should throw a ConnectionException stating the" + - " broker does not support the SASL mech specified by the client"); - } - catch (Exception e) - { - assertTrue("Unexpected exception message : " + e.getMessage(), - e.getMessage().contains("Client and broker have no SASL mechanisms in common.")); - assertTrue("Unexpected exception message : " + e.getMessage(), - e.getMessage().contains("Client restricted itself to : MY_MECH")); - - } - } - - /** - * Tests that when the same user connects twice with same clientid, the second connection - * fails if the clientid verification feature is enabled (which uses a dummy 0-10 Session - * with the clientid as its name to detect the previous usage of the clientid by the user) - */ - public void testClientIDVerificationForSameUser() throws Exception - { - setTestSystemProperty(ClientProperties.QPID_VERIFY_CLIENT_ID, "true"); - - BrokerDetails broker = getBroker(); - try - { - Connection con = new AMQConnection(broker.toString(), "guest", "guest", - "client_id", "test"); - - Connection con2 = new AMQConnection(broker.toString(), "guest", "guest", - "client_id", "test"); - - fail("The client should throw a ConnectionException stating the" + - " client ID is not unique"); - } - catch (Exception e) - { - assertTrue("Incorrect exception thrown: " + e.getMessage(), - e.getMessage().contains("ClientID must be unique")); - } - } - - /** - * Tests that when different users connects with same clientid, the second connection - * succeeds even though the clientid verification feature is enabled (which uses a dummy - * 0-10 Session with the clientid as its name; these are only verified unique on a - * per-principal basis) - */ - public void testClientIDVerificationForDifferentUsers() throws Exception - { - setTestSystemProperty(ClientProperties.QPID_VERIFY_CLIENT_ID, "true"); - - BrokerDetails broker = getBroker(); - try - { - Connection con = new AMQConnection(broker.toString(), "guest", "guest", - "client_id", "test"); - - Connection con2 = new AMQConnection(broker.toString(), "admin", "admin", - "client_id", "test"); - } - catch (Exception e) - { - fail("Unexpected exception thrown, client id was not unique but usernames were different! " + e.getMessage()); - } - } - - public static junit.framework.Test suite() - { - return new junit.framework.TestSuite(ConnectionTest.class); - } - - public void testExceptionWhenUserPassIsRequired() throws Exception - { - AMQConnection conn = null; - try - { - BrokerDetails broker = getBroker(); - String url = "amqp:///test?brokerlist='" + broker + "?sasl_mechs='PLAIN%2520CRAM-MD5''"; - conn = new AMQConnection(url); - conn.close(); - fail("Exception should be thrown as user name and password is required"); - } - catch (Exception e) - { - if (!e.getMessage().contains("Username and Password is required for the selected mechanism")) - { - if (conn != null && !conn.isClosed()) - { - conn.close(); - } - fail("Incorrect Exception thrown! The exception thrown is : " + e.getMessage()); - } - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ExceptionListenerTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ExceptionListenerTest.java deleted file mode 100644 index 141de1e5a8..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ExceptionListenerTest.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.test.unit.client.connection; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.jms.Connection; -import javax.jms.ExceptionListener; -import javax.jms.IllegalStateException; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageListener; -import javax.jms.Queue; -import javax.jms.Session; - -import org.apache.qpid.AMQConnectionClosedException; -import org.apache.qpid.client.AMQNoRouteException; -import org.apache.qpid.jms.ConnectionURL; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.transport.ConnectionException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ExceptionListenerTest extends QpidBrokerTestCase -{ - private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionListenerTest.class); - - private volatile Throwable _lastExceptionListenerException = null; - - public void testExceptionListenerHearsBrokerShutdown() throws Exception - { - final CountDownLatch exceptionReceivedLatch = new CountDownLatch(1); - final AtomicInteger exceptionCounter = new AtomicInteger(0); - final ExceptionListener listener = new ExceptionListener() - { - public void onException(JMSException exception) - { - exceptionCounter.incrementAndGet(); - _lastExceptionListenerException = exception; - exceptionReceivedLatch.countDown(); - } - }; - - Connection connection = getConnection(); - connection.setExceptionListener(listener); - - stopBroker(); - - exceptionReceivedLatch.await(10, TimeUnit.SECONDS); - - assertEquals("Unexpected number of exceptions received", 1, exceptionCounter.intValue()); - LOGGER.debug("exception was", _lastExceptionListenerException); - assertNotNull("Exception should have cause", _lastExceptionListenerException.getCause()); - Class expectedExceptionClass = isBroker010() ? ConnectionException.class : AMQConnectionClosedException.class; - assertEquals(expectedExceptionClass, _lastExceptionListenerException.getCause().getClass()); - } - - /** - * It is reasonable for an application to perform Connection#close within the exception - * listener. This test verifies that close is allowed, and proceeds without generating - * further exceptions. - */ - public void testExceptionListenerClosesConnection_IsAllowed() throws Exception - { - final CountDownLatch exceptionReceivedLatch = new CountDownLatch(1); - final Connection connection = getConnection(); - final ExceptionListener listener = new ExceptionListener() - { - public void onException(JMSException exception) - { - try - { - connection.close(); - // PASS - } - catch (Throwable t) - { - _lastExceptionListenerException = t; - } - finally - { - exceptionReceivedLatch.countDown(); - } - } - }; - connection.setExceptionListener(listener); - - - stopBroker(); - - boolean exceptionReceived = exceptionReceivedLatch.await(10, TimeUnit.SECONDS); - assertTrue("Exception listener did not hear exception within timeout", exceptionReceived); - assertNull("Connection#close() should not have thrown exception", _lastExceptionListenerException); - } - - /** - * Spring's SingleConnectionFactory installs an ExceptionListener that calls stop() - * and ignores any IllegalStateException that result. This test serves to test this - * scenario. - */ - public void testExceptionListenerStopsConnection_ThrowsIllegalStateException() throws Exception - { - final CountDownLatch exceptionReceivedLatch = new CountDownLatch(1); - final Connection connection = getConnection(); - final ExceptionListener listener = new ExceptionListener() - { - public void onException(JMSException exception) - { - try - { - connection.stop(); - fail("Exception not thrown"); - } - catch (IllegalStateException ise) - { - // PASS - } - catch (Throwable t) - { - _lastExceptionListenerException = t; - } - finally - { - exceptionReceivedLatch.countDown(); - } - } - }; - connection.setExceptionListener(listener); - - stopBroker(); - - boolean exceptionReceived = exceptionReceivedLatch.await(10, TimeUnit.SECONDS); - assertTrue("Exception listener did not hear exception within timeout", exceptionReceived); - assertNull("Connection#stop() should not have thrown unexpected exception", _lastExceptionListenerException); - } - - /** - * This test reproduces a deadlock that was the subject of a support call. A Spring based - * application was using SingleConnectionFactory. It installed an ExceptionListener that - * stops and closes the connection in response to any exception. On receipt of a message - * the application would create a new session then send a response message (within onMessage). - * It appears that a misconfiguration in the application meant that some of these messages - * were bounced (no-route). Bounces are treated like connection exceptions and are passed - * back to the application via the ExceptionListener. The deadlock occurred between the - * ExceptionListener's call to stop() and the MessageListener's attempt to create a new - * session. - */ - public void testExceptionListenerConnectionStopDeadlock() throws Exception - { - Queue messageQueue = getTestQueue(); - - Map options = new HashMap(); - options.put(ConnectionURL.OPTIONS_CLOSE_WHEN_NO_ROUTE, Boolean.toString(false)); - - final Connection connection = getConnectionWithOptions(options); - - Session session = connection.createSession(true, Session.SESSION_TRANSACTED); - session.createConsumer(messageQueue).close(); // Create queue by side-effect - - // Put 10 messages onto messageQueue - sendMessage(session, messageQueue, 10); - - // Install an exception listener that stops/closes the connection on receipt of 2nd AMQNoRouteException. - // (Triggering on the 2nd (rather than 1st) seems to increase the probability that the test ends in deadlock, - // at least on my machine). - final CountDownLatch exceptionReceivedLatch = new CountDownLatch(2); - final ExceptionListener listener = new ExceptionListener() - { - public void onException(JMSException exception) - { - try - { - assertNotNull("JMS Exception must have cause", exception.getCause() ); - assertEquals("JMS Exception is of wrong type", AMQNoRouteException.class, exception.getCause().getClass()); - exceptionReceivedLatch.countDown(); - if (exceptionReceivedLatch.getCount() == 0) - { - connection.stop(); // ** Deadlock - connection.close(); - } - } - catch (Throwable t) - { - _lastExceptionListenerException = t; - } - } - }; - connection.setExceptionListener(listener); - - // Create a message listener that receives from testQueue and tries to forward them to unknown queue (thus - // provoking AMQNoRouteException exceptions to be delivered to the ExceptionListener). - final Queue unknownQueue = session.createQueue(getTestQueueName() + "_unknown");; - MessageListener redirectingMessageListener = new MessageListener() - { - @Override - public void onMessage(Message msg) - { - try - { - Session mlSession = connection.createSession(true, Session.SESSION_TRANSACTED); // ** Deadlock - mlSession.createProducer(unknownQueue).send(msg); - mlSession.commit(); - } - catch (JMSException je) - { - // Connection is closed by the listener, so exceptions here are expected. - LOGGER.debug("Expected exception - message listener got exception", je); - } - } - }; - - MessageConsumer consumer = session.createConsumer(messageQueue); - consumer.setMessageListener(redirectingMessageListener); - connection.start(); - - // Await the 2nd exception - boolean exceptionReceived = exceptionReceivedLatch.await(10, TimeUnit.SECONDS); - assertTrue("Exception listener did not hear exception within timeout", exceptionReceived); - assertNull("Exception listener should not have had experienced exception", _lastExceptionListenerException); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/message/ObjectMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/message/ObjectMessageTest.java deleted file mode 100644 index 99dc5ff216..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/message/ObjectMessageTest.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.client.message; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageListener; -import javax.jms.MessageProducer; -import javax.jms.ObjectMessage; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; - -public class ObjectMessageTest extends QpidBrokerTestCase implements MessageListener -{ - private static final Logger _logger = LoggerFactory.getLogger(ObjectMessageTest.class); - - private AMQConnection connection; - private AMQDestination destination; - private AMQSession session; - private MessageProducer producer; - private Serializable[] data; - private volatile boolean waiting; - private int received; - private final ArrayList items = new ArrayList(); - - private String _broker = "vm://:1"; - - protected void setUp() throws Exception - { - super.setUp(); - connection = (AMQConnection) getConnection("guest", "guest"); - destination = new AMQQueue(connection, randomize("LatencyTest"), true); - session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); - - // set up a consumer - session.createConsumer(destination).setMessageListener(this); - connection.start(); - - // create a publisher - producer = session.createProducer(destination, false, false); - A a1 = new A(1, "A"); - A a2 = new A(2, "a"); - B b = new B(1, "B"); - C c = new C(); - c.put("A1", a1); - c.put("a2", a2); - c.put("B", b); - c.put("String", "String"); - - data = new Serializable[] { a1, a2, b, c, "Hello World!", new Integer(1001) }; - } - - protected void tearDown() throws Exception - { - close(); - super.tearDown(); - } - - public ObjectMessageTest() - { } - - ObjectMessageTest(String broker) throws Exception - { - _broker = broker; - } - - public void testSendAndReceive() throws Exception - { - try - { - send(); - waitUntilReceived(data.length); - check(); - _logger.info("All " + data.length + " items matched."); - } - catch (Exception e) - { - _logger.error("This Test should succeed but failed", e); - fail("This Test should succeed but failed due to: " + e); - } - } - - public void testSetObjectPropertyForString() throws Exception - { - String testStringProperty = "TestStringProperty"; - ObjectMessage msg = session.createObjectMessage(data[0]); - msg.setObjectProperty("TestStringProperty", testStringProperty); - assertEquals(testStringProperty, msg.getObjectProperty("TestStringProperty")); - } - - public void testSetObjectPropertyForBoolean() throws Exception - { - ObjectMessage msg = session.createObjectMessage(data[0]); - msg.setObjectProperty("TestBooleanProperty", Boolean.TRUE); - assertEquals(Boolean.TRUE, msg.getObjectProperty("TestBooleanProperty")); - } - - public void testSetObjectPropertyForByte() throws Exception - { - ObjectMessage msg = session.createObjectMessage(data[0]); - msg.setObjectProperty("TestByteProperty", Byte.MAX_VALUE); - assertEquals(Byte.MAX_VALUE, msg.getObjectProperty("TestByteProperty")); - } - - public void testSetObjectPropertyForShort() throws Exception - { - ObjectMessage msg = session.createObjectMessage(data[0]); - msg.setObjectProperty("TestShortProperty", Short.MAX_VALUE); - assertEquals(Short.MAX_VALUE, msg.getObjectProperty("TestShortProperty")); - } - - public void testSetObjectPropertyForInteger() throws Exception - { - ObjectMessage msg = session.createObjectMessage(data[0]); - msg.setObjectProperty("TestIntegerProperty", Integer.MAX_VALUE); - assertEquals(Integer.MAX_VALUE, msg.getObjectProperty("TestIntegerProperty")); - } - - public void testSetObjectPropertyForDouble() throws Exception - { - ObjectMessage msg = session.createObjectMessage(data[0]); - msg.setObjectProperty("TestDoubleProperty", Double.MAX_VALUE); - assertEquals(Double.MAX_VALUE, msg.getObjectProperty("TestDoubleProperty")); - } - - public void testSetObjectPropertyForFloat() throws Exception - { - ObjectMessage msg = session.createObjectMessage(data[0]); - msg.setObjectProperty("TestFloatProperty", Float.MAX_VALUE); - assertEquals(Float.MAX_VALUE, msg.getObjectProperty("TestFloatProperty")); - } - - public void testSetObjectPropertyForByteArray() throws Exception - { - byte[] array = { 1, 2, 3, 4, 5 }; - ObjectMessage msg = session.createObjectMessage(data[0]); - msg.setObjectProperty("TestByteArrayProperty", array); - assertTrue(Arrays.equals(array, (byte[]) msg.getObjectProperty("TestByteArrayProperty"))); - } - - public void testSetObjectForNull() throws Exception - { - ObjectMessage msg = session.createObjectMessage(); - msg.setObject(null); - assertNull(msg.getObject()); - } - - private void send() throws Exception - { - for (int i = 0; i < data.length; i++) - { - ObjectMessage msg; - if ((i % 2) == 0) - { - msg = session.createObjectMessage(data[i]); - } - else - { - msg = session.createObjectMessage(); - msg.setObject(data[i]); - } - - producer.send(msg); - } - } - - public void check() throws Exception - { - Object[] actual = (Object[]) items.toArray(); - if (actual.length != data.length) - { - throw new Exception("Expected " + data.length + " objects, got " + actual.length); - } - - for (int i = 0; i < data.length; i++) - { - if (actual[i] instanceof Exception) - { - throw new Exception("Error on receive of " + data[i], ((Exception) actual[i])); - } - - if (actual[i] == null) - { - throw new Exception("Expected " + data[i] + " got null"); - } - - if (!data[i].equals(actual[i])) - { - throw new Exception("Expected " + data[i] + " got " + actual[i]); - } - } - } - - private void close() throws Exception - { - session.close(); - connection.close(); - } - - private synchronized void waitUntilReceived(int count) throws InterruptedException - { - waiting = true; - while (received < count) - { - wait(); - } - - waiting = false; - } - - public void onMessage(Message message) - { - - try - { - if (message instanceof ObjectMessage) - { - items.add(((ObjectMessage) message).getObject()); - } - else - { - _logger.error("ERROR: Got " + message.getClass().getName() + " not ObjectMessage"); - items.add(message); - } - } - catch (JMSException e) - { - _logger.error("Error getting object from message", e); - items.add(e); - } - - synchronized (this) - { - received++; - notify(); - } - } - - public static void main(String[] argv) throws Exception - { - String broker = (argv.length > 0) ? argv[0] : "vm://:1"; - if ("-help".equals(broker)) - { - System.out.println("Usage: "); - } - - new ObjectMessageTest(broker).testSendAndReceive(); - } - - private static class A implements Serializable - { - private String sValue; - private int iValue; - - A(int i, String s) - { - sValue = s; - iValue = i; - } - - public int hashCode() - { - return iValue; - } - - public boolean equals(Object o) - { - return (o instanceof A) && equals((A) o); - } - - protected boolean equals(A a) - { - return areEqual(a.sValue, sValue) && (a.iValue == iValue); - } - } - - private static class B extends A - { - private long time; - - B(int i, String s) - { - super(i, s); - time = System.currentTimeMillis(); - } - - protected boolean equals(A a) - { - return super.equals(a) && (a instanceof B) && (time == ((B) a).time); - } - } - - private static class C extends HashMap implements Serializable - { } - - private static boolean areEqual(Object a, Object b) - { - return (a == null) ? (b == null) : a.equals(b); - } - - private static String randomize(String in) - { - return in + System.currentTimeMillis(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.java deleted file mode 100644 index 3ffa73b9b7..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.client.protocol; - -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.security.Principal; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.protocol.AMQProtocolHandler; -import org.apache.qpid.client.protocol.AMQProtocolSession; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.transport.Sender; -import org.apache.qpid.transport.network.NetworkConnection; - -public class AMQProtocolSessionTest extends QpidBrokerTestCase -{ - private static class TestProtocolSession extends AMQProtocolSession - { - - public TestProtocolSession(AMQProtocolHandler protocolHandler, AMQConnection connection) - { - super(protocolHandler,connection); - } - - public TestNetworkConnection getNetworkConnection() - { - return (TestNetworkConnection) getProtocolHandler().getNetworkConnection(); - } - - public AMQShortString genQueueName() - { - return generateQueueName(); - } - } - - private TestProtocolSession _testSession; - - protected void setUp() throws Exception - { - super.setUp(); - - AMQConnection con = (AMQConnection) getConnection("guest", "guest"); - AMQProtocolHandler protocolHandler = new AMQProtocolHandler(con); - protocolHandler.setNetworkConnection(new TestNetworkConnection()); - - //don't care about the values set here apart from the dummy IoSession - _testSession = new TestProtocolSession(protocolHandler , con); - } - - public void testTemporaryQueueWildcard() throws UnknownHostException - { - checkTempQueueName(new InetSocketAddress(1234), "tmp_0_0_0_0_0_0_0_0_1234_1"); - } - - public void testTemporaryQueueLocalhostAddr() throws UnknownHostException - { - checkTempQueueName(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 1234), "tmp_127_0_0_1_1234_1"); - } - - public void testTemporaryQueueLocalhostName() throws UnknownHostException - { - checkTempQueueName(new InetSocketAddress(InetAddress.getByName("localhost"), 1234), "tmp_localhost_127_0_0_1_1234_1"); - } - - public void testTemporaryQueueInet4() throws UnknownHostException - { - checkTempQueueName(new InetSocketAddress(InetAddress.getByName("192.168.1.2"), 1234), "tmp_192_168_1_2_1234_1"); - } - - public void testTemporaryQueueInet6() throws UnknownHostException - { - checkTempQueueName(new InetSocketAddress(InetAddress.getByName("1080:0:0:0:8:800:200C:417A"), 1234), "tmp_1080_0_0_0_8_800_200c_417a_1234_1"); - } - - private void checkTempQueueName(SocketAddress address, String queueName) - { - _testSession.getNetworkConnection().setLocalAddress(address); - assertEquals("Wrong queue name", queueName, _testSession.genQueueName().asString()); - } - - private static class TestNetworkConnection implements NetworkConnection - { - private String _remoteHost = "127.0.0.1"; - private String _localHost = "127.0.0.1"; - private int _port = 1; - private SocketAddress _localAddress = null; - private final Sender _sender; - - public TestNetworkConnection() - { - _sender = new Sender() - { - - public void setIdleTimeout(int i) - { - - } - - public void send(ByteBuffer msg) - { - - } - - public void flush() - { - - } - - public void close() - { - - } - }; - } - - @Override - public SocketAddress getLocalAddress() - { - return (_localAddress != null) ? _localAddress : new InetSocketAddress(_localHost, _port); - } - - @Override - public SocketAddress getRemoteAddress() - { - return new InetSocketAddress(_remoteHost, _port); - } - - @Override - public void setMaxReadIdle(int idleTime) - { - } - - @Override - public Principal getPeerPrincipal() - { - return null; - } - - @Override - public int getMaxReadIdle() - { - return 0; - } - - @Override - public int getMaxWriteIdle() - { - return 0; - } - - @Override - public void setMaxWriteIdle(int idleTime) - { - } - - @Override - public void close() - { - } - - public void setLocalAddress(SocketAddress address) - { - _localAddress = address; - } - - public Sender getSender() - { - return _sender; - } - - public void start() - { - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java deleted file mode 100644 index 41ab35f233..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.test.unit.client.temporaryqueue; - -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.TemporaryQueue; -import javax.jms.TextMessage; - -/** - * Tests the behaviour of {@link TemporaryQueue}. - */ -public class TemporaryQueueTest extends QpidBrokerTestCase -{ - /** - * Tests the basic produce/consume behaviour of a temporary queue. - */ - public void testMessageDeliveryUsingTemporaryQueue() throws Exception - { - final Connection conn = getConnection(); - final Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - final TemporaryQueue queue = session.createTemporaryQueue(); - assertNotNull(queue); - final MessageProducer producer = session.createProducer(queue); - final MessageConsumer consumer = session.createConsumer(queue); - conn.start(); - producer.send(session.createTextMessage("hello")); - TextMessage tm = (TextMessage) consumer.receive(2000); - assertNotNull("Message not received", tm); - assertEquals("hello", tm.getText()); - } - - /** - * Tests that a temporary queue cannot be used by another {@link Session}. - */ - public void testUseFromAnotherSessionProhibited() throws Exception - { - final Connection conn = getConnection(); - final Session session1 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - final Session session2 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - final TemporaryQueue queue = session1.createTemporaryQueue(); - assertNotNull(queue); - - try - { - session2.createConsumer(queue); - fail("Expected a JMSException when subscribing to a temporary queue created on a different session"); - } - catch (JMSException je) - { - //pass - assertEquals("Cannot consume from a temporary destination created on another session", je.getMessage()); - } - } - - /** - * Tests that the client is able to explicitly delete a temporary queue using - * {@link TemporaryQueue#delete()} and is prevented from deleting one that - * still has consumers. - * - * Note: Under < 0-10 {@link TemporaryQueue#delete()} only marks the queue as deleted - * on the client. 0-10 causes the queue to be deleted from the Broker. - */ - public void testExplictTemporaryQueueDeletion() throws Exception - { - final Connection conn = getConnection(); - final Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - final AMQSession amqSession = (AMQSession)session; // Required to observe the queue binding on the Broker - final TemporaryQueue queue = session.createTemporaryQueue(); - assertNotNull(queue); - final MessageConsumer consumer = session.createConsumer(queue); - conn.start(); - - assertTrue("Queue should be bound", amqSession.isQueueBound((AMQDestination)queue)); - - try - { - queue.delete(); - fail("Expected JMSException : should not be able to delete while there are active consumers"); - } - catch (JMSException je) - { - //pass - assertEquals("Temporary Queue has consumers so cannot be deleted", je.getMessage()); - } - consumer.close(); - - // Now deletion should succeed. - queue.delete(); - - try - { - session.createConsumer(queue); - fail("Exception not thrown"); - } - catch (JMSException je) - { - //pass - assertEquals("Cannot consume from a deleted destination", je.getMessage()); - } - - if (isBroker010()) - { - assertFalse("Queue should no longer be bound", amqSession.isQueueBound((AMQDestination)queue)); - } - } - - /** - * Tests that a temporary queue remains available for reuse even after its initial - * consumer has disconnected. - * - * This test would fail under < 0-10 as their temporary queues are deleted automatically - * (broker side) after the last consumer disconnects (so message2 would be lost). For this - * reason this test is excluded from those profiles. - */ - public void testTemporaryQueueReused() throws Exception - { - final Connection conn = getConnection(); - final Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - final TemporaryQueue queue = session.createTemporaryQueue(); - assertNotNull(queue); - - final MessageProducer producer1 = session.createProducer(queue); - final MessageConsumer consumer1 = session.createConsumer(queue); - conn.start(); - producer1.send(session.createTextMessage("message1")); - producer1.send(session.createTextMessage("message2")); - TextMessage tm = (TextMessage) consumer1.receive(2000); - assertNotNull("Message not received by first consumer", tm); - assertEquals("message1", tm.getText()); - consumer1.close(); - - final MessageConsumer consumer2 = session.createConsumer(queue); - conn.start(); - tm = (TextMessage) consumer2.receive(2000); - assertNotNull("Message not received by second consumer", tm); - assertEquals("message2", tm.getText()); - consumer2.close(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/JavaServerCloseRaceConditionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/JavaServerCloseRaceConditionTest.java deleted file mode 100644 index b43fe35a09..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/JavaServerCloseRaceConditionTest.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.close; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQSession_0_8; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ExchangeDeclareBody; -import org.apache.qpid.framing.ExchangeDeclareOkBody; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Session; - -/** QPID-1809 - * - * Race condition on error handling and close logic. - * - * See most often with SimpleACLTest as this test is the expects the server to - * shut the connection/channels. This sort of testing is not performed by many, - * if any, of the other system tests. - * - * The problem is that we have two threads - * - * MainThread Exception(Mina)Thread - * | | - * Performs | - * ACtion | - * | Receives Server - * | Close - * Blocks for | - * Response | - * | Starts To Notify - * | client - * | | - * | <----- Notify Main Thread - * Notification | - * wakes client | - * | | - * Client then | - * processes Error. | - * | | - * Potentially Attempting Close Channel/Connection - * Connection Close - * - * The two threads both attempt to close the connection but the main thread does - * so assuming that the connection is open and valid. - * - * The Exception thread must modify the connection so that no furter syncWait - * commands are performed. - * - * This test sends an ExchangeDeclare that is Asynchronous and will fail and - * so cause a ChannelClose error but we perform a syncWait so that we can be - * sure to test that the BlockingWaiter is correctly awoken. - * - */ -public class JavaServerCloseRaceConditionTest extends QpidBrokerTestCase -{ - private static final String EXCHANGE_NAME = "NewExchangeNametoFailLookup"; - - public void test() throws Exception - { - - AMQConnection connection = (AMQConnection) getConnection(); - - AMQSession_0_8 session = (AMQSession_0_8) connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - // Set no wait true so that we block the connection - // Also set a different exchange class string so the attempt to declare - // the exchange causes an exchange. - ExchangeDeclareBody body = session.getMethodRegistry().createExchangeDeclareBody(session.getTicket(), new AMQShortString(EXCHANGE_NAME), null, - true, false, false, false, true, null); - - AMQFrame exchangeDeclare = body.generateFrame(session.getChannelId()); - - try - { - // block our thread so that can times out - connection.getProtocolHandler().syncWrite(exchangeDeclare, ExchangeDeclareOkBody.class); - } - catch (Exception e) - { - assertTrue("Exception should say the exchange is not known.", e.getMessage().contains("Unknown exchange: " + EXCHANGE_NAME)); - } - - try - { - // Depending on if the notification thread has closed the connection - // or not we may get an exception here when we attempt to close the - // connection. If we do get one then it should be the same as above - // an AMQAuthenticationException. - connection.close(); - } - catch (Exception e) - { - assertTrue("Exception should say the exchange is not known.", e.getMessage().contains("Unknown exchange: " + EXCHANGE_NAME)); - } - - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageConsumerCloseTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageConsumerCloseTest.java deleted file mode 100644 index df32bd7858..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageConsumerCloseTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.close; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageListener; -import javax.jms.Session; - -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class MessageConsumerCloseTest extends QpidBrokerTestCase -{ - Exception _exception; - - public void testConsumerCloseAndSessionRollback() throws Exception - { - Connection connection = getConnection(); - final CountDownLatch receiveLatch = new CountDownLatch(1); - final Session session = connection.createSession(true, Session.SESSION_TRANSACTED); - Destination destination = getTestQueue(); - MessageConsumer consumer = session.createConsumer(destination); - sendMessage(session, destination, 2); - connection.start(); - consumer.setMessageListener(new MessageListener() - { - @Override - public void onMessage(Message message) - { - try - { - receiveLatch.countDown(); - session.rollback(); - } - catch (JMSException e) - { - _exception = e; - } - } - }); - boolean messageReceived = receiveLatch.await(1l, TimeUnit.SECONDS); - consumer.close(); - - assertNull("Exception occured on rollback:" + _exception, _exception); - assertTrue("Message is not received", messageReceived); - - consumer = session.createConsumer(destination); - Message message1 = consumer.receive(1000l); - assertNotNull("message1 is not received", message1); - Message message2 = consumer.receive(1000l); - assertNotNull("message2 is not received", message2); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java deleted file mode 100644 index 5895d670a7..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.test.unit.close; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.AMQException; -import org.apache.qpid.client.message.AbstractJMSMessage; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.test.utils.QpidClientConnection; -import org.apache.qpid.url.URLSyntaxException; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.Queue; -import javax.jms.Session; -import java.util.concurrent.atomic.AtomicInteger; - -public class MessageRequeueTest extends QpidBrokerTestCase -{ - private static final Logger _logger = LoggerFactory.getLogger(MessageRequeueTest.class); - - protected static AtomicInteger consumerIds = new AtomicInteger(0); - protected final Integer numTestMessages = 150; - - protected final int consumeTimeout = 3000; - - protected final String queue = "direct://amq.direct//message-requeue-test-queue"; - protected String payload = "Message:"; - - protected final String BROKER = "tcp://127.0.0.1:5672"; - private boolean testReception = true; - - private long[] receieved = new long[numTestMessages + 1]; - private boolean passed = false; - private QpidClientConnection conn; - - - protected void setUp() throws Exception - { - super.setUp(); - - conn = new QpidClientConnection(BROKER); - - conn.connect(); - // clear queue - conn.consume(queue, consumeTimeout); - // load test data - _logger.info("creating test data, " + numTestMessages + " messages"); - conn.put(queue, payload, numTestMessages); - // close this connection - conn.disconnect(); - } - - protected void tearDown() throws Exception - { - - if (!passed) // clean up - { - QpidClientConnection conn = new QpidClientConnection(BROKER); - - conn.connect(); - // clear queue - conn.consume(queue, consumeTimeout); - - conn.disconnect(); - } - - super.tearDown(); - } - - /** - * multiple consumers - * - * @throws javax.jms.JMSException if a JMS problem occurs - * @throws InterruptedException on timeout - */ - public void testDrain() throws Exception - { - QpidClientConnection conn = new QpidClientConnection(BROKER); - - conn.connect(); - - _logger.info("consuming queue " + queue); - Queue q = conn.getSession().createQueue(queue); - - final MessageConsumer consumer = conn.getSession().createConsumer(q); - int messagesReceived = 0; - - long[] messageLog = new long[numTestMessages + 1]; - - _logger.info("consuming..."); - Message msg = consumer.receive(1000); - while (msg != null) - { - messagesReceived++; - - long dt = ((AbstractJMSMessage) msg).getDeliveryTag(); - - int msgindex = msg.getIntProperty("index"); - if (messageLog[msgindex] != 0) - { - _logger.error("Received Message(" + msgindex + ":" + ((AbstractJMSMessage) msg).getDeliveryTag() - + ") more than once."); - } - - if (_logger.isInfoEnabled()) - { - _logger.info("Received Message(" + System.identityHashCode(msgindex) + ") " + "DT:" + dt + "IN:" + msgindex); - } - - if (dt == 0) - { - _logger.error("DT is zero for msg:" + msgindex); - } - - messageLog[msgindex] = dt; - - // get Next message - msg = consumer.receive(1000); - } - - _logger.info("consuming done."); - conn.getSession().commit(); - consumer.close(); - - int index = 0; - StringBuilder list = new StringBuilder(); - list.append("Failed to receive:"); - int failed = 0; - - _logger.info("consumed: " + messagesReceived); - - assertEquals("number of consumed messages does not match initial data", (int) numTestMessages, messagesReceived); - // with 0_10 we can have a delivery tag of 0 - if (!conn.isBroker010()) - { - for (long b : messageLog) - { - if ((b == 0) && (index != 0)) // delivery tag of zero shouldn't exist - { - _logger.error("Index: " + index + " was not received."); - list.append(" "); - list.append(index); - list.append(":"); - list.append(b); - failed++; - } - - index++; - } - - assertEquals(list.toString(), 0, failed); - } - - conn.disconnect(); - passed = true; - } - - /** multiple consumers - * Based on code subbmitted by client FT-304 - */ - public void testTwoCompetingConsumers() - { - Consumer c1 = new Consumer(); - Consumer c2 = new Consumer(); - Consumer c3 = new Consumer(); - Consumer c4 = new Consumer(); - - Thread t1 = new Thread(c1); - Thread t2 = new Thread(c2); - Thread t3 = new Thread(c3); - Thread t4 = new Thread(c4); - - t1.start(); - t2.start(); - t3.start(); - // t4.start(); - - try - { - t1.join(); - t2.join(); - t3.join(); - t4.join(); - } - catch (InterruptedException e) - { - fail("Unable to join to Consumer theads"); - } - - _logger.info("consumer 1 count is " + c1.getCount()); - _logger.info("consumer 2 count is " + c2.getCount()); - _logger.info("consumer 3 count is " + c3.getCount()); - _logger.info("consumer 4 count is " + c4.getCount()); - - Integer totalConsumed = c1.getCount() + c2.getCount() + c3.getCount() + c4.getCount(); - - // Check all messages were correctly delivered - int index = 0; - StringBuilder list = new StringBuilder(); - list.append("Failed to receive:"); - int failed = 0; - if (!conn.isBroker010()) - { - for (long b : receieved) - { - if ((b == 0) && (index != 0)) // delivery tag of zero shouldn't exist (and we don't have msg 0) - { - _logger.error("Index: " + index + " was not received."); - list.append(" "); - list.append(index); - list.append(":"); - list.append(b); - failed++; - } - - index++; - } - - assertEquals(list.toString() + "-" + numTestMessages + "-" + totalConsumed, 0, failed); - } - assertEquals("number of consumed messages does not match initial data", numTestMessages, totalConsumed); - passed = true; - } - - class Consumer implements Runnable - { - private Integer count = 0; - private Integer id; - - public Consumer() - { - id = consumerIds.addAndGet(1); - } - - public void run() - { - try - { - _logger.info("consumer-" + id + ": starting"); - QpidClientConnection conn = new QpidClientConnection(BROKER); - - conn.connect(); - - _logger.info("consumer-" + id + ": connected, consuming..."); - Message result; - do - { - result = conn.getNextMessage(queue, consumeTimeout); - if (result != null) - { - - long dt = ((AbstractJMSMessage) result).getDeliveryTag(); - - if (testReception) - { - int msgindex = result.getIntProperty("index"); - if (receieved[msgindex] != 0) - { - _logger.error("Received Message(" + msgindex + ":" - + ((AbstractJMSMessage) result).getDeliveryTag() + ") more than once."); - } - - if (_logger.isInfoEnabled()) - { - _logger.info("Received Message(" + System.identityHashCode(msgindex) + ") " + "DT:" + dt - + "IN:" + msgindex); - } - - if (dt == 0) - { - _logger.error("DT is zero for msg:" + msgindex); - } - - receieved[msgindex] = dt; - } - - count++; - if ((count % 100) == 0) - { - _logger.info("consumer-" + id + ": got " + result + ", new count is " + count); - } - } - } - while (result != null); - - _logger.info("consumer-" + id + ": complete"); - conn.disconnect(); - - } - catch (Exception e) - { - _logger.error("Consumer run error",e); - } - } - - public Integer getCount() - { - return count; - } - - public Integer getId() - { - return id; - } - } - - public void testRequeue() throws JMSException, AMQException, URLSyntaxException - { - int run = 0; - // while (run < 10) - { - run++; - - if (_logger.isInfoEnabled()) - { - _logger.info("testRequeue run " + run); - } - - String virtualHost = "/test"; - String brokerlist = BROKER; - String brokerUrl = "amqp://guest:guest@" + virtualHost + "?brokerlist='" + brokerlist + "'"; - QpidClientConnection qpc = new QpidClientConnection(BROKER); - qpc.connect(); - Connection conn = qpc. getConnection(); - - Session session = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE); - Queue q = session.createQueue(queue); - - _logger.debug("Create Consumer"); - MessageConsumer consumer = session.createConsumer(q); - - conn.start(); - - _logger.debug("Receiving msg"); - Message msg = consumer.receive(2000); - - assertNotNull("Message should not be null", msg); - - // As we have not ack'd message will be requeued. - _logger.debug("Close Consumer"); - consumer.close(); - - _logger.debug("Close Connection"); - conn.close(); - } - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/TopicPublisherCloseTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/TopicPublisherCloseTest.java deleted file mode 100644 index 957063b2e1..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/close/TopicPublisherCloseTest.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.test.unit.close; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Session; -import javax.jms.Topic; -import javax.jms.TopicPublisher; -import javax.jms.TopicSession; - -/** - * @author Apache Software Foundation - */ -public class TopicPublisherCloseTest extends QpidBrokerTestCase -{ - - protected void setUp() throws Exception - { - super.setUp(); - } - - - protected void tearDown() throws Exception - { - super.tearDown(); - } - - public void testAllMethodsThrowAfterConnectionClose() throws Exception - { - // give external brokers a chance to start up - Thread.sleep(3000); - - AMQConnection connection = (AMQConnection) getConnection("guest", "guest"); - - Topic destination1 = new AMQTopic(connection, "t1"); - TopicSession session1 = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - TopicPublisher pub = session1.createPublisher(destination1); - connection.close(); - try - { - pub.getDeliveryMode(); - fail("Expected exception not thrown"); - } - catch (javax.jms.IllegalStateException e) - { - // PASS - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ct/DurableSubscriberTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ct/DurableSubscriberTest.java deleted file mode 100644 index c292c718bb..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/ct/DurableSubscriberTest.java +++ /dev/null @@ -1,503 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.test.unit.ct; - -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.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.Message; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.TextMessage; -import javax.jms.Topic; -import javax.jms.TopicConnection; -import javax.jms.TopicConnectionFactory; -import javax.jms.TopicPublisher; -import javax.jms.TopicSession; -import javax.jms.TopicSubscriber; - -/** - * Crash Recovery tests for durable subscription - * - */ -public class DurableSubscriberTest extends QpidBrokerTestCase -{ - private final String _topicName = "durableSubscriberTopic"; - - /** - * test strategy: - * create and register a durable subscriber then close it - * create a publisher and send a persistant message followed by a non persistant message - * crash and restart the broker - * recreate the durable subscriber and check that only the first message is received - */ - public void testDurSubRestoredAfterNonPersistentMessageSent() throws Exception - { - if (isBrokerStorePersistent()) - { - TopicConnectionFactory factory = getConnectionFactory(); - Topic topic = (Topic) getInitialContext().lookup(_topicName); - //create and register a durable subscriber then close it - TopicConnection durConnection = factory.createTopicConnection("guest", "guest"); - TopicSession durSession = durConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - TopicSubscriber durSub1 = durSession.createDurableSubscriber(topic, "dursub"); - durConnection.start(); - durSub1.close(); - durSession.close(); - durConnection.stop(); - - //create a publisher and send a persistant message followed by a non persistant message - TopicConnection pubConnection = factory.createTopicConnection("guest", "guest"); - TopicSession pubSession = pubConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - TopicPublisher publisher = pubSession.createPublisher(topic); - Message message = pubSession.createMessage(); - message.setIntProperty("count", 1); - publisher.publish(message, javax.jms.DeliveryMode.PERSISTENT, javax.jms.Message.DEFAULT_PRIORITY, - javax.jms.Message.DEFAULT_TIME_TO_LIVE); - message.setIntProperty("count", 2); - publisher.publish(message, javax.jms.DeliveryMode.NON_PERSISTENT, javax.jms.Message.DEFAULT_PRIORITY, - javax.jms.Message.DEFAULT_TIME_TO_LIVE); - publisher.close(); - pubSession.close(); - //now stop the server - try - { - restartBroker(); - } - catch (Exception e) - { - _logger.error("problems restarting broker: " + e); - throw e; - } - //now recreate the durable subscriber and check the received messages - factory = getConnectionFactory(); - topic = (Topic) getInitialContext().lookup(_topicName); - TopicConnection durConnection2 = factory.createTopicConnection("guest", "guest"); - TopicSession durSession2 = durConnection2.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - TopicSubscriber durSub2 = durSession2.createDurableSubscriber(topic, "dursub"); - durConnection2.start(); - Message m1 = durSub2.receive(1000); - if (m1 == null) - { - assertTrue("testDurSubRestoredAfterNonPersistentMessageSent test failed. no message was returned", - false); - } - assertTrue("testDurSubRestoredAfterNonPersistentMessageSent test failed. Wrong message was returned.", - m1.getIntProperty("count") == 1); - durSession2.unsubscribe("dursub"); - durConnection2.close(); - } - } - - /** - * create and register a durable subscriber with a message selector and then close it - * crash the broker - * create a publisher and send 5 right messages and 5 wrong messages - * recreate the durable subscriber and check we receive the 5 expected messages - */ - public void testDurSubRestoresMessageSelector() throws Exception - { - if (isBrokerStorePersistent()) - { - TopicConnectionFactory factory = getConnectionFactory(); - Topic topic = (Topic) getInitialContext().lookup(_topicName); - //create and register a durable subscriber with a message selector and then close it - TopicConnection durConnection = factory.createTopicConnection("guest", "guest"); - TopicSession durSession = durConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - TopicSubscriber durSub1 = durSession.createDurableSubscriber(topic, "dursub", "testprop='true'", false); - durConnection.start(); - durSub1.close(); - durSession.close(); - durConnection.stop(); - //now stop the server - try - { - restartBroker(); - } - catch (Exception e) - { - _logger.error("problems restarting broker: " + e); - throw e; - } - topic = (Topic) getInitialContext().lookup(_topicName); - factory = getConnectionFactory(); - TopicConnection pubConnection = factory.createTopicConnection("guest", "guest"); - TopicSession pubSession = pubConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - TopicPublisher publisher = pubSession.createPublisher(topic); - for (int i = 0; i < 5; i++) - { - Message message = pubSession.createMessage(); - message.setStringProperty("testprop", "true"); - publisher.publish(message); - message = pubSession.createMessage(); - message.setStringProperty("testprop", "false"); - publisher.publish(message); - } - publisher.close(); - pubSession.close(); - - //now recreate the durable subscriber and check the received messages - TopicConnection durConnection2 = factory.createTopicConnection("guest", "guest"); - TopicSession durSession2 = durConnection2.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - TopicSubscriber durSub2 = durSession2.createDurableSubscriber(topic, "dursub", "testprop='true'", false); - durConnection2.start(); - for (int i = 0; i < 5; i++) - { - Message message = durSub2.receive(1000); - if (message == null) - { - assertTrue("testDurSubRestoresMessageSelector test failed. no message was returned", false); - } - else - { - assertTrue("testDurSubRestoresMessageSelector test failed. message selector not reset", - message.getStringProperty("testprop").equals("true")); - } - } - durSession2.unsubscribe("dursub"); - durConnection2.close(); - } - } - - /** - * create and register a durable subscriber without a message selector and then unsubscribe it - * create and register a durable subscriber with a message selector and then close it - * restart the broker - * send matching and non matching messages - * recreate and register the durable subscriber with a message selector - * verify only the matching messages are received - */ - public void testDurSubChangedToHaveSelectorThenRestart() throws Exception - { - if (! isBrokerStorePersistent()) - { - _logger.warn("Test skipped due to requirement of a persistent store"); - return; - } - - final String SUB_NAME=getTestQueueName(); - - TopicConnectionFactory factory = getConnectionFactory(); - Topic topic = (Topic) getInitialContext().lookup(_topicName); - - //create and register a durable subscriber then unsubscribe it - TopicConnection durConnection = factory.createTopicConnection("guest", "guest"); - TopicSession durSession = durConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - TopicSubscriber durSub1 = durSession.createDurableSubscriber(topic, SUB_NAME); - durConnection.start(); - durSub1.close(); - durSession.unsubscribe(SUB_NAME); - durSession.close(); - durConnection.close(); - - //create and register a durable subscriber with a message selector and then close it - TopicConnection durConnection2 = factory.createTopicConnection("guest", "guest"); - TopicSession durSession2 = durConnection2.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - TopicSubscriber durSub2 = durSession2.createDurableSubscriber(topic, SUB_NAME, "testprop='true'", false); - durConnection2.start(); - durSub2.close(); - durSession2.close(); - durConnection2.close(); - - //now restart the server - try - { - restartBroker(); - } - catch (Exception e) - { - _logger.error("problems restarting broker: " + e); - throw e; - } - - //send messages matching and not matching the selector - TopicConnection pubConnection = factory.createTopicConnection("guest", "guest"); - TopicSession pubSession = pubConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - TopicPublisher publisher = pubSession.createPublisher(topic); - for (int i = 0; i < 5; i++) - { - Message message = pubSession.createMessage(); - message.setStringProperty("testprop", "true"); - publisher.publish(message); - message = pubSession.createMessage(); - message.setStringProperty("testprop", "false"); - publisher.publish(message); - } - publisher.close(); - pubSession.close(); - - //now recreate the durable subscriber with selector to check there are no exceptions generated - //and then verify the messages are received correctly - TopicConnection durConnection3 = (TopicConnection) factory.createConnection("guest", "guest"); - TopicSession durSession3 = (TopicSession) durConnection3.createSession(false, Session.AUTO_ACKNOWLEDGE); - TopicSubscriber durSub3 = durSession3.createDurableSubscriber(topic, SUB_NAME, "testprop='true'", false); - durConnection3.start(); - - for (int i = 0; i < 5; i++) - { - Message message = durSub3.receive(2000); - if (message == null) - { - fail("testDurSubChangedToHaveSelectorThenRestart test failed. Expected message " + i + " was not returned"); - } - else - { - assertTrue("testDurSubChangedToHaveSelectorThenRestart test failed. Got message not matching selector", - message.getStringProperty("testprop").equals("true")); - } - } - - durSub3.close(); - durSession3.unsubscribe(SUB_NAME); - durSession3.close(); - durConnection3.close(); - } - - - /** - * create and register a durable subscriber with a message selector and then unsubscribe it - * create and register a durable subscriber without a message selector and then close it - * restart the broker - * send matching and non matching messages - * recreate and register the durable subscriber without a message selector - * verify ALL the sent messages are received - */ - public void testDurSubChangedToNotHaveSelectorThenRestart() throws Exception - { - if (! isBrokerStorePersistent()) - { - _logger.warn("Test skipped due to requirement of a persistent store"); - return; - } - - final String SUB_NAME=getTestQueueName(); - - TopicConnectionFactory factory = getConnectionFactory(); - Topic topic = (Topic) getInitialContext().lookup(_topicName); - - //create and register a durable subscriber with selector then unsubscribe it - TopicConnection durConnection = factory.createTopicConnection("guest", "guest"); - TopicSession durSession = durConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - TopicSubscriber durSub1 = durSession.createDurableSubscriber(topic, SUB_NAME, "testprop='true'", false); - durConnection.start(); - durSub1.close(); - durSession.unsubscribe(SUB_NAME); - durSession.close(); - durConnection.close(); - - //create and register a durable subscriber without the message selector and then close it - TopicConnection durConnection2 = factory.createTopicConnection("guest", "guest"); - TopicSession durSession2 = durConnection2.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - TopicSubscriber durSub2 = durSession2.createDurableSubscriber(topic, SUB_NAME); - durConnection2.start(); - durSub2.close(); - durSession2.close(); - durConnection2.close(); - - //now restart the server - try - { - restartBroker(); - } - catch (Exception e) - { - _logger.error("problems restarting broker: " + e); - throw e; - } - - //send messages matching and not matching the original used selector - TopicConnection pubConnection = factory.createTopicConnection("guest", "guest"); - TopicSession pubSession = pubConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - TopicPublisher publisher = pubSession.createPublisher(topic); - for (int i = 1; i <= 5; i++) - { - Message message = pubSession.createMessage(); - message.setStringProperty("testprop", "true"); - publisher.publish(message); - message = pubSession.createMessage(); - message.setStringProperty("testprop", "false"); - publisher.publish(message); - } - publisher.close(); - pubSession.close(); - - //now recreate the durable subscriber without selector to check there are no exceptions generated - //then verify ALL messages sent are received - TopicConnection durConnection3 = (TopicConnection) factory.createConnection("guest", "guest"); - TopicSession durSession3 = (TopicSession) durConnection3.createSession(false, Session.AUTO_ACKNOWLEDGE); - TopicSubscriber durSub3 = durSession3.createDurableSubscriber(topic, SUB_NAME); - durConnection3.start(); - - for (int i = 1; i <= 10; i++) - { - Message message = durSub3.receive(2000); - if (message == null) - { - fail("testDurSubChangedToNotHaveSelectorThenRestart test failed. Expected message " + i + " was not received"); - } - } - - durSub3.close(); - durSession3.unsubscribe(SUB_NAME); - durSession3.close(); - durConnection3.close(); - } - - - public void testResubscribeWithChangedSelectorAndRestart() throws Exception - { - if (! isBrokerStorePersistent()) - { - _logger.warn("Test skipped due to requirement of a persistent store"); - return; - } - - Connection conn = getConnection(); - conn.start(); - Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - AMQTopic topic = new AMQTopic((AMQConnection) conn, "testResubscribeWithChangedSelectorAndRestart"); - MessageProducer producer = session.createProducer(topic); - - // Create durable subscriber that matches A - TopicSubscriber subA = session.createDurableSubscriber(topic, - "testResubscribeWithChangedSelectorAndRestart", - "Match = True", false); - - // Send 1 matching message and 1 non-matching message - TextMessage msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart1"); - msg.setBooleanProperty("Match", true); - producer.send(msg); - msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart2"); - msg.setBooleanProperty("Match", false); - producer.send(msg); - - Message rMsg = subA.receive(1000); - assertNotNull(rMsg); - assertEquals("Content was wrong", - "testResubscribeWithChangedSelectorAndRestart1", - ((TextMessage) rMsg).getText()); - - // Queue has no messages left - AMQQueue subQueue = new AMQQueue("amq.topic", "clientid" + ":" + "testResubscribeWithChangedSelectorAndRestart"); - assertEquals("Msg count should be 0", 0, ((AMQSession) session).getQueueDepth(subQueue, true)); - - rMsg = subA.receive(1000); - assertNull(rMsg); - - // Send another 1 matching message and 1 non-matching message - msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart1"); - msg.setBooleanProperty("Match", true); - producer.send(msg); - msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart2"); - msg.setBooleanProperty("Match", false); - producer.send(msg); - - // Disconnect subscriber without receiving the message to - //leave it on the underlying queue - subA.close(); - - // Reconnect with new selector that matches B - TopicSubscriber subB = session.createDurableSubscriber(topic, - "testResubscribeWithChangedSelectorAndRestart", - "Match = false", false); - - //verify no messages are now present on the queue as changing selector should have issued - //an unsubscribe and thus deleted the previous durable backing queue for the subscription. - //check the dur sub's underlying queue now has msg count 0 - assertEquals("Msg count should be 0", 0, ((AMQSession) session).getQueueDepth(subQueue, true)); - - // Check that new messages are received properly - msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart1"); - msg.setBooleanProperty("Match", true); - producer.send(msg); - msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart2"); - msg.setBooleanProperty("Match", false); - producer.send(msg); - - rMsg = subB.receive(1000); - assertNotNull(rMsg); - assertEquals("Content was wrong", - "testResubscribeWithChangedSelectorAndRestart2", - ((TextMessage) rMsg).getText()); - - rMsg = subB.receive(1000); - assertNull(rMsg); - - //check the dur sub's underlying queue now has msg count 0 - assertEquals("Msg count should be 0", 0, ((AMQSession) session).getQueueDepth(subQueue, true)); - conn.close(); - - //now restart the server - try - { - restartBroker(); - } - catch (Exception e) - { - _logger.error("problems restarting broker: " + e); - throw e; - } - - // Reconnect to broker - Connection connection = getConnectionFactory().createConnection("guest", "guest"); - connection.start(); - session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - topic = new AMQTopic((AMQConnection) connection, "testResubscribeWithChangedSelectorAndRestart"); - producer = session.createProducer(topic); - - //verify no messages now present on the queue after we restart the broker - //check the dur sub's underlying queue now has msg count 0 - assertEquals("Msg count should be 0", 0, ((AMQSession) session).getQueueDepth(subQueue, true)); - - // Reconnect with new selector that matches B - TopicSubscriber subC = session.createDurableSubscriber(topic, - "testResubscribeWithChangedSelectorAndRestart", - "Match = False", false); - - // Check that new messages are still sent and recieved properly - msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart1"); - msg.setBooleanProperty("Match", true); - producer.send(msg); - msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart2"); - msg.setBooleanProperty("Match", false); - producer.send(msg); - - //check the dur sub's underlying queue now has msg count 1 - assertEquals("Msg count should be 1", 1, ((AMQSession) session).getQueueDepth(subQueue, true)); - - rMsg = subC.receive(1000); - assertNotNull(rMsg); - assertEquals("Content was wrong", - "testResubscribeWithChangedSelectorAndRestart2", - ((TextMessage) rMsg).getText()); - - rMsg = subC.receive(1000); - assertNull(rMsg); - - session.unsubscribe("testResubscribeWithChangedSelectorAndRestart"); - - subC.close(); - session.close(); - connection.close(); - } -} - diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java deleted file mode 100644 index 3f2d6f92ab..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.message; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.AMQPInvalidClassException; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.message.NonQpidObjectMessage; -import org.apache.qpid.client.message.QpidMessageProperties; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageFormatException; -import javax.jms.MessageProducer; -import javax.jms.ObjectMessage; -import javax.jms.Queue; -import javax.jms.Session; -import javax.jms.Topic; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; - -/** - * @author Apache Software Foundation - */ -public class JMSPropertiesTest extends QpidBrokerTestCase -{ - - private static final Logger _logger = LoggerFactory.getLogger(JMSPropertiesTest.class); - - public String _connectionString = "vm://:1"; - - public static final String JMS_CORR_ID = "QPIDID_01"; - public static final int JMS_DELIV_MODE = 1; - public static final String JMS_TYPE = "test.jms.type"; - protected static final String NULL_OBJECT_PROPERTY = "NullObject"; - protected static final String INVALID_OBJECT_PROPERTY = "InvalidObject"; - - protected void setUp() throws Exception - { - super.setUp(); - } - - protected void tearDown() throws Exception - { - super.tearDown(); - } - - public void testJMSProperties() throws Exception - { - AMQConnection con = (AMQConnection) getConnection("guest", "guest"); - AMQSession consumerSession = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE); - Queue queue = - new AMQQueue(con.getDefaultQueueExchangeName(), new AMQShortString("someQ"), new AMQShortString("someQ"), false, - true); - MessageConsumer consumer = consumerSession.createConsumer(queue); - - AMQConnection con2 = (AMQConnection) getConnection("guest", "guest"); - Session producerSession = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE); - MessageProducer producer = producerSession.createProducer(queue); - Destination JMS_REPLY_TO = new AMQQueue(con2, "my.replyto"); - // create a test message to send - ObjectMessage sentMsg = new NonQpidObjectMessage(producerSession); - sentMsg.setJMSCorrelationID(JMS_CORR_ID); - sentMsg.setJMSDeliveryMode(JMS_DELIV_MODE); - sentMsg.setJMSType(JMS_TYPE); - sentMsg.setJMSReplyTo(JMS_REPLY_TO); - - String JMSXGroupID_VALUE = "group"; - sentMsg.setStringProperty("JMSXGroupID", JMSXGroupID_VALUE); - - int JMSXGroupSeq_VALUE = 1; - sentMsg.setIntProperty("JMSXGroupSeq", JMSXGroupSeq_VALUE); - - try - { - sentMsg.setObjectProperty(NULL_OBJECT_PROPERTY, null); - fail("Null Object Property value set"); - } - catch (MessageFormatException mfe) - { - // Check the error message - assertEquals("Incorrect error message", AMQPInvalidClassException.INVALID_OBJECT_MSG + "null", mfe.getMessage()); - } - - try - { - sentMsg.setObjectProperty(INVALID_OBJECT_PROPERTY, new Exception()); - fail("Non primitive Object Property value set"); - } - catch (MessageFormatException mfe) - { - // Check the error message - assertEquals("Incorrect error message: " + mfe.getMessage(), AMQPInvalidClassException.INVALID_OBJECT_MSG + Exception.class, mfe.getMessage()); - } - - // send it - producer.send(sentMsg); - - con2.close(); - - con.start(); - - // get message and check JMS properties - ObjectMessage rm = (ObjectMessage) consumer.receive(2000); - assertNotNull(rm); - - assertEquals("JMS Correlation ID mismatch", sentMsg.getJMSCorrelationID(), rm.getJMSCorrelationID()); - // TODO: Commented out as always overwritten by send delivery mode value - prob should not set in conversion - // assertEquals("JMS Delivery Mode mismatch",sentMsg.getJMSDeliveryMode(),rm.getJMSDeliveryMode()); - assertEquals("JMS Type mismatch", sentMsg.getJMSType(), rm.getJMSType()); - assertEquals("JMS Reply To mismatch", sentMsg.getJMSReplyTo(), rm.getJMSReplyTo()); - assertTrue("JMSMessageID Does not start ID:", rm.getJMSMessageID().startsWith("ID:")); - assertEquals("JMS Default priority should be 4",Message.DEFAULT_PRIORITY,rm.getJMSPriority()); - - //Validate that the JMSX values are correct - assertEquals("JMSXGroupID is not as expected:", JMSXGroupID_VALUE, rm.getStringProperty("JMSXGroupID")); - assertEquals("JMSXGroupSeq is not as expected:", JMSXGroupSeq_VALUE, rm.getIntProperty("JMSXGroupSeq")); - - boolean JMSXGroupID_Available = false; - boolean JMSXGroupSeq_Available = false; - Enumeration props = con.getMetaData().getJMSXPropertyNames(); - while (props.hasMoreElements()) - { - String name = (String) props.nextElement(); - if (name.equals("JMSXGroupID")) - { - JMSXGroupID_Available = true; - } - if (name.equals("JMSXGroupSeq")) - { - JMSXGroupSeq_Available = true; - } - } - - assertTrue("JMSXGroupID not available.",JMSXGroupID_Available); - assertTrue("JMSXGroupSeq not available.",JMSXGroupSeq_Available); - - // Check that the NULL_OBJECT_PROPERTY was not set or transmitted. - assertFalse(NULL_OBJECT_PROPERTY + " was not set.", rm.propertyExists(NULL_OBJECT_PROPERTY)); - - con.close(); - } - - /** - * Test Goal : Test if custom message properties can be set and retrieved properly with out an error. - * Also test if unsupported properties are filtered out. See QPID-2930. - */ - public void testQpidExtensionProperties() throws Exception - { - Connection con = getConnection("guest", "guest"); - Session ssn = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE); - con.start(); - - Topic topic = ssn.createTopic("test"); - MessageConsumer consumer = ssn.createConsumer(topic); - MessageProducer prod = ssn.createProducer(topic); - Message m = ssn.createMessage(); - m.setObjectProperty("foo-bar", "foobar".getBytes()); - m.setObjectProperty(QpidMessageProperties.AMQP_0_10_APP_ID, "my-app-id"); - prod.send(m); - - Message msg = consumer.receive(1000); - assertNotNull(msg); - - Enumeration enu = msg.getPropertyNames(); - Map map = new HashMap(); - while (enu.hasMoreElements()) - { - String name = enu.nextElement(); - String value = msg.getStringProperty(name); - map.put(name, value); - } - - assertFalse("Property 'foo-bar' should have been filtered out",map.containsKey("foo-bar")); - assertEquals("Property "+ QpidMessageProperties.AMQP_0_10_APP_ID + " should be present","my-app-id",msg.getStringProperty(QpidMessageProperties.AMQP_0_10_APP_ID)); - assertEquals("Property "+ QpidMessageProperties.AMQP_0_10_ROUTING_KEY + " should be present","test",msg.getStringProperty(QpidMessageProperties.AMQP_0_10_ROUTING_KEY)); - - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/StreamMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/StreamMessageTest.java deleted file mode 100644 index f8ab593c88..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/StreamMessageTest.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.message; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQHeadersExchange; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.url.AMQBindingURL; -import org.apache.qpid.url.BindingURL; - -import javax.jms.Connection; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageEOFException; -import javax.jms.MessageListener; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.StreamMessage; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -/** - * @author Apache Software Foundation - */ -public class StreamMessageTest extends QpidBrokerTestCase -{ - private static final Logger _logger = LoggerFactory.getLogger(StreamMessageTest.class); - - public void testStreamMessageEOF() throws Exception - { - AMQConnection con = (AMQConnection) getConnection("guest", "guest"); - AMQSession consumerSession = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE); - - AMQHeadersExchange queue = - new AMQHeadersExchange(new AMQBindingURL( - ExchangeDefaults.HEADERS_EXCHANGE_CLASS + "://" + ExchangeDefaults.HEADERS_EXCHANGE_NAME - + "/test/queue1?" + BindingURL.OPTION_ROUTING_KEY + "='F0000=1'")); - - FieldTable ft = new FieldTable(); - ft.setString("x-match", "any"); - ft.setString("F1000", "1"); - consumerSession.declareAndBind(queue, ft); - MessageConsumer consumer = consumerSession.createConsumer(queue); - // force synch to ensure the consumer has resulted in a bound queue - // ((AMQSession) consumerSession).declareExchangeSynch(ExchangeDefaults.HEADERS_EXCHANGE_NAME, ExchangeDefaults.HEADERS_EXCHANGE_CLASS); - // This is the default now - - Connection con2 = (AMQConnection) getConnection("guest", "guest"); - - AMQSession producerSession = (AMQSession) con2.createSession(false, Session.CLIENT_ACKNOWLEDGE); - - // Need to start the "producer" connection in order to receive bounced messages - _logger.info("Starting producer connection"); - con2.start(); - - MessageProducer mandatoryProducer = producerSession.createProducer(queue); - - // Third test - should be routed - _logger.info("Sending isBound message"); - StreamMessage msg = producerSession.createStreamMessage(); - - msg.setStringProperty("F1000", "1"); - - msg.writeByte((byte) 42); - - mandatoryProducer.send(msg); - - _logger.info("Starting consumer connection"); - con.start(); - - StreamMessage msg2 = (StreamMessage) consumer.receive(2000); - assertNotNull(msg2); - - msg2.readByte(); - try - { - msg2.readByte(); - fail("Expected exception not thrown"); - } - catch (Exception e) - { - assertTrue("Expected MessageEOFException: " + e, e instanceof MessageEOFException); - } - con.close(); - con2.close(); - } - - public void testModifyReceivedMessageExpandsBuffer() throws Exception - { - final CountDownLatch awaitMessages = new CountDownLatch(1); - final AtomicReference listenerCaughtException = new AtomicReference(); - - AMQConnection con = (AMQConnection) getConnection("guest", "guest"); - AMQSession consumerSession = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE); - AMQQueue queue = new AMQQueue(con.getDefaultQueueExchangeName(), new AMQShortString("testQ")); - MessageConsumer consumer = consumerSession.createConsumer(queue); - consumer.setMessageListener(new MessageListener() - { - - public void onMessage(Message message) - { - final StreamMessage sm = (StreamMessage) message; - try - { - sm.clearBody(); - // it is legal to extend a stream message's content - sm.writeString("dfgjshfslfjshflsjfdlsjfhdsljkfhdsljkfhsd"); - } - catch (Throwable t) - { - listenerCaughtException.set(t); - } - finally - { - awaitMessages.countDown(); - } - } - }); - - Connection con2 = (AMQConnection) getConnection("guest", "guest"); - AMQSession producerSession = (AMQSession) con2.createSession(false, Session.CLIENT_ACKNOWLEDGE); - MessageProducer producer = producerSession.createProducer(queue); - con.start(); - StreamMessage sm = producerSession.createStreamMessage(); - sm.writeInt(42); - producer.send(sm); - - // Allow up to five seconds for the message to arrive with the consumer - final boolean completed = awaitMessages.await(5, TimeUnit.SECONDS); - assertTrue("Message did not arrive with consumer within a reasonable time", completed); - final Throwable listenerException = listenerCaughtException.get(); - assertNull("No exception should be caught by listener : " + listenerException, listenerException); - - con.close(); - con2.close(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8En b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8En deleted file mode 100644 index c9734b1988..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8En +++ /dev/null @@ -1,4 +0,0 @@ -exhangeName -queueName -routingkey -data \ No newline at end of file diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8Jp b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8Jp deleted file mode 100644 index ae10752dab..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8Jp +++ /dev/null @@ -1,4 +0,0 @@ -設定がそのように構成されていなければな -的某些更新没有出现在这个 README 中。你可以访问下面的 -的发行版本包括多张光盘,其中包括安装光盘和源码光盘 -目のインストール CD は、ほとんどの最近のシス \ No newline at end of file diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8Test.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8Test.java deleted file mode 100644 index cc95afafa2..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/message/UTF8Test.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.message; - -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.TextMessage; -import javax.naming.InitialContext; -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Properties; - - -/** - * This test makes sure that utf8 characters can be used for - * specifying exchange, queue name and routing key. - * - * those tests are related to qpid-1384 - */ -public class UTF8Test extends QpidBrokerTestCase -{ - public void testPlainEn() throws Exception - { - invoke("UTF8En"); - } - - - public void testUTF8Jp() throws Exception - { - invoke("UTF8Jp"); - } - - private void invoke(String name) throws Exception - { - InputStream stream = getClass().getClassLoader().getResourceAsStream("org/apache/qpid/test/unit/message/" + name); - - BufferedReader in = new BufferedReader(new InputStreamReader(stream, "UTF8")); - runTest(in.readLine(), in.readLine(), in.readLine(), in.readLine()); - in.close(); - } - - private void runTest(String exchangeName, String queueName, String routingKey, String data) throws Exception - { - Connection con = getConnection(); - Session sess = con.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); - final Destination dest = getDestination(exchangeName, routingKey, queueName); - - final MessageConsumer msgCons = sess.createConsumer(dest); - con.start(); - - // Send data - MessageProducer msgProd = sess.createProducer(dest); - TextMessage message = sess.createTextMessage(data); - msgProd.send(message); - - // consume data - TextMessage m = (TextMessage) msgCons.receive(RECEIVE_TIMEOUT); - assertNotNull(m); - assertEquals(m.getText(), data); - } - - private Destination getDestination(String exch, String routkey, String qname) throws Exception - { - Properties props = new Properties(); - props.setProperty("destination.directUTF8Queue", - "direct://" + exch + "//" + qname + "?autodelete='false'&durable='false'" - + "&routingkey='" + routkey + "'"); - - // Get our connection context - InitialContext ctx = new InitialContext(props); - return (Destination) ctx.lookup("directUTF8Queue"); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java deleted file mode 100644 index cc8bfb9433..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java +++ /dev/null @@ -1,1063 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.topic; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQNoRouteException; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.management.common.JMXConnnectionFactory; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.ExceptionListener; -import javax.jms.InvalidDestinationException; -import javax.jms.InvalidSelectorException; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.TextMessage; -import javax.jms.Topic; -import javax.jms.TopicSubscriber; -import javax.management.MBeanServerConnection; -import javax.management.ObjectName; -import javax.management.remote.JMXConnector; -import java.io.IOException; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -/** - * @todo Code to check that a consumer gets only one particular method could be factored into a re-usable method (as - * a static on a base test helper class, e.g. TestUtils. - * - * @todo Code to create test end-points using session per connection, or all sessions on one connection, to be factored - * out to make creating this test variation simpler. Want to make this variation available through LocalCircuit, - * driven by the test model. - */ -public class DurableSubscriptionTest extends QpidBrokerTestCase -{ - private static final Logger _logger = LoggerFactory.getLogger(DurableSubscriptionTest.class); - - private static final String MY_TOPIC = "MyTopic"; - - private static final String MY_SUBSCRIPTION = "MySubscription"; - - /** Timeout for receive() if we are expecting a message */ - private static final long POSITIVE_RECEIVE_TIMEOUT = 2000; - - /** Timeout for receive() if we are not expecting a message */ - private static final long NEGATIVE_RECEIVE_TIMEOUT = 1000; - - private JMXConnector _jmxc; - private MBeanServerConnection _mbsc; - private static final String USER = "admin"; - private static final String PASSWORD = "admin"; - private boolean _jmxConnected; - - public void setUp() throws Exception - { - getBrokerConfiguration().addJmxManagementConfiguration(); - _jmxConnected=false; - super.setUp(); - } - - public void tearDown() throws Exception - { - try - { - if(_jmxConnected) - { - try - { - _jmxc.close(); - } - catch (IOException e) - { - _logger.error("Error closing JMX connection", e); - } - } - } - finally - { - super.tearDown(); - } - } - - public void testUnsubscribe() throws Exception - { - AMQConnection con = (AMQConnection) getConnection(); - AMQTopic topic = new AMQTopic(con, "MyDurableSubscriptionTestTopic"); - _logger.info("Create Session 1"); - Session session1 = con.createSession(false, AMQSession.NO_ACKNOWLEDGE); - _logger.info("Create Consumer on Session 1"); - MessageConsumer consumer1 = session1.createConsumer(topic); - _logger.info("Create Producer on Session 1"); - MessageProducer producer = session1.createProducer(topic); - - _logger.info("Create Session 2"); - Session session2 = con.createSession(false, AMQSession.NO_ACKNOWLEDGE); - _logger.info("Create Durable Subscriber on Session 2"); - TopicSubscriber consumer2 = session2.createDurableSubscriber(topic, MY_SUBSCRIPTION); - - _logger.info("Starting connection"); - con.start(); - - _logger.info("Producer sending message A"); - producer.send(session1.createTextMessage("A")); - - //check the dur sub's underlying queue now has msg count 1 - AMQQueue subQueue = new AMQQueue("amq.topic", "clientid" + ":" + MY_SUBSCRIPTION); - assertEquals("Msg count should be 1", 1, ((AMQSession) session1).getQueueDepth(subQueue, true)); - - Message msg; - _logger.info("Receive message on consumer 1:expecting A"); - msg = consumer1.receive(POSITIVE_RECEIVE_TIMEOUT); - assertNotNull("Message should have been received",msg); - assertEquals("A", ((TextMessage) msg).getText()); - _logger.info("Receive message on consumer 1 :expecting null"); - msg = consumer1.receive(NEGATIVE_RECEIVE_TIMEOUT); - assertEquals(null, msg); - - _logger.info("Receive message on consumer 2:expecting A"); - msg = consumer2.receive(POSITIVE_RECEIVE_TIMEOUT); - assertNotNull("Message should have been received",msg); - assertEquals("A", ((TextMessage) msg).getText()); - msg = consumer2.receive(NEGATIVE_RECEIVE_TIMEOUT); - _logger.info("Receive message on consumer 1 :expecting null"); - assertEquals(null, msg); - - //check the dur sub's underlying queue now has msg count 0 - assertEquals("Msg count should be 0", 0, ((AMQSession) session2).getQueueDepth(subQueue, true)); - - consumer2.close(); - _logger.info("Unsubscribe session2/consumer2"); - session2.unsubscribe(MY_SUBSCRIPTION); - - ((AMQSession) session2).sync(); - - if(isJavaBroker()) - { - //Verify that the queue was deleted by querying for its JMX MBean - _jmxc = JMXConnnectionFactory.getJMXConnection(5000, "127.0.0.1", - getManagementPort(getPort()), USER, PASSWORD); - - _jmxConnected = true; - _mbsc = _jmxc.getMBeanServerConnection(); - - //must replace the occurrence of ':' in queue name with '-' - String queueObjectNameText = "clientid" + "-" + MY_SUBSCRIPTION; - - ObjectName objName = new ObjectName("org.apache.qpid:type=VirtualHost.Queue,name=" - + queueObjectNameText + ",*"); - - Set objectInstances = _mbsc.queryNames(objName, null); - - if(objectInstances.size() != 0) - { - fail("Queue MBean was found. Expected queue to have been deleted"); - } - else - { - _logger.info("Underlying dueue for the durable subscription was confirmed deleted."); - } - } - - //verify unsubscribing the durable subscriber did not affect the non-durable one - _logger.info("Producer sending message B"); - producer.send(session1.createTextMessage("B")); - - _logger.info("Receive message on consumer 1 :expecting B"); - msg = consumer1.receive(POSITIVE_RECEIVE_TIMEOUT); - assertNotNull("Message should have been received",msg); - assertEquals("B", ((TextMessage) msg).getText()); - _logger.info("Receive message on consumer 1 :expecting null"); - msg = consumer1.receive(NEGATIVE_RECEIVE_TIMEOUT); - assertEquals(null, msg); - - _logger.info("Close connection"); - con.close(); - } - - - /** - * Specifically uses a subscriber with a selector because QPID-4731 found that selectors - * can prevent queue removal. - */ - public void testUnsubscribeWhenUsingSelectorMakesTopicUnreachable() throws Exception - { - setTestClientSystemProperty("qpid.default_mandatory_topic","true"); - - // set up subscription - AMQConnection connection = (AMQConnection) getConnection(); - connection.start(); - - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Topic topic = new AMQTopic(connection, MY_TOPIC); - MessageProducer producer = session.createProducer(topic); - - TopicSubscriber subscriber = session.createDurableSubscriber(topic, MY_SUBSCRIPTION, "1 = 1", false); - StoringExceptionListener exceptionListener = new StoringExceptionListener(); - connection.setExceptionListener(exceptionListener); - - // send message and verify it was consumed - producer.send(session.createTextMessage("message1")); - assertNotNull("Message should have been successfully received", subscriber.receive(POSITIVE_RECEIVE_TIMEOUT)); - assertEquals(null, exceptionListener.getException()); - session.unsubscribe(MY_SUBSCRIPTION); - - // send another message and verify that the connection exception listener was fired. - StoringExceptionListener exceptionListener2 = new StoringExceptionListener(); - connection.setExceptionListener(exceptionListener2); - - producer.send(session.createTextMessage("message that should be unroutable")); - ((AMQSession) session).sync(); - - JMSException exception = exceptionListener2.awaitException(); - assertNotNull("Expected exception as message should no longer be routable", exception); - - Throwable linkedException = exception.getLinkedException(); - assertNotNull("The linked exception of " + exception + " should be the 'no route' exception", linkedException); - assertEquals(AMQNoRouteException.class, linkedException.getClass()); - } - - private final class StoringExceptionListener implements ExceptionListener - { - private volatile JMSException _exception; - private CountDownLatch _latch = new CountDownLatch(1); - - @Override - public void onException(JMSException exception) - { - _exception = exception; - _logger.info("Exception listener received: " + exception); - _latch.countDown(); - } - - public JMSException awaitException() throws InterruptedException - { - _latch.await(POSITIVE_RECEIVE_TIMEOUT, TimeUnit.MILLISECONDS); - return _exception; - } - - public JMSException getException() - { - return _exception; - } - } - - public void testDurabilityNOACK() throws Exception - { - durabilityImpl(AMQSession.NO_ACKNOWLEDGE, false); - } - - public void testDurabilityAUTOACK() throws Exception - { - durabilityImpl(Session.AUTO_ACKNOWLEDGE, false); - } - - public void testDurabilityAUTOACKwithRestartIfPersistent() throws Exception - { - if(!isBrokerStorePersistent()) - { - _logger.warn("The broker store is not persistent, skipping this test"); - return; - } - - durabilityImpl(Session.AUTO_ACKNOWLEDGE, true); - } - - public void testDurabilityNOACKSessionPerConnection() throws Exception - { - durabilityImplSessionPerConnection(AMQSession.NO_ACKNOWLEDGE); - } - - public void testDurabilityAUTOACKSessionPerConnection() throws Exception - { - durabilityImplSessionPerConnection(Session.AUTO_ACKNOWLEDGE); - } - - private void durabilityImpl(int ackMode, boolean restartBroker) throws Exception - { - AMQConnection con = (AMQConnection) getConnection(); - AMQTopic topic = new AMQTopic(con, MY_TOPIC); - Session session1 = con.createSession(false, ackMode); - MessageConsumer consumer1 = session1.createConsumer(topic); - - Session sessionProd = con.createSession(false, ackMode); - MessageProducer producer = sessionProd.createProducer(topic); - - Session session2 = con.createSession(false, ackMode); - TopicSubscriber consumer2 = session2.createDurableSubscriber(topic, MY_SUBSCRIPTION); - - con.start(); - - //send message A and check both consumers receive - producer.send(session1.createTextMessage("A")); - - Message msg; - _logger.info("Receive message on consumer 1 :expecting A"); - msg = consumer1.receive(POSITIVE_RECEIVE_TIMEOUT); - assertNotNull("Message should have been received",msg); - assertEquals("A", ((TextMessage) msg).getText()); - msg = consumer1.receive(NEGATIVE_RECEIVE_TIMEOUT); - assertEquals(null, msg); - - _logger.info("Receive message on consumer 2 :expecting A"); - msg = consumer2.receive(POSITIVE_RECEIVE_TIMEOUT); - assertNotNull("Message should have been received",msg); - assertEquals("A", ((TextMessage) msg).getText()); - msg = consumer2.receive(NEGATIVE_RECEIVE_TIMEOUT); - assertEquals(null, msg); - - //send message B, receive with consumer 1, and disconnect consumer 2 to leave the message behind (if not NO_ACK) - producer.send(session1.createTextMessage("B")); - - _logger.info("Receive message on consumer 1 :expecting B"); - msg = consumer1.receive(POSITIVE_RECEIVE_TIMEOUT); - assertNotNull("Consumer 1 should get message 'B'.", msg); - assertEquals("Incorrect Message received on consumer1.", "B", ((TextMessage) msg).getText()); - _logger.info("Receive message on consumer 1 :expecting null"); - msg = consumer1.receive(500); - assertNull("There should be no more messages for consumption on consumer1.", msg); - - consumer2.close(); - session2.close(); - - //Send message C, then connect consumer 3 to durable subscription and get - //message B if not using NO_ACK, then receive C with consumer 1 and 3 - producer.send(session1.createTextMessage("C")); - - Session session3 = con.createSession(false, ackMode); - MessageConsumer consumer3 = session3.createDurableSubscriber(topic, MY_SUBSCRIPTION); - - if(ackMode == AMQSession.NO_ACKNOWLEDGE) - { - //Do nothing if NO_ACK was used, as prefetch means the message was dropped - //when we didn't call receive() to get it before closing consumer 2 - } - else - { - _logger.info("Receive message on consumer 3 :expecting B"); - msg = consumer3.receive(POSITIVE_RECEIVE_TIMEOUT); - assertNotNull("Consumer 3 should get message 'B'.", msg); - assertEquals("Incorrect Message received on consumer3.", "B", ((TextMessage) msg).getText()); - } - - _logger.info("Receive message on consumer 1 :expecting C"); - msg = consumer1.receive(POSITIVE_RECEIVE_TIMEOUT); - assertNotNull("Consumer 1 should get message 'C'.", msg); - assertEquals("Incorrect Message received on consumer1.", "C", ((TextMessage) msg).getText()); - _logger.info("Receive message on consumer 1 :expecting null"); - msg = consumer1.receive(500); - assertNull("There should be no more messages for consumption on consumer1.", msg); - - _logger.info("Receive message on consumer 3 :expecting C"); - msg = consumer3.receive(POSITIVE_RECEIVE_TIMEOUT); - assertNotNull("Consumer 3 should get message 'C'.", msg); - assertEquals("Incorrect Message received on consumer3.", "C", ((TextMessage) msg).getText()); - _logger.info("Receive message on consumer 3 :expecting null"); - msg = consumer3.receive(500); - assertNull("There should be no more messages for consumption on consumer3.", msg); - - consumer1.close(); - consumer3.close(); - - session3.unsubscribe(MY_SUBSCRIPTION); - - con.close(); - - if(restartBroker) - { - try - { - restartBroker(); - } - catch (Exception e) - { - fail("Error restarting the broker"); - } - } - } - - private void durabilityImplSessionPerConnection(int ackMode) throws Exception - { - Message msg; - // Create producer. - AMQConnection con0 = (AMQConnection) getConnection(); - con0.start(); - Session session0 = con0.createSession(false, ackMode); - - AMQTopic topic = new AMQTopic(con0, MY_TOPIC); - - Session sessionProd = con0.createSession(false, ackMode); - MessageProducer producer = sessionProd.createProducer(topic); - - // Create consumer 1. - AMQConnection con1 = (AMQConnection) getConnection(); - con1.start(); - Session session1 = con1.createSession(false, ackMode); - - MessageConsumer consumer1 = session1.createConsumer(topic); - - // Create consumer 2. - AMQConnection con2 = (AMQConnection) getConnection(); - con2.start(); - Session session2 = con2.createSession(false, ackMode); - - TopicSubscriber consumer2 = session2.createDurableSubscriber(topic, MY_SUBSCRIPTION); - - // Send message and check that both consumers get it and only it. - producer.send(session0.createTextMessage("A")); - - msg = consumer1.receive(POSITIVE_RECEIVE_TIMEOUT); - assertNotNull("Message should be available", msg); - assertEquals("Message Text doesn't match", "A", ((TextMessage) msg).getText()); - msg = consumer1.receive(500); - assertNull("There should be no more messages for consumption on consumer1.", msg); - - msg = consumer2.receive(POSITIVE_RECEIVE_TIMEOUT); - assertNotNull("Message should have been received",msg); - assertEquals("Consumer 2 should also received the first msg.", "A", ((TextMessage) msg).getText()); - msg = consumer2.receive(NEGATIVE_RECEIVE_TIMEOUT); - assertNull("There should be no more messages for consumption on consumer2.", msg); - - // Send message and receive on consumer 1. - producer.send(session0.createTextMessage("B")); - - _logger.info("Receive message on consumer 1 :expecting B"); - msg = consumer1.receive(POSITIVE_RECEIVE_TIMEOUT); - assertEquals("B", ((TextMessage) msg).getText()); - _logger.info("Receive message on consumer 1 :expecting null"); - msg = consumer1.receive(NEGATIVE_RECEIVE_TIMEOUT); - assertEquals(null, msg); - - // Detach the durable subscriber. - consumer2.close(); - session2.close(); - con2.close(); - - // Send message C and receive on consumer 1 - producer.send(session0.createTextMessage("C")); - - _logger.info("Receive message on consumer 1 :expecting C"); - msg = consumer1.receive(POSITIVE_RECEIVE_TIMEOUT); - assertEquals("C", ((TextMessage) msg).getText()); - _logger.info("Receive message on consumer 1 :expecting null"); - msg = consumer1.receive(NEGATIVE_RECEIVE_TIMEOUT); - assertEquals(null, msg); - - // Re-attach a new consumer to the durable subscription, and check that it gets message B it left (if not NO_ACK) - // and also gets message C sent after it was disconnected. - AMQConnection con3 = (AMQConnection) getConnection(); - con3.start(); - Session session3 = con3.createSession(false, ackMode); - - TopicSubscriber consumer3 = session3.createDurableSubscriber(topic, MY_SUBSCRIPTION); - - if(ackMode == AMQSession.NO_ACKNOWLEDGE) - { - //Do nothing if NO_ACK was used, as prefetch means the message was dropped - //when we didn't call receive() to get it before closing consumer 2 - } - else - { - _logger.info("Receive message on consumer 3 :expecting B"); - msg = consumer3.receive(POSITIVE_RECEIVE_TIMEOUT); - assertNotNull(msg); - assertEquals("B", ((TextMessage) msg).getText()); - } - - _logger.info("Receive message on consumer 3 :expecting C"); - msg = consumer3.receive(POSITIVE_RECEIVE_TIMEOUT); - assertNotNull("Consumer 3 should get message 'C'.", msg); - assertEquals("Incorrect Message recevied on consumer3.", "C", ((TextMessage) msg).getText()); - _logger.info("Receive message on consumer 3 :expecting null"); - msg = consumer3.receive(NEGATIVE_RECEIVE_TIMEOUT); - assertNull("There should be no more messages for consumption on consumer3.", msg); - - consumer1.close(); - consumer3.close(); - - session3.unsubscribe(MY_SUBSCRIPTION); - - con0.close(); - con1.close(); - con3.close(); - } - - /** - * This tests the fix for QPID-1085 - * Creates a durable subscriber with an invalid selector, checks that the - * exception is thrown correctly and that the subscription is not created. - * @throws Exception - */ - public void testDurableWithInvalidSelector() throws Exception - { - Connection conn = getConnection(); - conn.start(); - Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - AMQTopic topic = new AMQTopic((AMQConnection) conn, "MyTestDurableWithInvalidSelectorTopic"); - MessageProducer producer = session.createProducer(topic); - producer.send(session.createTextMessage("testDurableWithInvalidSelector1")); - try - { - TopicSubscriber deadSubscriber = session.createDurableSubscriber(topic, "testDurableWithInvalidSelectorSub", - "=TEST 'test", true); - assertNull("Subscriber should not have been created", deadSubscriber); - } - catch (JMSException e) - { - assertTrue("Wrong type of exception thrown", e instanceof InvalidSelectorException); - } - TopicSubscriber liveSubscriber = session.createDurableSubscriber(topic, "testDurableWithInvalidSelectorSub"); - assertNotNull("Subscriber should have been created", liveSubscriber); - - producer.send(session.createTextMessage("testDurableWithInvalidSelector2")); - - Message msg = liveSubscriber.receive(POSITIVE_RECEIVE_TIMEOUT); - assertNotNull ("Message should have been received", msg); - assertEquals ("testDurableWithInvalidSelector2", ((TextMessage) msg).getText()); - assertNull("Should not receive subsequent message", liveSubscriber.receive(200)); - liveSubscriber.close(); - session.unsubscribe("testDurableWithInvalidSelectorSub"); - } - - /** - * This tests the fix for QPID-1085 - * Creates a durable subscriber with an invalid destination, checks that the - * exception is thrown correctly and that the subscription is not created. - * @throws Exception - */ - public void testDurableWithInvalidDestination() throws Exception - { - Connection conn = getConnection(); - conn.start(); - Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - AMQTopic topic = new AMQTopic((AMQConnection) conn, "testDurableWithInvalidDestinationTopic"); - try - { - TopicSubscriber deadSubscriber = session.createDurableSubscriber(null, "testDurableWithInvalidDestinationsub"); - assertNull("Subscriber should not have been created", deadSubscriber); - } - catch (InvalidDestinationException e) - { - // This was expected - } - MessageProducer producer = session.createProducer(topic); - producer.send(session.createTextMessage("testDurableWithInvalidSelector1")); - - TopicSubscriber liveSubscriber = session.createDurableSubscriber(topic, "testDurableWithInvalidDestinationsub"); - assertNotNull("Subscriber should have been created", liveSubscriber); - - producer.send(session.createTextMessage("testDurableWithInvalidSelector2")); - Message msg = liveSubscriber.receive(POSITIVE_RECEIVE_TIMEOUT); - assertNotNull ("Message should have been received", msg); - assertEquals ("testDurableWithInvalidSelector2", ((TextMessage) msg).getText()); - assertNull("Should not receive subsequent message", liveSubscriber.receive(200)); - - session.unsubscribe("testDurableWithInvalidDestinationsub"); - } - - /** - * Creates a durable subscription with a selector, then changes that selector on resubscription - *

- * QPID-1202, QPID-2418 - */ - public void testResubscribeWithChangedSelector() throws Exception - { - Connection conn = getConnection(); - conn.start(); - Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - AMQTopic topic = new AMQTopic((AMQConnection) conn, "testResubscribeWithChangedSelector"); - MessageProducer producer = session.createProducer(topic); - - // Create durable subscriber that matches A - TopicSubscriber subA = session.createDurableSubscriber(topic, - "testResubscribeWithChangedSelector", - "Match = True", false); - - // Send 1 matching message and 1 non-matching message - sendMatchingAndNonMatchingMessage(session, producer); - - Message rMsg = subA.receive(NEGATIVE_RECEIVE_TIMEOUT); - assertNotNull(rMsg); - assertEquals("Content was wrong", - "testResubscribeWithChangedSelector1", - ((TextMessage) rMsg).getText()); - - rMsg = subA.receive(NEGATIVE_RECEIVE_TIMEOUT); - assertNull(rMsg); - - // Disconnect subscriber - subA.close(); - - // Reconnect with new selector that matches B - TopicSubscriber subB = session.createDurableSubscriber(topic, - "testResubscribeWithChangedSelector","Match = False", false); - - //verify no messages are now received. - rMsg = subB.receive(NEGATIVE_RECEIVE_TIMEOUT); - assertNull("Should not have received message as the selector was changed", rMsg); - - // Check that new messages are received properly - sendMatchingAndNonMatchingMessage(session, producer); - rMsg = subB.receive(POSITIVE_RECEIVE_TIMEOUT); - - assertNotNull("Message should have been received", rMsg); - assertEquals("Content was wrong", - "testResubscribeWithChangedSelector2", - ((TextMessage) rMsg).getText()); - - - rMsg = subB.receive(NEGATIVE_RECEIVE_TIMEOUT); - assertNull("Message should not have been received",rMsg); - session.unsubscribe("testResubscribeWithChangedSelector"); - } - - public void testDurableSubscribeWithTemporaryTopic() throws Exception - { - Connection conn = getConnection(); - conn.start(); - Session ssn = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - Topic topic = ssn.createTemporaryTopic(); - try - { - ssn.createDurableSubscriber(topic, "test"); - fail("expected InvalidDestinationException"); - } - catch (InvalidDestinationException ex) - { - // this is expected - } - try - { - ssn.createDurableSubscriber(topic, "test", null, false); - fail("expected InvalidDestinationException"); - } - catch (InvalidDestinationException ex) - { - // this is expected - } - } - - private void sendMatchingAndNonMatchingMessage(Session session, MessageProducer producer) throws JMSException - { - TextMessage msg = session.createTextMessage("testResubscribeWithChangedSelector1"); - msg.setBooleanProperty("Match", true); - producer.send(msg); - msg = session.createTextMessage("testResubscribeWithChangedSelector2"); - msg.setBooleanProperty("Match", false); - producer.send(msg); - } - - - /** - * create and register a durable subscriber with a message selector and then close it - * create a publisher and send 5 right messages and 5 wrong messages - * create another durable subscriber with the same selector and name - * check messages are still there - *

- * QPID-2418 - */ - public void testDurSubSameMessageSelector() throws Exception - { - Connection conn = getConnection(); - conn.start(); - Session session = conn.createSession(true, Session.SESSION_TRANSACTED); - AMQTopic topic = new AMQTopic((AMQConnection) conn, "sameMessageSelector"); - - //create and register a durable subscriber with a message selector and then close it - TopicSubscriber subOne = session.createDurableSubscriber(topic, "sameMessageSelector", "testprop = TRUE", false); - subOne.close(); - - MessageProducer producer = session.createProducer(topic); - for (int i = 0; i < 5; i++) - { - Message message = session.createMessage(); - message.setBooleanProperty("testprop", true); - producer.send(message); - message = session.createMessage(); - message.setBooleanProperty("testprop", false); - producer.send(message); - } - session.commit(); - producer.close(); - - // should be 5 or 10 messages on queue now - // (5 for the java broker due to use of server side selectors, and 10 for the cpp broker due to client side selectors only) - AMQQueue queue = new AMQQueue("amq.topic", "clientid" + ":" + "sameMessageSelector"); - assertEquals("Queue depth is wrong", isJavaBroker() ? 5 : 10, ((AMQSession) session).getQueueDepth(queue, true)); - - // now recreate the durable subscriber and check the received messages - TopicSubscriber subTwo = session.createDurableSubscriber(topic, "sameMessageSelector", "testprop = TRUE", false); - - for (int i = 0; i < 5; i++) - { - Message message = subTwo.receive(1000); - if (message == null) - { - fail("sameMessageSelector test failed. no message was returned"); - } - else - { - assertEquals("sameMessageSelector test failed. message selector not reset", - "true", message.getStringProperty("testprop")); - } - } - - session.commit(); - - // Check queue has no messages - if (isJavaBroker()) - { - assertEquals("Queue should be empty", 0, ((AMQSession) session).getQueueDepth(queue)); - } - else - { - assertTrue("At most the queue should have only 1 message", ((AMQSession) session).getQueueDepth(queue) <= 1); - } - - // Unsubscribe - session.unsubscribe("sameMessageSelector"); - - conn.close(); - } - - /** - *

    - *
  • create and register a durable subscriber with a message selector - *
  • create another durable subscriber with a different selector and same name - *
  • check first subscriber is now closed - *
  • create a publisher and send messages - *
  • check messages are received correctly - *
- *

- * QPID-2418 - */ - public void testResubscribeWithChangedSelectorNoClose() throws Exception - { - Connection conn = getConnection(); - conn.start(); - Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - AMQTopic topic = new AMQTopic((AMQConnection) conn, "testResubscribeWithChangedSelectorNoClose"); - - // Create durable subscriber that matches A - TopicSubscriber subA = session.createDurableSubscriber(topic, - "testResubscribeWithChangedSelectorNoClose", - "Match = True", false); - - // Reconnect with new selector that matches B - TopicSubscriber subB = session.createDurableSubscriber(topic, - "testResubscribeWithChangedSelectorNoClose", - "Match = false", false); - - // First subscription has been closed - try - { - subA.receive(1000); - fail("First subscription was not closed"); - } - catch (Exception e) - { - _logger.error("Receive error",e); - } - - conn.stop(); - - // Send 1 matching message and 1 non-matching message - MessageProducer producer = session.createProducer(topic); - TextMessage msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart1"); - msg.setBooleanProperty("Match", true); - producer.send(msg); - msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart2"); - msg.setBooleanProperty("Match", false); - producer.send(msg); - - // should be 1 or 2 messages on queue now - // (1 for the java broker due to use of server side selectors, and 2 for the cpp broker due to client side selectors only) - AMQQueue queue = new AMQQueue("amq.topic", "clientid" + ":" + "testResubscribeWithChangedSelectorNoClose"); - assertEquals("Queue depth is wrong", isJavaBroker() ? 1 : 2, ((AMQSession) session).getQueueDepth(queue, true)); - - conn.start(); - - Message rMsg = subB.receive(POSITIVE_RECEIVE_TIMEOUT); - assertNotNull(rMsg); - assertEquals("Content was wrong", - "testResubscribeWithChangedSelectorAndRestart2", - ((TextMessage) rMsg).getText()); - - rMsg = subB.receive(1000); - assertNull(rMsg); - - // Check queue has no messages - assertEquals("Queue should be empty", 0, ((AMQSession) session).getQueueDepth(queue, true)); - - conn.close(); - } - - /** - *

    - *
  • create and register a durable subscriber with no message selector - *
  • create another durable subscriber with a selector and same name - *
  • check first subscriber is now closed - *
  • create a publisher and send messages - *
  • check messages are received correctly - *
- *

- * QPID-2418 - */ - public void testDurSubAddMessageSelectorNoClose() throws Exception - { - Connection conn = getConnection(); - conn.start(); - Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - AMQTopic topic = new AMQTopic((AMQConnection) conn, "subscriptionName"); - - // create and register a durable subscriber with no message selector - TopicSubscriber subOne = session.createDurableSubscriber(topic, "subscriptionName", null, false); - - // now create a durable subscriber with a selector - TopicSubscriber subTwo = session.createDurableSubscriber(topic, "subscriptionName", "testprop = TRUE", false); - - // First subscription has been closed - try - { - subOne.receive(1000); - fail("First subscription was not closed"); - } - catch (Exception e) - { - _logger.error("Receive error",e); - } - - conn.stop(); - - // Send 1 matching message and 1 non-matching message - MessageProducer producer = session.createProducer(topic); - TextMessage msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart1"); - msg.setBooleanProperty("testprop", true); - producer.send(msg); - msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart2"); - msg.setBooleanProperty("testprop", false); - producer.send(msg); - - // should be 1 or 2 messages on queue now - // (1 for the java broker due to use of server side selectors, and 2 for the cpp broker due to client side selectors only) - AMQQueue queue = new AMQQueue("amq.topic", "clientid" + ":" + "subscriptionName"); - assertEquals("Queue depth is wrong", isJavaBroker() ? 1 : 2, ((AMQSession) session).getQueueDepth(queue, true)); - - conn.start(); - - Message rMsg = subTwo.receive(POSITIVE_RECEIVE_TIMEOUT); - assertNotNull(rMsg); - assertEquals("Content was wrong", - "testResubscribeWithChangedSelectorAndRestart1", - ((TextMessage) rMsg).getText()); - - rMsg = subTwo.receive(1000); - assertNull(rMsg); - - // Check queue has no messages - assertEquals("Queue should be empty", 0, ((AMQSession) session).getQueueDepth(queue, true)); - - conn.close(); - } - - /** - *

    - *
  • create and register a durable subscriber with no message selector - *
  • try to create another durable with the same name, should fail - *
- *

- * QPID-2418 - */ - public void testDurSubNoSelectorResubscribeNoClose() throws Exception - { - Connection conn = getConnection(); - conn.start(); - Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - AMQTopic topic = new AMQTopic((AMQConnection) conn, "subscriptionName"); - - // create and register a durable subscriber with no message selector - session.createDurableSubscriber(topic, "subscriptionName", null, false); - - // try to recreate the durable subscriber - try - { - session.createDurableSubscriber(topic, "subscriptionName", null, false); - fail("Subscription should not have been created"); - } - catch (Exception e) - { - _logger.error("Error creating durable subscriber",e); - } - } - - /** - * Tests that a subscriber created on a same session as producer with - * no local true does not receive messages. - */ - public void testNoLocalOnSameSession() throws Exception - { - Connection connection = getConnection(); - Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Topic topic = session.createTopic(getTestQueueName()); - MessageProducer producer = session.createProducer(topic); - TopicSubscriber subscriber = null; - try - { - subscriber = session.createDurableSubscriber(topic, getTestName(), null, true); - connection.start(); - - producer.send(createNextMessage(session, 1)); - - Message m = subscriber.receive(NEGATIVE_RECEIVE_TIMEOUT); - assertNull("Unexpected message received", m); - } - finally - { - session.unsubscribe(getTestName()); - } - } - - - /** - * Tests that a subscriber created on a same connection but separate - * sessionM as producer with no local true does not receive messages. - */ - public void testNoLocalOnSameConnection() throws Exception - { - Connection connection = getConnection(); - - Session consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Session producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Topic topic = consumerSession.createTopic(getTestQueueName()); - MessageProducer producer = producerSession.createProducer(topic); - - TopicSubscriber subscriber = null; - try - { - subscriber = consumerSession.createDurableSubscriber(topic, getTestName(), null, true); - connection.start(); - - producer.send(createNextMessage(producerSession, 1)); - - Message m = subscriber.receive(NEGATIVE_RECEIVE_TIMEOUT); - assertNull("Unexpected message received", m); - } - finally - { - consumerSession.unsubscribe(getTestName()); - } - } - - /** - * Tests that if no-local is in use, that the messages are delivered when - * the client reconnects. - * - * Currently fails on the Java Broker due to QPID-3605. - */ - public void testNoLocalMessagesNotDeliveredAfterReconnection() throws Exception - { - Connection connection = getConnection(); - - Session consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Session producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Topic topic = consumerSession.createTopic(getTestQueueName()); - MessageProducer producer = producerSession.createProducer(topic); - - TopicSubscriber subscriber = null; - try - { - subscriber = consumerSession.createDurableSubscriber(topic, getTestName(), null, true); - connection.start(); - - producer.send(createNextMessage(producerSession, 1)); - - Message m = subscriber.receive(NEGATIVE_RECEIVE_TIMEOUT); - assertNull("Unexpected message received", m); - - connection.close(); - - connection = getConnection(); - - consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - subscriber = consumerSession.createDurableSubscriber(topic, getTestName(), null, true); - connection.start(); - m = subscriber.receive(NEGATIVE_RECEIVE_TIMEOUT); - assertNull("Message should not be received on a new connection", m); - } - finally - { - consumerSession.unsubscribe(getTestName()); - } - } - - /** - * Tests that messages are delivered normally to a subscriber on a separate connection despite - * the use of durable subscriber with no-local on the first connection. - */ - public void testNoLocalSubscriberAndSubscriberOnSeparateConnection() throws Exception - { - Connection noLocalConnection = getConnection(); - Connection connection = getConnection(); - - String noLocalSubId1 = getTestName() + "subId1"; - String subId = getTestName() + "subId2"; - - Session noLocalSession = noLocalConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Topic noLocalTopic = noLocalSession.createTopic(getTestQueueName()); - - Session consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - Topic topic = consumerSession.createTopic(getTestQueueName()); - - TopicSubscriber noLocalSubscriber = null; - TopicSubscriber subscriber = null; - try - { - MessageProducer producer = noLocalSession.createProducer(noLocalTopic); - noLocalSubscriber = noLocalSession.createDurableSubscriber(noLocalTopic, noLocalSubId1, null, true); - subscriber = consumerSession.createDurableSubscriber(topic, subId, null, true); - noLocalConnection.start(); - connection.start(); - - producer.send(createNextMessage(noLocalSession, 1)); - - Message m1 = noLocalSubscriber.receive(NEGATIVE_RECEIVE_TIMEOUT); - assertNull("Subscriber on nolocal connection should not receive message", m1); - - Message m2 = subscriber.receive(NEGATIVE_RECEIVE_TIMEOUT); - assertNotNull("Subscriber on non-nolocal connection should receive message", m2); - } - finally - { - noLocalSession.unsubscribe(noLocalSubId1); - consumerSession.unsubscribe(subId); - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TemporaryTopicTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TemporaryTopicTest.java deleted file mode 100644 index a5b9ce8365..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TemporaryTopicTest.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.topic; - -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.TemporaryTopic; -import javax.jms.TextMessage; - - -/** - * Tests the behaviour of {@link TemporaryTopic}. - */ -public class TemporaryTopicTest extends QpidBrokerTestCase -{ - /** - * Tests the basic publish/subscribe behaviour of a temporary topic. Single - * message is sent to two subscribers. - */ - public void testMessageDeliveryUsingTemporaryTopic() throws Exception - { - final Connection conn = getConnection(); - final Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - final TemporaryTopic topic = session.createTemporaryTopic(); - assertNotNull(topic); - final MessageProducer producer = session.createProducer(topic); - final MessageConsumer consumer1 = session.createConsumer(topic); - final MessageConsumer consumer2 = session.createConsumer(topic); - conn.start(); - producer.send(session.createTextMessage("hello")); - - final TextMessage tm1 = (TextMessage) consumer1.receive(2000); - final TextMessage tm2 = (TextMessage) consumer2.receive(2000); - - assertNotNull("Message not received by subscriber1", tm1); - assertEquals("hello", tm1.getText()); - assertNotNull("Message not received by subscriber2", tm2); - assertEquals("hello", tm2.getText()); - } - - /** - * Tests that the client is able to explicitly delete a temporary topic using - * {@link TemporaryTopic#delete()} and is prevented from deleting one that - * still has consumers. - * - * Note: Under < 0-10 {@link TemporaryTopic#delete()} only marks the queue as deleted - * on the client. 0-10 causes the topic to be deleted from the Broker. - */ - public void testExplictTemporaryTopicDeletion() throws Exception - { - final Connection conn = getConnection(); - - final Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - final TemporaryTopic topic = session.createTemporaryTopic(); - assertNotNull(topic); - final MessageConsumer consumer = session.createConsumer(topic); - conn.start(); - try - { - topic.delete(); - fail("Expected JMSException : should not be able to delete while there are active consumers"); - } - catch (JMSException je) - { - //pass - assertEquals("Temporary Topic has consumers so cannot be deleted", je.getMessage()); - } - - consumer.close(); - - // Now deletion should succeed. - topic.delete(); - - try - { - session.createConsumer(topic); - fail("Exception not thrown"); - } - catch (JMSException je) - { - //pass - assertEquals("Cannot consume from a deleted destination", je.getMessage()); - } - } - - /** - * Tests that a temporary topic cannot be used by another {@link Session}. - */ - public void testUseFromAnotherSessionProhibited() throws Exception - { - final Connection conn = getConnection(); - final Session session1 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - final Session session2 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - final TemporaryTopic topic = session1.createTemporaryTopic(); - - try - { - session2.createConsumer(topic); - fail("Expected a JMSException when subscribing to a temporary topic created on a different session"); - } - catch (JMSException je) - { - // pass - assertEquals("Cannot consume from a temporary destination created on another session", je.getMessage()); - } - } - - /** - * Tests that the client is prohibited from creating a durable subscriber for a temporary - * queue. - */ - public void testDurableSubscriptionProhibited() throws Exception - { - final Connection conn = getConnection(); - - final Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - final TemporaryTopic topic = session.createTemporaryTopic(); - assertNotNull(topic); - try - { - session.createDurableSubscriber(topic, null); - fail("Expected JMSException : should not be able to create durable subscription from temp topic"); - } - catch (JMSException je) - { - //pass - assertEquals("Cannot create a durable subscription with a temporary topic: " + topic.toString(), je.getMessage()); - } - } - - /** - * Tests that a temporary topic remains available for reuse even after its initial - * subscribers have disconnected. - */ - public void testTemporaryTopicReused() throws Exception - { - final Connection conn = getConnection(); - final Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); - final TemporaryTopic topic = session.createTemporaryTopic(); - assertNotNull(topic); - - final MessageProducer producer = session.createProducer(topic); - final MessageConsumer consumer1 = session.createConsumer(topic); - conn.start(); - producer.send(session.createTextMessage("message1")); - TextMessage tm = (TextMessage) consumer1.receive(2000); - assertNotNull("Message not received by first consumer", tm); - assertEquals("message1", tm.getText()); - consumer1.close(); - - final MessageConsumer consumer2 = session.createConsumer(topic); - conn.start(); - producer.send(session.createTextMessage("message2")); - tm = (TextMessage) consumer2.receive(2000); - assertNotNull("Message not received by second consumer", tm); - assertEquals("message2", tm.getText()); - consumer2.close(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicPublisherTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicPublisherTest.java deleted file mode 100644 index 5fbbc7f67f..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicPublisherTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.topic; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.MessageConsumer; -import javax.jms.TextMessage; -import javax.jms.TopicPublisher; -import javax.jms.TopicSession; - -/** - * @author Apache Software Foundation - */ -public class TopicPublisherTest extends QpidBrokerTestCase -{ - protected void setUp() throws Exception - { - super.setUp(); - } - - protected void tearDown() throws Exception - { - super.tearDown(); - } - - public void testUnidentifiedProducer() throws Exception - { - - AMQConnection con = (AMQConnection) getConnection("guest", "guest"); - AMQTopic topic = new AMQTopic(con,"MyTopic"); - TopicSession session1 = con.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE); - TopicPublisher publisher = session1.createPublisher(null); - MessageConsumer consumer1 = session1.createConsumer(topic); - con.start(); - publisher.publish(topic, session1.createTextMessage("Hello")); - TextMessage m = (TextMessage) consumer1.receive(2000); - assertNotNull(m); - try - { - publisher.publish(session1.createTextMessage("Goodbye")); - fail("Did not throw UnsupportedOperationException"); - } - catch (UnsupportedOperationException e) - { - // PASS - } - con.close(); - } - - public static junit.framework.Test suite() - { - return new junit.framework.TestSuite(TopicPublisherTest.class); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java deleted file mode 100644 index c2ea3a5695..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java +++ /dev/null @@ -1,388 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.topic; - -import javax.jms.JMSException; -import javax.naming.NamingException; -import org.apache.qpid.AMQException; -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.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.InvalidDestinationException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.TextMessage; -import javax.jms.Topic; -import javax.jms.TopicPublisher; -import javax.jms.TopicSession; -import javax.jms.TopicSubscriber; -import org.apache.qpid.url.URLSyntaxException; - - -/** @author Apache Software Foundation */ -public class TopicSessionTest extends QpidBrokerTestCase -{ - public void testTopicSubscriptionUnsubscription() throws Exception - { - - AMQConnection con = (AMQConnection) getConnection("guest", "guest"); - AMQTopic topic = new AMQTopic(con.getDefaultTopicExchangeName(), "MyTopic"); - TopicSession session1 = con.createTopicSession(true, AMQSession.NO_ACKNOWLEDGE); - TopicSubscriber sub = session1.createDurableSubscriber(topic, "subscription0"); - TopicPublisher publisher = session1.createPublisher(topic); - - con.start(); - - TextMessage tm = session1.createTextMessage("Hello"); - publisher.publish(tm); - session1.commit(); - - tm = (TextMessage) sub.receive(2000); - assertNotNull(tm); - session1.commit(); - session1.unsubscribe("subscription0"); - - try - { - session1.unsubscribe("not a subscription"); - fail("expected InvalidDestinationException when unsubscribing from unknown subscription"); - } - catch (InvalidDestinationException e) - { - ; // PASS - } - catch (Exception e) - { - fail("expected InvalidDestinationException when unsubscribing from unknown subscription, got: " + e); - } - - con.close(); - } - - public void testSubscriptionNameReuseForDifferentTopicSingleConnection() throws Exception - { - subscriptionNameReuseForDifferentTopic(false); - } - - public void testSubscriptionNameReuseForDifferentTopicTwoConnections() throws Exception - { - subscriptionNameReuseForDifferentTopic(true); - } - - private void subscriptionNameReuseForDifferentTopic(boolean shutdown) throws Exception - { - AMQConnection con = (AMQConnection) getConnection("guest", "guest"); - AMQTopic topic = new AMQTopic(con, "MyTopic1" + String.valueOf(shutdown)); - AMQTopic topic2 = new AMQTopic(con, "MyOtherTopic1" + String.valueOf(shutdown)); - - TopicSession session1 = con.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE); - TopicSubscriber sub = session1.createDurableSubscriber(topic, "subscription0"); - TopicPublisher publisher = session1.createPublisher(null); - - con.start(); - - publisher.publish(topic, session1.createTextMessage("hello")); - session1.commit(); - TextMessage m = (TextMessage) sub.receive(2000); - assertNotNull(m); - session1.commit(); - - if (shutdown) - { - session1.close(); - con.close(); - con = (AMQConnection) getConnection("guest", "guest"); - con.start(); - session1 = con.createTopicSession(true, AMQSession.NO_ACKNOWLEDGE); - publisher = session1.createPublisher(null); - } - sub.close(); - TopicSubscriber sub2 = session1.createDurableSubscriber(topic2, "subscription0"); - publisher.publish(topic, session1.createTextMessage("hello")); - session1.commit(); - if (!shutdown) - { - m = (TextMessage) sub2.receive(2000); - assertNull(m); - session1.commit(); - } - publisher.publish(topic2, session1.createTextMessage("goodbye")); - session1.commit(); - m = (TextMessage) sub2.receive(2000); - assertNotNull(m); - assertEquals("goodbye", m.getText()); - session1.unsubscribe("subscription0"); - con.close(); - } - - public void testUnsubscriptionAfterConnectionClose() throws Exception - { - AMQConnection con1 = (AMQConnection) getClientConnection("guest", "guest", "clientid"); - AMQTopic topic = new AMQTopic(con1, "MyTopic3"); - - TopicSession session1 = con1.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE); - TopicPublisher publisher = session1.createPublisher(topic); - - AMQConnection con2 = (AMQConnection) getClientConnection("guest", "guest", "clientid"); - TopicSession session2 = con2.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE); - TopicSubscriber sub = session2.createDurableSubscriber(topic, "subscription0"); - - con2.start(); - - publisher.publish(session1.createTextMessage("Hello")); - session1.commit(); - TextMessage tm = (TextMessage) sub.receive(2000); - session2.commit(); - assertNotNull(tm); - con2.close(); - publisher.publish(session1.createTextMessage("Hello2")); - session1.commit(); - con2 = (AMQConnection) getClientConnection("guest", "guest", "clientid"); - session2 = con2.createTopicSession(true, AMQSession.NO_ACKNOWLEDGE); - sub = session2.createDurableSubscriber(topic, "subscription0"); - con2.start(); - tm = (TextMessage) sub.receive(2000); - session2.commit(); - assertNotNull(tm); - assertEquals("Hello2", tm.getText()); - session2.unsubscribe("subscription0"); - con1.close(); - con2.close(); - } - - public void testTextMessageCreation() throws Exception - { - - AMQConnection con = (AMQConnection) getConnection("guest", "guest"); - AMQTopic topic = new AMQTopic(con, "MyTopic4"); - TopicSession session1 = con.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE); - TopicPublisher publisher = session1.createPublisher(topic); - MessageConsumer consumer1 = session1.createConsumer(topic); - con.start(); - TextMessage tm = session1.createTextMessage("Hello"); - publisher.publish(tm); - session1.commit(); - tm = (TextMessage) consumer1.receive(10000L); - assertNotNull(tm); - String msgText = tm.getText(); - assertEquals("Hello", msgText); - tm = session1.createTextMessage(); - msgText = tm.getText(); - assertNull(msgText); - publisher.publish(tm); - session1.commit(); - tm = (TextMessage) consumer1.receive(10000L); - assertNotNull(tm); - session1.commit(); - msgText = tm.getText(); - assertNull(msgText); - tm.clearBody(); - tm.setText("Now we are not null"); - publisher.publish(tm); - session1.commit(); - tm = (TextMessage) consumer1.receive(2000); - assertNotNull(tm); - session1.commit(); - msgText = tm.getText(); - assertEquals("Now we are not null", msgText); - - tm = session1.createTextMessage(""); - msgText = tm.getText(); - assertEquals("Empty string not returned", "", msgText); - publisher.publish(tm); - session1.commit(); - tm = (TextMessage) consumer1.receive(2000); - session1.commit(); - assertNotNull(tm); - assertEquals("Empty string not returned", "", msgText); - con.close(); - } - - public void testNoLocal() throws Exception - { - - AMQConnection con = (AMQConnection) getConnection("guest", "guest"); - - AMQTopic topic = new AMQTopic(con, "testNoLocal"); - - noLocalTest(con, topic); - - - con.close(); - } - - - public void testNoLocalDirectExchange() throws Exception - { - - AMQConnection con = (AMQConnection) getConnection("guest", "guest"); - - AMQTopic topic = new AMQTopic("direct://amq.direct/testNoLocal/testNoLocal?routingkey='testNoLocal',exclusive='true',autodelete='true'"); - - noLocalTest(con, topic); - - - con.close(); - } - - - - public void testNoLocalFanoutExchange() throws Exception - { - - AMQConnection con = (AMQConnection) getConnection("guest", "guest"); - - AMQTopic topic = new AMQTopic("fanout://amq.fanout/testNoLocal/testNoLocal?routingkey='testNoLocal',exclusive='true',autodelete='true'"); - - noLocalTest(con, topic); - - con.close(); - } - - - private void noLocalTest(AMQConnection con, AMQTopic topic) - throws JMSException, URLSyntaxException, AMQException, NamingException - { - TopicSession session1 = con.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE); - TopicSubscriber noLocal = session1.createSubscriber(topic, "", true); - - TopicSubscriber select = session1.createSubscriber(topic, "Selector = 'select'", false); - TopicSubscriber normal = session1.createSubscriber(topic); - - - TopicPublisher publisher = session1.createPublisher(topic); - - con.start(); - TextMessage m; - TextMessage message; - - //send message to all consumers - publisher.publish(session1.createTextMessage("hello-new2")); - session1.commit(); - //test normal subscriber gets message - m = (TextMessage) normal.receive(1000); - assertNotNull(m); - session1.commit(); - - //test selector subscriber doesn't message - m = (TextMessage) select.receive(1000); - assertNull(m); - session1.commit(); - - //test nolocal subscriber doesn't message - m = (TextMessage) noLocal.receive(1000); - if (m != null) - { - _logger.info("Message:" + m.getText()); - } - assertNull(m); - - //send message to all consumers - message = session1.createTextMessage("hello2"); - message.setStringProperty("Selector", "select"); - - publisher.publish(message); - session1.commit(); - - //test normal subscriber gets message - m = (TextMessage) normal.receive(1000); - assertNotNull(m); - session1.commit(); - - //test selector subscriber does get message - m = (TextMessage) select.receive(1000); - assertNotNull(m); - session1.commit(); - - //test nolocal subscriber doesn't message - m = (TextMessage) noLocal.receive(100); - assertNull(m); - - AMQConnection con2 = (AMQConnection) getClientConnection("guest", "guest", "foo"); - TopicSession session2 = con2.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE); - TopicPublisher publisher2 = session2.createPublisher(topic); - - - message = session2.createTextMessage("hello2"); - message.setStringProperty("Selector", "select"); - - publisher2.publish(message); - session2.commit(); - - //test normal subscriber gets message - m = (TextMessage) normal.receive(1000); - assertNotNull(m); - session1.commit(); - - //test selector subscriber does get message - m = (TextMessage) select.receive(1000); - assertNotNull(m); - session1.commit(); - - //test nolocal subscriber does message - m = (TextMessage) noLocal.receive(1000); - assertNotNull(m); - con2.close(); - } - - /** - * This tests was added to demonstrate QPID-3542. The Java Client when used with the CPP Broker was failing to - * ack messages received that did not match the selector. This meant the messages remained indefinitely on the Broker. - */ - public void testNonMatchingMessagesHandledCorrectly() throws Exception - { - final String topicName = getName(); - final String clientId = "clientId" + topicName; - final Connection con1 = getConnection(); - final Session session1 = con1.createSession(false, Session.AUTO_ACKNOWLEDGE); - final Topic topic1 = session1.createTopic(topicName); - final AMQQueue internalNameOnBroker = new AMQQueue("amq.topic", "clientid" + ":" + clientId); - - // Setup subscriber with selector - final TopicSubscriber subscriberWithSelector = session1.createDurableSubscriber(topic1, clientId, "Selector = 'select'", false); - final MessageProducer publisher = session1.createProducer(topic1); - - con1.start(); - - // Send non-matching message - final Message sentMessage = session1.createTextMessage("hello"); - sentMessage.setStringProperty("Selector", "nonMatch"); - publisher.send(sentMessage); - - // Try to consume non-message, expect this to fail. - final Message message1 = subscriberWithSelector.receive(1000); - assertNull("should not have received message", message1); - subscriberWithSelector.close(); - - session1.close(); - - // Now verify queue depth on broker. - final Session session2 = con1.createSession(false, Session.AUTO_ACKNOWLEDGE); - final long depth = ((AMQSession) session2).getQueueDepth(internalNameOnBroker); - assertEquals("Expected queue depth of zero", 0, depth); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java deleted file mode 100644 index 4715831de6..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java +++ /dev/null @@ -1,544 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - * - */ -package org.apache.qpid.test.unit.transacted; - -import org.apache.qpid.client.RejectBehaviour; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -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 java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -/** - * This class tests a number of commits and roll back scenarios - * - * Assumptions; - Assumes empty Queue - * - * @see org.apache.qpid.test.client.RollbackOrderTest - */ -public class CommitRollbackTest extends QpidBrokerTestCase -{ - private static final Logger _logger = LoggerFactory.getLogger(CommitRollbackTest.class); - private static final int POSITIVE_TIMEOUT = 2000; - private static final int NEGATIVE_TIMEOUT = 250; - - protected AMQConnection _conn; - private Session _session; - private MessageProducer _publisher; - private Session _pubSession; - private MessageConsumer _consumer; - private Queue _jmsQueue; - - private void newConnection() throws Exception - { - _logger.debug("calling newConnection()"); - _conn = (AMQConnection) getConnection(); - - _session = _conn.createSession(true, Session.SESSION_TRANSACTED); - - final String queueName = getTestQueueName(); - _jmsQueue = _session.createQueue(queueName); - _consumer = _session.createConsumer(_jmsQueue); - - _pubSession = _conn.createSession(true, Session.SESSION_TRANSACTED); - - _publisher = _pubSession.createProducer(_pubSession.createQueue(queueName)); - - _conn.start(); - } - - /** - * PUT a text message, disconnect before commit, confirm it is gone. - * - * @throws Exception On error - */ - public void testPutThenDisconnect() throws Exception - { - newConnection(); - - assertTrue("session is not transacted", _session.getTransacted()); - assertTrue("session is not transacted", _pubSession.getTransacted()); - - _logger.info("sending test message"); - String MESSAGE_TEXT = "testPutThenDisconnect"; - _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); - - _logger.info("reconnecting without commit"); - _conn.close(); - - newConnection(); - - _logger.info("receiving result"); - Message result = _consumer.receive(NEGATIVE_TIMEOUT); - - // commit to ensure message is removed from queue - _session.commit(); - - assertNull("test message was put and disconnected before commit, but is still present", result); - } - - - /** - * PUT a text message, rollback, confirm message is gone. The consumer is on the same connection but different - * session as producer - * - * @throws Exception On error - */ - public void testPutThenRollback() throws Exception - { - newConnection(); - - assertTrue("session is not transacted", _session.getTransacted()); - assertTrue("session is not transacted", _pubSession.getTransacted()); - - _logger.info("sending test message"); - String MESSAGE_TEXT = "testPutThenRollback"; - _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); - - _logger.info("rolling back"); - _pubSession.rollback(); - - _logger.info("receiving result"); - Message result = _consumer.receive(NEGATIVE_TIMEOUT); - - assertNull("test message was put and rolled back, but is still present", result); - } - - /** - * GET a text message, disconnect before commit, confirm it is still there. The consumer is on a new connection - * - * @throws Exception On error - */ - public void testGetThenDisconnect() throws Exception - { - newConnection(); - - assertTrue("session is not transacted", _session.getTransacted()); - assertTrue("session is not transacted", _pubSession.getTransacted()); - - _logger.info("sending test message"); - String MESSAGE_TEXT = "testGetThenDisconnect"; - _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); - - _pubSession.commit(); - - _logger.info("getting test message"); - - Message msg = _consumer.receive(POSITIVE_TIMEOUT); - assertNotNull("retrieved message is null", msg); - - _logger.info("closing connection"); - _conn.close(); - - newConnection(); - - _logger.info("receiving result"); - Message result = _consumer.receive(NEGATIVE_TIMEOUT); - - _session.commit(); - - assertNotNull("test message was consumed and disconnected before commit, but is gone", result); - assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) result).getText()); - } - - /** - * GET a text message, close consumer, disconnect before commit, confirm it is still there. The consumer is on the - * same connection but different session as producer - * - * @throws Exception On error - */ - public void testGetThenCloseDisconnect() throws Exception - { - newConnection(); - - assertTrue("session is not transacted", _session.getTransacted()); - assertTrue("session is not transacted", _pubSession.getTransacted()); - - _logger.info("sending test message"); - String MESSAGE_TEXT = "testGetThenCloseDisconnect"; - _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); - - _pubSession.commit(); - - _logger.info("getting test message"); - - Message msg = _consumer.receive(POSITIVE_TIMEOUT); - assertNotNull("retrieved message is null", msg); - assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) msg).getText()); - - _logger.info("reconnecting without commit"); - _consumer.close(); - _conn.close(); - - newConnection(); - - _logger.info("receiving result"); - Message result = _consumer.receive(POSITIVE_TIMEOUT); - - _session.commit(); - - assertNotNull("test message was consumed and disconnected before commit, but is gone", result); - assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) result).getText()); - } - - /** - * GET a text message, rollback, confirm it is still there. The consumer is on the same connection but differnt - * session to the producer - * - * @throws Exception On error - */ - public void testGetThenRollback() throws Exception - { - newConnection(); - - assertTrue("session is not transacted", _session.getTransacted()); - assertTrue("session is not transacted", _pubSession.getTransacted()); - - _logger.info("sending test message"); - String MESSAGE_TEXT = "testGetThenRollback"; - _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); - - _pubSession.commit(); - - _logger.info("getting test message"); - - Message msg = _consumer.receive(POSITIVE_TIMEOUT); - - assertNotNull("retrieved message is null", msg); - assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) msg).getText()); - - _logger.info("rolling back"); - - _session.rollback(); - - _logger.info("receiving result"); - - Message result = _consumer.receive(POSITIVE_TIMEOUT); - - _session.commit(); - assertNotNull("test message was consumed and rolled back, but is gone", result); - assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) result).getText()); - assertTrue("Message is not marked as redelivered", result.getJMSRedelivered()); - } - - /** - * GET a text message, close message producer, rollback, confirm it is still there. The consumer is on the same - * connection but different session as producer - * - * @throws Exception On error - */ - public void testGetThenCloseRollback() throws Exception - { - newConnection(); - - assertTrue("session is not transacted", _session.getTransacted()); - assertTrue("session is not transacted", _pubSession.getTransacted()); - - _logger.info("sending test message"); - String MESSAGE_TEXT = "testGetThenCloseRollback"; - _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); - - _pubSession.commit(); - - _logger.info("getting test message"); - - Message msg = _consumer.receive(POSITIVE_TIMEOUT); - - assertNotNull("retrieved message is null", msg); - assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) msg).getText()); - - _logger.info("Closing consumer"); - _consumer.close(); - - _logger.info("rolling back"); - _session.rollback(); - - _logger.info("receiving result"); - - _consumer = _session.createConsumer(_jmsQueue); - - Message result = _consumer.receive(POSITIVE_TIMEOUT); - - _session.commit(); - assertNotNull("test message was consumed and rolled back, but is gone", result); - assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) result).getText()); - assertTrue("Message is not marked as redelivered", result.getJMSRedelivered()); - } - - /** - * This test sends two messages receives one of them but doesn't ack it. - * The consumer is then closed - * the first message should be returned as redelivered. - * the second message should be delivered normally. - * @throws Exception - */ - public void testSend2ThenCloseAfter1andTryAgain() throws Exception - { - newConnection(); - - assertTrue("session is not transacted", _session.getTransacted()); - assertTrue("session is not transacted", _pubSession.getTransacted()); - - _logger.info("sending two test messages"); - _publisher.send(_pubSession.createTextMessage("1")); - _publisher.send(_pubSession.createTextMessage("2")); - _pubSession.commit(); - - _logger.info("getting test message"); - Message result = _consumer.receive(POSITIVE_TIMEOUT); - - assertNotNull("Message received should not be null", result); - assertEquals("1", ((TextMessage) result).getText()); - assertTrue("Message is marked as redelivered" + result, !result.getJMSRedelivered()); - - _logger.info("Closing Consumer"); - - _consumer.close(); - - _logger.info("Creating New consumer"); - _consumer = _session.createConsumer(_jmsQueue); - - _logger.info("receiving result"); - - - // Message 2 may be marked as redelivered if it was prefetched. - result = _consumer.receive(POSITIVE_TIMEOUT); - assertNotNull("Second message was not consumed, but is gone", result); - - // The first message back will be 2, message 1 has been received but not committed - // Closing the consumer does not commit the session. - - // if this is message 1 then it should be marked as redelivered - if("1".equals(((TextMessage) result).getText())) - { - fail("First message was received again"); - } - - result = _consumer.receive(NEGATIVE_TIMEOUT); - assertNull("test message should be null:" + result, result); - - _session.commit(); - } - - public void testPutThenRollbackThenGet() throws Exception - { - newConnection(); - - assertTrue("session is not transacted", _session.getTransacted()); - assertTrue("session is not transacted", _pubSession.getTransacted()); - - _logger.info("sending test message"); - String MESSAGE_TEXT = "testPutThenRollbackThenGet"; - - _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); - _pubSession.commit(); - - assertNotNull(_consumer.receive(POSITIVE_TIMEOUT)); - - _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); - - _logger.info("rolling back"); - _pubSession.rollback(); - - _logger.info("receiving result"); - Message result = _consumer.receive(NEGATIVE_TIMEOUT); - assertNull("test message was put and rolled back, but is still present", result); - - _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); - - _pubSession.commit(); - - assertNotNull(_consumer.receive(POSITIVE_TIMEOUT)); - - _session.commit(); - } - - /** - * Qpid-1163 - * Check that when commit is called inside onMessage then - * the last message is nor redelivered. - * - * @throws Exception - */ - public void testCommitWithinOnMessage() throws Exception - { - newConnection(); - - Queue queue = (Queue) getInitialContext().lookup("queue"); - // create a consumer - MessageConsumer cons = _session.createConsumer(queue); - MessageProducer prod = _session.createProducer(queue); - Message message = _session.createTextMessage("Message"); - message.setJMSCorrelationID("m1"); - prod.send(message); - _session.commit(); - _logger.info("Sent message to queue"); - CountDownLatch cd = new CountDownLatch(1); - cons.setMessageListener(new CommitWithinOnMessageListener(cd)); - _conn.start(); - cd.await(30, TimeUnit.SECONDS); - if( cd.getCount() > 0 ) - { - fail("Did not received message"); - } - // Check that the message has been dequeued - _session.close(); - _conn.close(); - _conn = (AMQConnection) getConnection(); - _conn.start(); - Session session = _conn.createSession(false, Session.CLIENT_ACKNOWLEDGE); - cons = session.createConsumer(queue); - message = cons.receiveNoWait(); - if(message != null) - { - if(message.getJMSCorrelationID().equals("m1")) - { - fail("received message twice"); - } - else - { - fail("queue should have been empty, received message: " + message); - } - } - } - - /** - * This test ensures that after exhausting credit (prefetch), a {@link Session#rollback()} successfully - * restores credit and allows the same messages to be re-received. - */ - public void testRollbackSessionAfterCreditExhausted() throws Exception - { - final int maxPrefetch= 5; - - // We send more messages than prefetch size. This ensure that if the 0-10 client were to - // complete the message commands before the rollback command is sent, the broker would - // send additional messages utilising the release credit. This problem would manifest itself - // as an incorrect message (or no message at all) being received at the end of the test. - - final int numMessages = maxPrefetch * 2; - - setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, String.valueOf(maxPrefetch)); - - newConnection(); - - assertEquals("Prefetch not reset", maxPrefetch, ((AMQSession)_session).getDefaultPrefetch()); - - assertTrue("session is not transacted", _session.getTransacted()); - assertTrue("session is not transacted", _pubSession.getTransacted()); - - sendMessage(_pubSession, _publisher.getDestination(), numMessages); - _pubSession.commit(); - - for (int i=0 ;i< maxPrefetch; i++) - { - final Message message = _consumer.receive(POSITIVE_TIMEOUT); - assertNotNull("Received:" + i, message); - assertEquals("Unexpected message received", i, message.getIntProperty(INDEX)); - } - - _logger.info("Rolling back"); - _session.rollback(); - - _logger.info("Receiving messages"); - - Message result = _consumer.receive(POSITIVE_TIMEOUT);; - assertNotNull("Message expected", result); - // Expect the first message - assertEquals("Unexpected message received", 0, result.getIntProperty(INDEX)); - } - - private class CommitWithinOnMessageListener implements MessageListener - { - private CountDownLatch _cd; - private CommitWithinOnMessageListener(CountDownLatch cd) - { - _cd = cd; - } - public void onMessage(Message message) - { - try - { - _logger.info("received message " + message); - assertEquals("Wrong message received", message.getJMSCorrelationID(), "m1"); - _logger.info("commit session"); - _session.commit(); - _cd.countDown(); - } - catch (JMSException e) - { - _logger.error("OnMessage error",e); - } - } - } - - - public void testResendUnseenMessagesAfterRollback() throws Exception - { - resendAfterRollback(); - } - - public void testResendUnseenMessagesAfterRollbackWithServerReject() throws Exception - { - setTestSystemProperty(ClientProperties.REJECT_BEHAVIOUR_PROP_NAME, RejectBehaviour.SERVER.toString()); - resendAfterRollback(); - } - - private void resendAfterRollback() throws Exception - { - newConnection(); - - assertTrue("session is not transacted", _session.getTransacted()); - assertTrue("session is not transacted", _pubSession.getTransacted()); - - _logger.info("sending test message"); - String MESSAGE_TEXT = "message text"; - - _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); - _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); - - _pubSession.commit(); - - assertNotNull("two messages were sent, but none has been received", _consumer.receive(POSITIVE_TIMEOUT)); - - _session.rollback(); - - _logger.info("receiving result"); - - assertNotNull("two messages were sent, but none has been received", _consumer.receive(POSITIVE_TIMEOUT)); - assertNotNull("two messages were sent, but only one has been received", _consumer.receive(POSITIVE_TIMEOUT)); - assertNull("Only two messages were sent, but more have been received", _consumer.receive(NEGATIVE_TIMEOUT)); - - _session.commit(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java deleted file mode 100644 index 78c76602c5..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java +++ /dev/null @@ -1,389 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.transacted; - - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.jms.Session; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.IllegalStateException; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.TextMessage; - -public class TransactedTest extends QpidBrokerTestCase -{ - private AMQQueue queue1; - - private AMQConnection con; - private Session session; - private MessageConsumer consumer1; - private MessageProducer producer2; - - private AMQConnection prepCon; - private Session prepSession; - private MessageProducer prepProducer1; - - private AMQConnection testCon; - private Session testSession; - private MessageConsumer testConsumer1; - private MessageConsumer testConsumer2; - private static final Logger _logger = LoggerFactory.getLogger(TransactedTest.class); - - protected void setUp() throws Exception - { - try - { - super.setUp(); - _logger.info("Create Connection"); - con = (AMQConnection) getConnection("guest", "guest"); - _logger.info("Create Session"); - session = con.createSession(true, Session.SESSION_TRANSACTED); - _logger.info("Create Q1"); - queue1 = new AMQQueue(session.getDefaultQueueExchangeName(), new AMQShortString("Q1"), - new AMQShortString("Q1"), false, true); - _logger.info("Create Q2"); - AMQQueue queue2 = new AMQQueue(session.getDefaultQueueExchangeName(), new AMQShortString("Q2"), false); - - _logger.info("Create Consumer of Q1"); - consumer1 = session.createConsumer(queue1); - // Dummy just to create the queue. - _logger.info("Create Consumer of Q2"); - MessageConsumer consumer2 = session.createConsumer(queue2); - _logger.info("Close Consumer of Q2"); - consumer2.close(); - - _logger.info("Create producer to Q2"); - producer2 = session.createProducer(queue2); - - _logger.info("Start Connection"); - con.start(); - - _logger.info("Create prep connection"); - prepCon = (AMQConnection) getConnection("guest", "guest"); - - _logger.info("Create prep session"); - prepSession = prepCon.createSession(false, AMQSession.AUTO_ACKNOWLEDGE); - - _logger.info("Create prep producer to Q1"); - prepProducer1 = prepSession.createProducer(queue1); - - _logger.info("Create prep connection start"); - prepCon.start(); - - _logger.info("Create test connection"); - testCon = (AMQConnection) getConnection("guest", "guest"); - _logger.info("Create test session"); - testSession = testCon.createSession(false, AMQSession.AUTO_ACKNOWLEDGE); - _logger.info("Create test consumer of q2"); - testConsumer2 = testSession.createConsumer(queue2); - } - catch (Exception e) - { - _logger.error("setup error",e); - stopBroker(); - throw e; - } - } - - protected void tearDown() throws Exception - { - try - { - _logger.info("Close connection"); - con.close(); - _logger.info("Close test connection"); - testCon.close(); - _logger.info("Close prep connection"); - prepCon.close(); - } - catch (Exception e) - { - _logger.error("tear down error",e); - } - finally - { - super.tearDown(); - } - } - - public void testCommit() throws Exception - { - _logger.info("Send prep A"); - prepProducer1.send(prepSession.createTextMessage("A")); - _logger.info("Send prep B"); - prepProducer1.send(prepSession.createTextMessage("B")); - _logger.info("Send prep C"); - prepProducer1.send(prepSession.createTextMessage("C")); - - // send and receive some messages - _logger.info("Send X to Q2"); - producer2.send(session.createTextMessage("X")); - _logger.info("Send Y to Q2"); - producer2.send(session.createTextMessage("Y")); - _logger.info("Send Z to Q2"); - producer2.send(session.createTextMessage("Z")); - - _logger.info("Read A from Q1"); - expect("A", consumer1.receive(1000)); - _logger.info("Read B from Q1"); - expect("B", consumer1.receive(1000)); - _logger.info("Read C from Q1"); - expect("C", consumer1.receive(1000)); - - // commit - _logger.info("session commit"); - session.commit(); - _logger.info("Start test Connection"); - testCon.start(); - - // ensure sent messages can be received and received messages are gone - _logger.info("Read X from Q2"); - expect("X", testConsumer2.receive(1000)); - _logger.info("Read Y from Q2"); - expect("Y", testConsumer2.receive(1000)); - _logger.info("Read Z from Q2"); - expect("Z", testConsumer2.receive(1000)); - - _logger.info("create test session on Q1"); - testConsumer1 = testSession.createConsumer(queue1); - _logger.info("Read null from Q1"); - assertTrue(null == testConsumer1.receive(1000)); - _logger.info("Read null from Q2"); - assertTrue(null == testConsumer2.receive(1000)); - } - - public void testRollback() throws Exception - { - // add some messages - _logger.info("Send prep RB_A"); - prepProducer1.send(prepSession.createTextMessage("RB_A")); - _logger.info("Send prep RB_B"); - prepProducer1.send(prepSession.createTextMessage("RB_B")); - _logger.info("Send prep RB_C"); - prepProducer1.send(prepSession.createTextMessage("RB_C")); - - _logger.info("Sending RB_X RB_Y RB_Z"); - producer2.send(session.createTextMessage("RB_X")); - producer2.send(session.createTextMessage("RB_Y")); - producer2.send(session.createTextMessage("RB_Z")); - _logger.info("Receiving RB_A RB_B"); - expect("RB_A", consumer1.receive(1000)); - expect("RB_B", consumer1.receive(1000)); - // Don't consume 'RB_C' leave it in the prefetch cache to ensure rollback removes it. - // Quick sleep to ensure 'RB_C' gets pre-fetched - Thread.sleep(500); - - // rollback - _logger.info("rollback"); - session.rollback(); - - _logger.info("Receiving RB_A RB_B RB_C"); - // ensure sent messages are not visible and received messages are requeued - expect("RB_A", consumer1.receive(1000), true); - expect("RB_B", consumer1.receive(1000), true); - expect("RB_C", consumer1.receive(1000), isBroker010()?false:true); - _logger.info("Starting new connection"); - testCon.start(); - testConsumer1 = testSession.createConsumer(queue1); - _logger.info("Testing we have no messages left"); - assertTrue(null == testConsumer1.receive(1000)); - assertTrue(null == testConsumer2.receive(1000)); - - session.commit(); - - _logger.info("Testing we have no messages left after commit"); - assertTrue(null == testConsumer1.receive(1000)); - assertTrue(null == testConsumer2.receive(1000)); - } - - public void testResendsMsgsAfterSessionClose() throws Exception - { - AMQConnection con = (AMQConnection) getConnection("guest", "guest"); - - Session consumerSession = con.createSession(true, Session.SESSION_TRANSACTED); - AMQQueue queue3 = new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q3"), false); - MessageConsumer consumer = consumerSession.createConsumer(queue3); - - AMQConnection con2 = (AMQConnection) getConnection("guest", "guest"); - Session producerSession = con2.createSession(true, Session.SESSION_TRANSACTED); - MessageProducer producer = producerSession.createProducer(queue3); - - _logger.info("Sending four messages"); - producer.send(producerSession.createTextMessage("msg1")); - producer.send(producerSession.createTextMessage("msg2")); - producer.send(producerSession.createTextMessage("msg3")); - producer.send(producerSession.createTextMessage("msg4")); - - producerSession.commit(); - - _logger.info("Starting connection"); - con.start(); - TextMessage tm = (TextMessage) consumer.receive(); - assertNotNull(tm); - assertEquals("msg1", tm.getText()); - - consumerSession.commit(); - - _logger.info("Received and committed first message"); - tm = (TextMessage) consumer.receive(1000); - assertNotNull(tm); - assertEquals("msg2", tm.getText()); - - tm = (TextMessage) consumer.receive(1000); - assertNotNull(tm); - assertEquals("msg3", tm.getText()); - - tm = (TextMessage) consumer.receive(1000); - assertNotNull(tm); - assertEquals("msg4", tm.getText()); - - _logger.info("Received all four messages. Closing connection with three outstanding messages"); - - consumerSession.close(); - - consumerSession = con.createSession(true, Session.SESSION_TRANSACTED); - - consumer = consumerSession.createConsumer(queue3); - - // no ack for last three messages so when I call recover I expect to get three messages back - tm = (TextMessage) consumer.receive(3000); - assertNotNull(tm); - assertEquals("msg2", tm.getText()); - assertTrue("Message is not redelivered", tm.getJMSRedelivered()); - - tm = (TextMessage) consumer.receive(3000); - assertNotNull(tm); - assertEquals("msg3", tm.getText()); - assertTrue("Message is not redelivered", tm.getJMSRedelivered()); - - tm = (TextMessage) consumer.receive(3000); - assertNotNull(tm); - assertEquals("msg4", tm.getText()); - assertTrue("Message is not redelivered", tm.getJMSRedelivered()); - - _logger.info("Received redelivery of three messages. Committing"); - - consumerSession.commit(); - - _logger.info("Called commit"); - - tm = (TextMessage) consumer.receive(1000); - assertNull(tm); - - _logger.info("No messages redelivered as is expected"); - - con.close(); - con2.close(); - } - - public void testCommitOnClosedConnection() throws Exception - { - Connection connnection = getConnection(); - javax.jms.Session transactedSession = connnection.createSession(true, Session.SESSION_TRANSACTED); - connnection.close(); - try - { - transactedSession.commit(); - fail("Commit on closed connection should throw IllegalStateException!"); - } - catch(IllegalStateException e) - { - // passed - } - } - - public void testCommitOnClosedSession() throws Exception - { - Connection connnection = getConnection(); - javax.jms.Session transactedSession = connnection.createSession(true, Session.SESSION_TRANSACTED); - transactedSession.close(); - try - { - transactedSession.commit(); - fail("Commit on closed session should throw IllegalStateException!"); - } - catch(IllegalStateException e) - { - // passed - } - } - - public void testRollbackOnClosedSession() throws Exception - { - Connection connnection = getConnection(); - javax.jms.Session transactedSession = connnection.createSession(true, Session.SESSION_TRANSACTED); - transactedSession.close(); - try - { - transactedSession.rollback(); - fail("Rollback on closed session should throw IllegalStateException!"); - } - catch(IllegalStateException e) - { - // passed - } - } - - public void testGetTransactedOnClosedSession() throws Exception - { - Connection connnection = getConnection(); - javax.jms.Session transactedSession = connnection.createSession(true, Session.SESSION_TRANSACTED); - transactedSession.close(); - try - { - transactedSession.getTransacted(); - fail("According to Sun TCK invocation of Session#getTransacted on closed session should throw IllegalStateException!"); - } - catch(IllegalStateException e) - { - // passed - } - } - - private void expect(String text, Message msg) throws JMSException - { - expect(text, msg, false); - } - - private void expect(String text, Message msg, boolean requeued) throws JMSException - { - assertNotNull("Message should not be null", msg); - assertTrue("Message should be a text message", msg instanceof TextMessage); - assertEquals("Message content does not match expected", text, ((TextMessage) msg).getText()); - assertEquals("Message should " + (requeued ? "" : "not") + " be requeued", requeued, msg.getJMSRedelivered()); - } - - public static junit.framework.Test suite() - { - return new junit.framework.TestSuite(TransactedTest.class); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutDisabledTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutDisabledTest.java deleted file mode 100644 index e37c6cf54b..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutDisabledTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.transacted; - -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -/** - * This verifies that the default behaviour is not to time out transactions. - */ -public class TransactionTimeoutDisabledTest extends TransactionTimeoutTestCase -{ - @Override - protected void configure() throws Exception - { - // Setup housekeeping every second - TestBrokerConfiguration brokerConfiguration = getBrokerConfiguration(); - setTestSystemProperty("virtualhost.housekeepingCheckPeriod", "100"); - - // No transaction timeout configuration. - } - - public void testProducerIdleCommit() throws Exception - { - try - { - send(5, 0); - - sleep(2.0f); - - _psession.commit(); - } - catch (Exception e) - { - fail("Should have succeeded"); - } - - assertEquals("Listener should not have received exception", 0, getNumberOfDeliveredExceptions()); - - monitor(0, 0); - } - - public void testProducerOpenCommit() throws Exception - { - try - { - send(5, 0.3f); - - _psession.commit(); - } - catch (Exception e) - { - fail("Should have succeeded"); - } - - assertEquals("Listener should not have received exception", 0, getNumberOfDeliveredExceptions()); - - monitor(0, 0); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTest.java deleted file mode 100644 index b84e03972d..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTest.java +++ /dev/null @@ -1,350 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.transacted; - -import javax.jms.DeliveryMode; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageProducer; -import javax.jms.Queue; - -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -/** - * This tests the behaviour of transactional sessions when the {@code transactionTimeout} configuration - * is set for a virtual host. - * - * A producer that is idle for too long or open for too long will have its connection/session(0-10) closed and - * any further operations will fail with a 408 resource timeout exception. Consumers will not - * be affected by the transaction timeout configuration. - */ -public class TransactionTimeoutTest extends TransactionTimeoutTestCase -{ - - protected void configure() throws Exception - { - // switch off connection close in order to test timeout on publishing of unroutable messages - getBrokerConfiguration().setBrokerAttribute(Broker.CONNECTION_CLOSE_WHEN_NO_ROUTE, false); - - // Setup housekeeping every 100ms - TestBrokerConfiguration brokerConfiguration = getBrokerConfiguration(); - setTestSystemProperty("virtualhost.housekeepingCheckPeriod","100"); - - if (getName().contains("ProducerIdle")) - { - setTestSystemProperty("virtualhost.storeTransactionOpenTimeoutWarn", "0"); - setTestSystemProperty("virtualhost.storeTransactionOpenTimeoutClose", "0"); - setTestSystemProperty("virtualhost.storeTransactionIdleTimeoutWarn", "500"); - setTestSystemProperty("virtualhost.storeTransactionIdleTimeoutClose", "1500"); - } - else if (getName().contains("ProducerOpen")) - { - setTestSystemProperty("virtualhost.storeTransactionOpenTimeoutWarn", "1000"); - setTestSystemProperty("virtualhost.storeTransactionOpenTimeoutClose", "2000"); - setTestSystemProperty("virtualhost.storeTransactionIdleTimeoutWarn", "0"); - setTestSystemProperty("virtualhost.storeTransactionIdleTimeoutClose", "0"); - } - else - { - setTestSystemProperty("virtualhost.storeTransactionOpenTimeoutWarn", "1000"); - setTestSystemProperty("virtualhost.storeTransactionOpenTimeoutClose", "2000"); - setTestSystemProperty("virtualhost.storeTransactionIdleTimeoutWarn", "500"); - setTestSystemProperty("virtualhost.storeTransactionIdleTimeoutClose", "1500"); - } - } - - public void testProducerIdle() throws Exception - { - sleep(2.0f); - - _psession.commit(); - - assertEquals("Listener should not have received exception", 0, getNumberOfDeliveredExceptions()); - - monitor(0, 0); - } - - public void testProducerIdleCommit() throws Exception - { - send(5, 0); - // Idle for more than idleClose to generate idle-warns and cause a close. - sleep(2.0f); - - try - { - _psession.commit(); - fail("Exception not thrown"); - } - catch (Exception e) - { - _exception = e; - } - - monitor(10, 0); - - check(IDLE); - } - - public void testProducerIdleCommitTwice() throws Exception - { - send(5, 0); - // Idle for less than idleClose to generate idle-warns - sleep(1.0f); - - _psession.commit(); - - send(5, 0); - // Now idle for more than idleClose to generate more idle-warns and cause a close. - sleep(2.0f); - - try - { - _psession.commit(); - fail("Exception not thrown"); - } - catch (Exception e) - { - _exception = e; - } - - monitor(15, 0); - - check(IDLE); - } - - public void testProducerIdleRollback() throws Exception - { - send(5, 0); - // Now idle for more than idleClose to generate more idle-warns and cause a close. - sleep(2.0f); - try - { - _psession.rollback(); - fail("Exception not thrown"); - } - catch (Exception e) - { - _exception = e; - } - - monitor(10, 0); - - check(IDLE); - } - - public void testProducerIdleRollbackTwice() throws Exception - { - send(5, 0); - // Idle for less than idleClose to generate idle-warns - sleep(1.0f); - _psession.rollback(); - send(5, 0); - // Now idle for more than idleClose to generate more idle-warns and cause a close. - sleep(2.0f); - try - { - _psession.rollback(); - fail("should fail"); - } - catch (Exception e) - { - _exception = e; - } - - monitor(15, 0); - - check(IDLE); - } - - public void testProducerOpenCommit() throws Exception - { - try - { - // Sleep between sends to cause open warns and then cause a close. - send(6, 0.5f); - _psession.commit(); - fail("Exception not thrown"); - } - catch (Exception e) - { - _exception = e; - } - - monitor(0, 10); - - check(OPEN); - } - - public void testProducerOpenCommitTwice() throws Exception - { - send(5, 0); - sleep(1.0f); - _psession.commit(); - - try - { - // Now sleep between sends to cause open warns and then cause a close. - send(6, 0.5f); - _psession.commit(); - fail("Exception not thrown"); - } - catch (Exception e) - { - _exception = e; - } - - monitor(0, 10); - - check(OPEN); - } - - public void testConsumerCommitClose() throws Exception - { - send(1, 0); - - _psession.commit(); - - expect(1, 0); - - _csession.commit(); - - sleep(3.0f); - - _csession.close(); - - assertEquals("Listener should not have received exception", 0, getNumberOfDeliveredExceptions()); - - monitor(0, 0); - } - - public void testConsumerIdleReceiveCommit() throws Exception - { - send(1, 0); - - _psession.commit(); - - sleep(2.0f); - - expect(1, 0); - - sleep(2.0f); - - _csession.commit(); - - assertEquals("Listener should not have received exception", 0, getNumberOfDeliveredExceptions()); - - monitor(0, 0); - } - - public void testConsumerIdleCommit() throws Exception - { - send(1, 0); - - _psession.commit(); - - expect(1, 0); - - sleep(2.0f); - - _csession.commit(); - - assertEquals("Listener should not have received exception", 0, getNumberOfDeliveredExceptions()); - - monitor(0, 0); - } - - public void testConsumerIdleRollback() throws Exception - { - send(1, 0); - - _psession.commit(); - - expect(1, 0); - - sleep(2.0f); - - _csession.rollback(); - - assertEquals("Listener should not have received exception", 0, getNumberOfDeliveredExceptions()); - - monitor(0, 0); - } - - public void testConsumerOpenCommit() throws Exception - { - send(1, 0); - - _psession.commit(); - - sleep(3.0f); - - _csession.commit(); - - assertEquals("Listener should not have received exception", 0, getNumberOfDeliveredExceptions()); - - monitor(0, 0); - } - - public void testConsumerOpenRollback() throws Exception - { - send(1, 0); - - _psession.commit(); - - sleep(3.0f); - - _csession.rollback(); - - assertEquals("Listener should not have received exception", 0, getNumberOfDeliveredExceptions()); - - monitor(0, 0); - } - - /** - * Tests that sending an unroutable persistent message does not result in a long running store transaction [warning]. - */ - public void testTransactionCommittedOnNonRoutableQueuePersistentMessage() throws Exception - { - checkTransactionCommittedOnNonRoutableQueueMessage(DeliveryMode.PERSISTENT); - } - - /** - * Tests that sending an unroutable transient message does not result in a long running store transaction [warning]. - */ - public void testTransactionCommittedOnNonRoutableQueueTransientMessage() throws Exception - { - checkTransactionCommittedOnNonRoutableQueueMessage(DeliveryMode.NON_PERSISTENT); - } - - private void checkTransactionCommittedOnNonRoutableQueueMessage(int deliveryMode) throws JMSException, Exception - { - Queue nonExisting = _psession.createQueue(getTestQueueName() + System.currentTimeMillis()); - MessageProducer producer = _psession.createProducer(nonExisting); - Message message = _psession.createMessage(); - producer.send(message, deliveryMode, Message.DEFAULT_PRIORITY, Message.DEFAULT_TIME_TO_LIVE); - _psession.commit(); - - // give time to house keeping thread to log messages - sleep(3f); - monitor(0, 0); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTestCase.java deleted file mode 100644 index 98fe29f826..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTestCase.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.transacted; - -import junit.framework.TestCase; - -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.util.LogMonitor; - -import javax.jms.Connection; -import javax.jms.DeliveryMode; -import javax.jms.ExceptionListener; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.Session; -import javax.jms.TextMessage; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * The {@link TestCase} for transaction timeout testing. - */ -public abstract class TransactionTimeoutTestCase extends QpidBrokerTestCase implements ExceptionListener -{ - private static final int ALERT_MESSAGE_TOLERANCE = 6; - public static final String VIRTUALHOST = "test"; - public static final String TEXT = "0123456789abcdefghiforgettherest"; - public static final String CHN_OPEN_TXN = "CHN-1007"; - public static final String CHN_IDLE_TXN = "CHN-1008"; - public static final String IDLE = "Idle"; - public static final String OPEN = "Open"; - - protected LogMonitor _monitor; - protected Connection _con; - protected Session _psession, _csession; - protected Queue _queue; - protected MessageConsumer _consumer; - protected MessageProducer _producer; - protected Exception _exception; - - private final CountDownLatch _exceptionListenerLatch = new CountDownLatch(1); - private final AtomicInteger _exceptionCount = new AtomicInteger(0); - private volatile AMQConstant _linkedExceptionCode; - private volatile String _linkedExceptionMessage; - - /** - * Subclasses must implement this to configure transaction timeout parameters. - */ - protected abstract void configure() throws Exception; - - @Override - protected void setUp() throws Exception - { - // Configure timeouts - configure(); - - // Monitor log file - _monitor = new LogMonitor(_outputFile); - - // Start broker - super.setUp(); - - // Connect to broker - setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, String.valueOf(1)); - _con = getConnection(); - _con.setExceptionListener(this); - _con.start(); - - // Create queue - Session qsession = _con.createSession(true, Session.SESSION_TRANSACTED); - _queue = qsession.createQueue(getTestQueueName()); - qsession.close(); - - // Create producer and consumer - producer(); - consumer(); - } - - /** - * Create a transacted persistent message producer session. - */ - protected void producer() throws Exception - { - _psession = _con.createSession(true, Session.SESSION_TRANSACTED); - _producer = _psession.createProducer(_queue); - _producer.setDeliveryMode(DeliveryMode.PERSISTENT); - } - - /** - * Create a transacted message consumer session. - */ - protected void consumer() throws Exception - { - _csession = _con.createSession(true, Session.SESSION_TRANSACTED); - _consumer = _csession.createConsumer(_queue); - } - - /** - * Send a number of messages to the queue, optionally pausing after each. - * - * Need to sync to ensure that the Broker has received the message(s) in order - * the test and broker start timing the idle transaction from the same point in time. - */ - protected void send(int count, float delay) throws Exception - { - for (int i = 0; i < count; i++) - { - sleep(delay); - Message msg = _psession.createTextMessage(TEXT); - msg.setIntProperty("i", i); - _producer.send(msg); - } - - ((AMQSession)_psession).sync(); - } - - /** - * Sleep for a number of seconds. - */ - protected void sleep(float seconds) throws Exception - { - try - { - Thread.sleep((long) (seconds * 1000.0f)); - } - catch (InterruptedException ie) - { - throw new RuntimeException("Interrupted"); - } - } - - /** - * Check for idle and open messages. - * - * Either exactly zero messages, or +-2 error accepted around the specified number. - */ - protected void monitor(int idle, int open) throws Exception - { - List idleMsgs = _monitor.findMatches(CHN_IDLE_TXN); - List openMsgs = _monitor.findMatches(CHN_OPEN_TXN); - - String idleErr = "Expected " + idle + " but found " + idleMsgs.size() + " txn idle messages"; - String openErr = "Expected " + open + " but found " + openMsgs.size() + " txn open messages"; - - if (idle == 0) - { - assertTrue(idleErr, idleMsgs.isEmpty()); - } - else - { - assertTrue(idleErr, idleMsgs.size() >= idle - ALERT_MESSAGE_TOLERANCE && idleMsgs.size() <= idle + ALERT_MESSAGE_TOLERANCE); - } - - if (open == 0) - { - assertTrue(openErr, openMsgs.isEmpty()); - } - else - { - assertTrue(openErr, openMsgs.size() >= open - ALERT_MESSAGE_TOLERANCE && openMsgs.size() <= open + ALERT_MESSAGE_TOLERANCE); - } - } - - /** - * Receive a number of messages, optionally pausing after each. - */ - protected void expect(int count, float delay) throws Exception - { - for (int i = 0; i < count; i++) - { - sleep(delay); - Message msg = _consumer.receive(1000); - assertNotNull("Message should not be null", msg); - assertTrue("Message should be a text message", msg instanceof TextMessage); - assertEquals("Message content does not match expected", TEXT, ((TextMessage) msg).getText()); - assertEquals("Message order is incorrect", i, msg.getIntProperty("i")); - } - } - - /** - * Checks that the correct exception was thrown and was received - * by the listener with a 506 error code. - */ - protected void check(String reason) throws InterruptedException - { - assertNotNull("Should have thrown exception to client", _exception); - - assertTrue("Should have caught exception in listener", _exceptionListenerLatch.await(1, TimeUnit.SECONDS)); - assertNotNull("Linked exception message should not be null", _linkedExceptionMessage); - assertTrue("Linked exception message '" + _linkedExceptionMessage + "' should contain '" + reason + "'", - _linkedExceptionMessage.contains(reason + " transaction timed out")); - assertNotNull("Linked exception should have an error code", _linkedExceptionCode); - assertEquals("Linked exception error code should be 506", AMQConstant.RESOURCE_ERROR, _linkedExceptionCode); - } - - /** @see javax.jms.ExceptionListener#onException(javax.jms.JMSException) */ - @Override - public void onException(JMSException jmse) - { - if (jmse.getLinkedException() != null) - { - _linkedExceptionMessage = jmse.getLinkedException().getMessage(); - } - - if (jmse.getLinkedException() instanceof AMQException) - { - _linkedExceptionCode = ((AMQException) jmse.getLinkedException()).getErrorCode(); - } - _exceptionCount.incrementAndGet(); - _exceptionListenerLatch.countDown(); - } - - protected int getNumberOfDeliveredExceptions() - { - return _exceptionCount.get(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/AbstractXATestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/AbstractXATestCase.java deleted file mode 100644 index 92df1bd331..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/AbstractXATestCase.java +++ /dev/null @@ -1,138 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.test.unit.xa; - -import org.apache.qpid.dtx.XidImpl; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.DeliveryMode; -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.TextMessage; -import javax.jms.XASession; -import javax.transaction.xa.XAResource; -import javax.transaction.xa.Xid; -import java.util.Random; - -/** - * - * - */ -public abstract class AbstractXATestCase extends QpidBrokerTestCase -{ - protected static final String _sequenceNumberPropertyName = "seqNumber"; - - /** - * the xaResource associated with the standard session - */ - protected static XAResource _xaResource = null; - - /** - * producer registered with the standard session - */ - protected static MessageProducer _producer = null; - - /** - * consumer registered with the standard session - */ - protected static MessageConsumer _consumer = null; - - /** - * a standard message - */ - protected static TextMessage _message = null; - - /** - * xid counter - */ - private static int _xidCounter = (new Random()).nextInt(1000000); - - - protected void setUp() throws Exception - { - super.setUp(); - init(); - } - - public abstract void init() throws Exception; - - - - /** - * construct a new Xid - * - * @return a new Xid - */ - protected Xid getNewXid() - { - byte[] branchQualifier; - byte[] globalTransactionID; - int format = _xidCounter; - String branchQualifierSt = "branchQualifier" + _xidCounter; - String globalTransactionIDSt = "globalTransactionID" + _xidCounter; - branchQualifier = branchQualifierSt.getBytes(); - globalTransactionID = globalTransactionIDSt.getBytes(); - _xidCounter++; - return new XidImpl(branchQualifier, format, globalTransactionID); - } - - public void init(XASession session, Destination destination) - { - // get the xaResource - try - { - _xaResource = session.getXAResource(); - } - catch (Exception e) - { - fail("cannot access the xa resource: " + e.getMessage()); - } - // create standard producer - try - { - _producer = session.createProducer(destination); - _producer.setDeliveryMode(DeliveryMode.PERSISTENT); - } - catch (JMSException e) - { - _logger.error("Producer error",e); - fail("cannot create message producer: " + e.getMessage()); - } - // create standard consumer - try - { - _consumer = session.createConsumer(destination); - } - catch (JMSException e) - { - fail("cannot create message consumer: " + e.getMessage()); - } - // create a standard message - try - { - _message = session.createTextMessage(); - _message.setText("test XA"); - } - catch (JMSException e) - { - fail("cannot create standard message: " + e.getMessage()); - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/FaultTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/FaultTest.java deleted file mode 100644 index c5fa217aa9..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/FaultTest.java +++ /dev/null @@ -1,414 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.unit.xa; - - -import junit.framework.TestSuite; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.jms.Queue; -import javax.jms.QueueConnection; -import javax.jms.QueueSession; -import javax.jms.Session; -import javax.jms.XAQueueConnection; -import javax.jms.XAQueueConnectionFactory; -import javax.jms.XAQueueSession; -import javax.transaction.xa.XAException; -import javax.transaction.xa.XAResource; -import javax.transaction.xa.Xid; - - -public class FaultTest extends AbstractXATestCase -{ - private static final Logger _logger = LoggerFactory.getLogger(FaultTest.class); - - /** - * the queue use by all the tests - */ - private static Queue _queue = null; - /** - * the queue connection factory used by all tests - */ - private static XAQueueConnectionFactory _queueFactory = null; - - /** - * standard xa queue connection - */ - private static XAQueueConnection _xaqueueConnection = null; - - /** - * standard xa queue connection - */ - private static QueueConnection _queueConnection = null; - - - /** - * standard queue session created from the standard connection - */ - private static QueueSession _nonXASession = null; - - /** - * the queue name - */ - private static final String QUEUENAME = "xaQueue"; - - /** ----------------------------------------------------------------------------------- **/ - /** - * ----------------------------- JUnit support ----------------------------------------- * - */ - - /** - * Gets the test suite tests - * - * @return the test suite tests - */ - public static TestSuite getSuite() - { - return new TestSuite(QueueTest.class); - } - - /** - * Run the test suite. - * - * @param args Any command line arguments specified to this class. - */ - public static void main(String args[]) - { - junit.textui.TestRunner.run(getSuite()); - } - - public void tearDown() throws Exception - { - if (!isBroker08()) - { - _xaqueueConnection.close(); - _queueConnection.close(); - } - super.tearDown(); - } - - /** - * Initialize standard actors - */ - public void init() throws Exception - { - if (!isBroker08()) - { - _queue = (Queue) getInitialContext().lookup(QUEUENAME); - _queueFactory = getConnectionFactory(); - _xaqueueConnection = _queueFactory.createXAQueueConnection("guest", "guest"); - XAQueueSession session = _xaqueueConnection.createXAQueueSession(); - _queueConnection = _queueFactory.createQueueConnection("guest","guest"); - _nonXASession = _queueConnection.createQueueSession(true, Session.AUTO_ACKNOWLEDGE); - init(session, _queue); - } - } - - /** -------------------------------------------------------------------------------------- **/ - /** ----------------------------- Test Suite -------------------------------------------- **/ - /** -------------------------------------------------------------------------------------- **/ - - /** - * Strategy: - * Invoke start twice with the same xid on an XA resource. - * Check that the second - * invocation is throwing the expected XA exception. - */ - public void testSameXID() throws Exception - { - Xid xid = getNewXid(); - _xaResource.start(xid, XAResource.TMNOFLAGS); - // we now exepct this operation to fail - try - { - _xaResource.start(xid, XAResource.TMNOFLAGS); - fail("We managed to start a transaction with the same xid"); - } - catch (XAException e) - { - assertEquals("Wrong error code: ", XAException.XAER_DUPID, e.errorCode); - } - } - - /** - * Strategy: - * Invoke start on a XA resource with flag other than TMNOFLAGS, TMJOIN, or TMRESUME. - * Check that a XA Exception is thrown. - */ - public void testWrongStartFlag() - { - Xid xid = getNewXid(); - try - { - _xaResource.start(xid, XAResource.TMONEPHASE); - fail("We managed to start a transaction with a wrong flag"); - } - catch (XAException e) - { - assertEquals("Wrong error code: ", XAException.XAER_INVAL, e.errorCode); - } - } - - /** - * Strategy: - * Check that a XA exception is thrown when: - * A non started xid is ended - */ - public void testEnd() - { - Xid xid = getNewXid(); - try - { - _xaResource.end(xid, XAResource.TMSUCCESS); - fail("We managed to end a transaction before it is started"); - } - catch (XAException e) - { - assertEquals("Wrong error code: ", XAException.XAER_PROTO, e.errorCode); - } - } - - - /** - * Strategy: - * Check that a XA exception is thrown when: - * Call forget on an unknown xid - * call forget on a started xid - * A non started xid is prepared - * A non ended xis is prepared - */ - public void testForget() - { - Xid xid = getNewXid(); - try - { - _xaResource.forget(xid); - fail("We managed to forget an unknown xid"); - } - catch (XAException e) - { - // assertEquals("Wrong error code: ", XAException.XAER_NOTA, e.errorCode); - } - xid = getNewXid(); - try - { - _xaResource.start(xid, XAResource.TMNOFLAGS); - _xaResource.forget(xid); - fail("We managed to forget a started xid"); - } - catch (XAException e) - { - assertEquals("Wrong error code: ", XAException.XAER_PROTO, e.errorCode); - } - } - - /** - * Strategy: - * Check that a XA exception is thrown when: - * A non started xid is prepared - * A non ended xid is prepared - */ - public void testPrepare() - { - Xid xid = getNewXid(); - try - { - _xaResource.prepare(xid); - fail("We managed to prepare an unknown xid"); - } - catch (XAException e) - { - assertEquals("Wrong error code: ", XAException.XAER_NOTA, e.errorCode); - } - xid = getNewXid(); - try - { - _xaResource.start(xid, XAResource.TMNOFLAGS); - _xaResource.prepare(xid); - fail("We managed to prepare a started xid"); - } - catch (XAException e) - { - assertEquals("Wrong error code: ", XAException.XAER_PROTO, e.errorCode); - } - } - - /** - * Strategy: - * Check that the expected XA exception is thrown when: - * A non started xid is committed - * A non ended xid is committed - * A non prepared xid is committed with one phase set to false. - * A prepared xid is committed with one phase set to true. - */ - public void testCommit() throws Exception - { - Xid xid = getNewXid(); - try - { - _xaResource.commit(xid, true); - fail("We managed to commit an unknown xid"); - } - catch (XAException e) - { - assertEquals("Wrong error code: ", XAException.XAER_NOTA, e.errorCode); - } - xid = getNewXid(); - try - { - _xaResource.start(xid, XAResource.TMNOFLAGS); - _xaResource.commit(xid, true); - fail("We managed to commit a not ended xid"); - } - catch (XAException e) - { - assertEquals("Wrong error code: ", XAException.XAER_PROTO, e.errorCode); - } - xid = getNewXid(); - try - { - _xaResource.start(xid, XAResource.TMNOFLAGS); - _xaResource.end(xid, XAResource.TMSUCCESS); - _xaResource.commit(xid, false); - fail("We managed to commit a not prepared xid"); - } - catch (XAException e) - { - assertEquals("Wrong error code: ", XAException.XAER_PROTO, e.errorCode); - } - xid = getNewXid(); - try - { - _xaResource.start(xid, XAResource.TMNOFLAGS); - _xaResource.end(xid, XAResource.TMSUCCESS); - _xaResource.prepare(xid); - _xaResource.commit(xid, true); - fail("We managed to commit a prepared xid"); - } - catch (XAException e) - { - assertEquals("Wrong error code: ", XAException.XAER_PROTO, e.errorCode); - } - finally - { - _xaResource.commit(xid, false); - } - } - - /** - * Strategy: - * Check that the expected XA exception is thrown when: - * A non started xid is rolled back - * A non ended xid is rolled back - */ - public void testRollback() - { - Xid xid = getNewXid(); - try - { - _xaResource.rollback(xid); - fail("We managed to rollback an unknown xid"); - } - catch (XAException e) - { - assertEquals("Wrong error code: ", XAException.XAER_NOTA, e.errorCode); - } - xid = getNewXid(); - try - { - _xaResource.start(xid, XAResource.TMNOFLAGS); - _xaResource.rollback(xid); - fail("We managed to rollback a not ended xid"); - } - catch (XAException e) - { - assertEquals("Wrong error code: ", XAException.XAER_PROTO, e.errorCode); - } - } - - /** - * Strategy: - * Check that the timeout is set correctly - */ - public void testTransactionTimeoutvalue() throws Exception - { - Xid xid = getNewXid(); - _xaResource.start(xid, XAResource.TMNOFLAGS); - assertEquals("Wrong timeout", _xaResource.getTransactionTimeout(), 0); - _xaResource.setTransactionTimeout(1000); - assertEquals("Wrong timeout", _xaResource.getTransactionTimeout(), 1000); - _xaResource.end(xid, XAResource.TMSUCCESS); - xid = getNewXid(); - _xaResource.start(xid, XAResource.TMNOFLAGS); - assertEquals("Wrong timeout", _xaResource.getTransactionTimeout(), 1000); - } - - /** - * Strategy: - * Check that a transaction timeout as expected - * - set timeout to 1s - * - sleep 1500ms - * - call end and check that the expected exception is thrown - */ - public void testTransactionTimeout() throws Exception - { - _xaResource.setTransactionTimeout(1); - - Xid xid = getNewXid(); - try - { - _xaResource.start(xid, XAResource.TMNOFLAGS); - Thread.sleep(1500); - _xaResource.end(xid, XAResource.TMSUCCESS); - fail("Timeout expected "); - } - catch (XAException e) - { - assertEquals("Wrong error code: ", XAException.XA_RBTIMEOUT, e.errorCode); - } - } - - /** - * Strategy: - * Set the transaction timeout to 1000 - */ - public void testTransactionTimeoutAfterCommit() throws Exception - { - Xid xid = getNewXid(); - - _xaResource.start(xid, XAResource.TMNOFLAGS); - _xaResource.setTransactionTimeout(1000); - assertEquals("Wrong timeout", 1000,_xaResource.getTransactionTimeout()); - - //_xaResource.prepare(xid); - _xaResource.end(xid, XAResource.TMSUCCESS); - _xaResource.commit(xid, true); - - _xaResource.setTransactionTimeout(2000); - assertEquals("Wrong timeout", 2000,_xaResource.getTransactionTimeout()); - - xid = getNewXid(); - _xaResource.start(xid, XAResource.TMNOFLAGS); - assertEquals("Wrong timeout", 2000, _xaResource.getTransactionTimeout()); - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/QueueTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/QueueTest.java deleted file mode 100644 index 350781e970..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/QueueTest.java +++ /dev/null @@ -1,669 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.test.unit.xa; - -import junit.framework.TestSuite; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.jms.DeliveryMode; -import javax.jms.JMSException; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.QueueConnection; -import javax.jms.QueueSession; -import javax.jms.Session; -import javax.jms.TextMessage; -import javax.jms.XAQueueConnection; -import javax.jms.XAQueueConnectionFactory; -import javax.jms.XAQueueSession; -import javax.transaction.xa.XAException; -import javax.transaction.xa.XAResource; -import javax.transaction.xa.Xid; - -public class QueueTest extends AbstractXATestCase -{ - private static final Logger _logger = LoggerFactory.getLogger(QueueTest.class); - - /** - * the queue use by all the tests - */ - private static Queue _queue = null; - /** - * the queue connection factory used by all tests - */ - private static XAQueueConnectionFactory _queueFactory = null; - - /** - * standard xa queue connection - */ - private static XAQueueConnection _xaqueueConnection= null; - - /** - * standard xa queue connection - */ - private static QueueConnection _queueConnection=null; - - - /** - * standard queue session created from the standard connection - */ - private static QueueSession _nonXASession = null; - - /** - * the queue name - */ - private static final String QUEUENAME = "xaQueue"; - - /** ----------------------------------------------------------------------------------- **/ - /** - * ----------------------------- JUnit support ----------------------------------------- * - */ - - /** - * Gets the test suite tests - * - * @return the test suite tests - */ - public static TestSuite getSuite() - { - return new TestSuite(QueueTest.class); - } - - /** - * Run the test suite. - * - * @param args Any command line arguments specified to this class. - */ - public static void main(String args[]) - { - junit.textui.TestRunner.run(getSuite()); - } - - public void tearDown() throws Exception - { - if (!isBroker08()) - { - try - { - _xaqueueConnection.close(); - _queueConnection.close(); - } - catch (Exception e) - { - fail("Exception thrown when cleaning standard connection: " + e.getStackTrace()); - } - } - super.tearDown(); - } - - /** - * Initialize standard actors - */ - public void init() - { - if (!isBroker08()) - { - // lookup test queue - try - { - _queue = (Queue) getInitialContext().lookup(QUEUENAME); - } - catch (Exception e) - { - fail("cannot lookup test queue " + e.getMessage()); - } - - // lookup connection factory - try - { - _queueFactory = getConnectionFactory(); - } - catch (Exception e) - { - fail("enable to lookup connection factory "); - } - // create standard connection - try - { - _xaqueueConnection= getNewQueueXAConnection(); - } - catch (JMSException e) - { - fail("cannot create queue connection: " + e.getMessage()); - } - // create xa session - XAQueueSession session = null; - try - { - session = _xaqueueConnection.createXAQueueSession(); - } - catch (JMSException e) - { - fail("cannot create queue session: " + e.getMessage()); - } - // create a standard session - try - { - _queueConnection = _queueFactory.createQueueConnection("guest", "guest"); - _nonXASession = _queueConnection.createQueueSession(true, Session.AUTO_ACKNOWLEDGE); - } - catch (JMSException e) - { - _logger.error("cannot create queue session",e); - fail("cannot create queue session: " + e.getMessage()); - } - init(session, _queue); - } - } - - /** -------------------------------------------------------------------------------------- **/ - /** ----------------------------- Test Suite -------------------------------------------- **/ - /** -------------------------------------------------------------------------------------- **/ - - /** - * Uses two transactions respectively with xid1 and xid2 that are used to send a message - * within xid1 and xid2. xid2 is committed and xid1 is used to receive the message that was sent within xid2. - * Xid is then committed and a standard transaction is used to receive the message that was sent within xid1. - */ - public void testProducer() - { - if (!isBroker08()) - { - _logger.debug("running testProducer"); - Xid xid1 = getNewXid(); - Xid xid2 = getNewXid(); - // start the xaResource for xid1 - try - { - _xaResource.start(xid1, XAResource.TMNOFLAGS); - } - catch (XAException e) - { - _logger.error("cannot start the transaction with xid1", e); - fail("cannot start the transaction with xid1: " + e.getMessage()); - } - try - { - // start the connection - _xaqueueConnection.start(); - // produce a message with sequence number 1 - _message.setLongProperty(_sequenceNumberPropertyName, 1); - _producer.send(_message); - } - catch (JMSException e) - { - fail(" cannot send persistent message: " + e.getMessage()); - } - // suspend the transaction - try - { - _xaResource.end(xid1, XAResource.TMSUSPEND); - } - catch (XAException e) - { - fail("Cannot end the transaction with xid1: " + e.getMessage()); - } - // start the xaResource for xid2 - try - { - _xaResource.start(xid2, XAResource.TMNOFLAGS); - } - catch (XAException e) - { - fail("cannot start the transaction with xid2: " + e.getMessage()); - } - try - { - // produce a message - _message.setLongProperty(_sequenceNumberPropertyName, 2); - _producer.send(_message); - } - catch (JMSException e) - { - fail(" cannot send second persistent message: " + e.getMessage()); - } - // end xid2 and start xid1 - try - { - _xaResource.end(xid2, XAResource.TMSUCCESS); - _xaResource.start(xid1, XAResource.TMRESUME); - } - catch (XAException e) - { - fail("Exception when ending and starting transactions: " + e.getMessage()); - } - // two phases commit transaction with xid2 - try - { - int resPrepare = _xaResource.prepare(xid2); - if (resPrepare != XAResource.XA_OK) - { - fail("prepare returned: " + resPrepare); - } - _xaResource.commit(xid2, false); - } - catch (XAException e) - { - fail("Exception thrown when preparing transaction with xid2: " + e.getMessage()); - } - // receive a message from queue test we expect it to be the second one - try - { - TextMessage message = (TextMessage) _consumer.receive(1000); - if (message == null) - { - fail("did not receive second message as expected "); - } - else - { - if (message.getLongProperty(_sequenceNumberPropertyName) != 2) - { - fail("receive wrong message its sequence number is: " + message - .getLongProperty(_sequenceNumberPropertyName)); - } - } - } - catch (JMSException e) - { - fail("Exception when receiving second message: " + e.getMessage()); - } - // end and one phase commit the first transaction - try - { - _xaResource.end(xid1, XAResource.TMSUCCESS); - _xaResource.commit(xid1, true); - } - catch (XAException e) - { - fail("Exception thrown when commiting transaction with xid1"); - } - // We should now be able to receive the first message - try - { - _xaqueueConnection.close(); - Session nonXASession = _nonXASession; - MessageConsumer nonXAConsumer = nonXASession.createConsumer(_queue); - _queueConnection.start(); - TextMessage message1 = (TextMessage) nonXAConsumer.receive(1000); - if (message1 == null) - { - fail("did not receive first message as expected "); - } - else - { - if (message1.getLongProperty(_sequenceNumberPropertyName) != 1) - { - fail("receive wrong message its sequence number is: " + message1 - .getLongProperty(_sequenceNumberPropertyName)); - } - } - // commit that transacted session - nonXASession.commit(); - // the queue should be now empty - message1 = (TextMessage) nonXAConsumer.receive(1000); - if (message1 != null) - { - fail("receive an unexpected message "); - } - } - catch (JMSException e) - { - fail("Exception thrown when emptying the queue: " + e.getMessage()); - } - } - } - - /** - * strategy: Produce a message within Tx1 and prepare tx1. crash the server then commit tx1 and consume the message - */ - public void testSendAndRecover() - { - if (!isBroker08()) - { - _logger.debug("running testSendAndRecover"); - Xid xid1 = getNewXid(); - // start the xaResource for xid1 - try - { - _xaResource.start(xid1, XAResource.TMNOFLAGS); - } - catch (XAException e) - { - fail("cannot start the transaction with xid1: " + e.getMessage()); - } - try - { - // start the connection - _xaqueueConnection.start(); - // produce a message with sequence number 1 - _message.setLongProperty(_sequenceNumberPropertyName, 1); - _producer.send(_message); - } - catch (JMSException e) - { - fail(" cannot send persistent message: " + e.getMessage()); - } - // suspend the transaction - try - { - _xaResource.end(xid1, XAResource.TMSUCCESS); - } - catch (XAException e) - { - fail("Cannot end the transaction with xid1: " + e.getMessage()); - } - // prepare the transaction with xid1 - try - { - _xaResource.prepare(xid1); - } - catch (XAException e) - { - fail("Exception when preparing xid1: " + e.getMessage()); - } - - /////// stop the server now !! - try - { - _logger.debug("stopping broker"); - restartBroker(); - init(); - } - catch (Exception e) - { - fail("Exception when stopping and restarting the server"); - } - - // get the list of in doubt transactions - try - { - Xid[] inDoubt = _xaResource.recover(XAResource.TMSTARTRSCAN); - if (inDoubt == null) - { - fail("the array of in doubt transactions should not be null "); - } - // At that point we expect only two indoubt transactions: - if (inDoubt.length != 1) - { - fail("in doubt transaction size is diffenrent thatn 2, there are " + inDoubt.length + "in doubt transactions"); - } - - // commit them - for (Xid anInDoubt : inDoubt) - { - if (anInDoubt.equals(xid1)) - { - _logger.info("commit xid1 "); - try - { - _xaResource.commit(anInDoubt, false); - } - catch (Exception e) - { - _logger.error("PB when aborted xid1", e); - } - } - else - { - fail("did not receive right xid "); - } - } - } - catch (XAException e) - { - _logger.error("exception thrown when recovering transactions", e); - fail("exception thrown when recovering transactions " + e.getMessage()); - } - // the queue should contain the first message! - try - { - _xaqueueConnection.close(); - Session nonXASession = _nonXASession; - MessageConsumer nonXAConsumer = nonXASession.createConsumer(_queue); - _queueConnection.start(); - TextMessage message1 = (TextMessage) nonXAConsumer.receive(1000); - - if (message1 == null) - { - fail("queue does not contain any message!"); - } - if (message1.getLongProperty(_sequenceNumberPropertyName) != 1) - { - fail("Wrong message returned! Sequence number is " + message1 - .getLongProperty(_sequenceNumberPropertyName)); - } - nonXASession.commit(); - } - catch (JMSException e) - { - fail("Exception thrown when testin that queue test is not empty: " + e.getMessage()); - } - } - } - - /** - * strategy: Produce a message within Tx1 and prepare tx1. Produce a standard message and consume - * it within tx2 and prepare tx2. Shutdown the server and get the list of in doubt transactions: - * we expect tx1 and tx2! Then, Tx1 is aborted and tx2 is committed so we expect the test's queue to be empty! - */ - public void testRecover() - { - if (!isBroker08()) - { - _logger.debug("running testRecover"); - Xid xid1 = getNewXid(); - Xid xid2 = getNewXid(); - // start the xaResource for xid1 - try - { - _xaResource.start(xid1, XAResource.TMNOFLAGS); - } - catch (XAException e) - { - fail("cannot start the transaction with xid1: " + e.getMessage()); - } - try - { - // start the connection - _xaqueueConnection.start(); - // produce a message with sequence number 1 - _message.setLongProperty(_sequenceNumberPropertyName, 1); - _producer.send(_message); - } - catch (JMSException e) - { - fail(" cannot send persistent message: " + e.getMessage()); - } - // suspend the transaction - try - { - _xaResource.end(xid1, XAResource.TMSUCCESS); - } - catch (XAException e) - { - fail("Cannot end the transaction with xid1: " + e.getMessage()); - } - // prepare the transaction with xid1 - try - { - _xaResource.prepare(xid1); - } - catch (XAException e) - { - fail("Exception when preparing xid1: " + e.getMessage()); - } - - // send a message using the standard session - try - { - Session nonXASession = _nonXASession; - MessageProducer nonXAProducer = nonXASession.createProducer(_queue); - TextMessage message2 = nonXASession.createTextMessage(); - message2.setText("non XA "); - message2.setLongProperty(_sequenceNumberPropertyName, 2); - nonXAProducer.setDeliveryMode(DeliveryMode.PERSISTENT); - nonXAProducer.send(message2); - // commit that transacted session - nonXASession.commit(); - } - catch (Exception e) - { - fail("Exception thrown when emptying the queue: " + e.getMessage()); - } - // start the xaResource for xid2 - try - { - _xaResource.start(xid2, XAResource.TMNOFLAGS); - } - catch (XAException e) - { - fail("cannot start the transaction with xid1: " + e.getMessage()); - } - // receive a message from queue test we expect it to be the second one - try - { - TextMessage message = (TextMessage) _consumer.receive(1000); - if (message == null || message.getLongProperty(_sequenceNumberPropertyName) != 2) - { - fail("did not receive second message as expected "); - } - } - catch (JMSException e) - { - fail("Exception when receiving second message: " + e.getMessage()); - } - // suspend the transaction - try - { - _xaResource.end(xid2, XAResource.TMSUCCESS); - } - catch (XAException e) - { - fail("Cannot end the transaction with xid2: " + e.getMessage()); - } - // prepare the transaction with xid1 - try - { - _xaResource.prepare(xid2); - } - catch (XAException e) - { - fail("Exception when preparing xid2: " + e.getMessage()); - } - - /////// stop the server now !! - try - { - _logger.debug("stopping broker"); - restartBroker(); - init(); - } - catch (Exception e) - { - fail("Exception when stopping and restarting the server"); - } - - // get the list of in doubt transactions - try - { - Xid[] inDoubt = _xaResource.recover(XAResource.TMSTARTRSCAN); - if (inDoubt == null) - { - fail("the array of in doubt transactions should not be null "); - } - // At that point we expect only two indoubt transactions: - if (inDoubt.length != 2) - { - fail("in doubt transaction size is diffenrent thatn 2, there are " + inDoubt.length + "in doubt transactions"); - } - - // commit them - for (Xid anInDoubt : inDoubt) - { - if (anInDoubt.equals(xid1)) - { - _logger.debug("rollback xid1 "); - try - { - _xaResource.rollback(anInDoubt); - } - catch (Exception e) - { - _logger.error("PB when aborted xid1", e); - } - } - else if (anInDoubt.equals(xid2)) - { - _logger.debug("commit xid2 "); - try - { - _xaResource.commit(anInDoubt, false); - } - catch (Exception e) - { - _logger.error("PB when commiting xid2", e); - } - } - } - } - catch (XAException e) - { - _logger.error("exception thrown when recovering transactions", e); - fail("exception thrown when recovering transactions " + e.getMessage()); - } - // the queue should be empty - try - { - _xaqueueConnection.close(); - Session nonXASession = _nonXASession; - MessageConsumer nonXAConsumer = nonXASession.createConsumer(_queue); - _queueConnection.start(); - TextMessage message1 = (TextMessage) nonXAConsumer.receive(1000); - if (message1 != null) - { - - fail("The queue is not empty! " + message1.getLongProperty(_sequenceNumberPropertyName)); - } - } - catch (JMSException e) - { - fail("Exception thrown when testin that queue test is empty: " + e.getMessage()); - } - } - } - - /** -------------------------------------------------------------------------------------- **/ - /** ----------------------------- Utility methods --------------------------------------- **/ - /** -------------------------------------------------------------------------------------- **/ - - /** - * get a new queue connection - * - * @return a new queue connection - * @throws JMSException If the JMS provider fails to create the queue connection - * due to some internal error or in case of authentication failure - */ - private XAQueueConnection getNewQueueXAConnection() throws JMSException - { - return _queueFactory.createXAQueueConnection("guest", "guest"); - } - - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/TopicTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/TopicTest.java deleted file mode 100644 index 4d9242b8b3..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/xa/TopicTest.java +++ /dev/null @@ -1,1742 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.test.unit.xa; - -import junit.framework.TestSuite; -import org.apache.qpid.configuration.ClientProperties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.jms.*; -import javax.transaction.xa.XAException; -import javax.transaction.xa.XAResource; -import javax.transaction.xa.Xid; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * - * - */ -public class TopicTest extends AbstractXATestCase -{ - /* this class logger */ - private static final Logger _logger = LoggerFactory.getLogger(TopicTest.class); - - /** - * the topic use by all the tests - */ - private static Topic _topic = null; - - /** - * the topic connection factory used by all tests - */ - private static XATopicConnectionFactory _topicFactory = null; - - /** - * standard topic connection - */ - private static XATopicConnection _topicConnection = null; - - /** - * standard topic session created from the standard connection - */ - private static XATopicSession _session = null; - - private static TopicSession _nonXASession = null; - - /** - * the topic name - */ - private static final String TOPICNAME = "xaTopic"; - - /** - * Indicate that a listenere has failed - */ - private static boolean _failure = false; - - /** -------------------------------------------------------------------------------------- **/ - /** ----------------------------- JUnit support ----------------------------------------- **/ - /** -------------------------------------------------------------------------------------- **/ - - /** - * Gets the test suite tests - * - * @return the test suite tests - */ - public static TestSuite getSuite() - { - return new TestSuite(TopicTest.class); - } - - /** - * Run the test suite. - * - * @param args Any command line arguments specified to this class. - */ - public static void main(String args[]) - { - junit.textui.TestRunner.run(getSuite()); - } - - public void tearDown() throws Exception - { - if (!isBroker08()) - { - try - { - _topicConnection.stop(); - _topicConnection.close(); - } - catch (Exception e) - { - fail("Exception thrown when cleaning standard connection: " + e); - } - } - super.tearDown(); - } - - /** - * Initialize standard actors - */ - public void init() - { - if (!isBroker08()) - { - setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, "1"); - // lookup test queue - try - { - _topic = (Topic) getInitialContext().lookup(TOPICNAME); - } - catch (Exception e) - { - fail("cannot lookup test topic " + e.getMessage()); - } - // lookup connection factory - try - { - _topicFactory = getConnectionFactory(); - } - catch (Exception e) - { - fail("enable to lookup connection factory "); - } - // create standard connection - try - { - _topicConnection = getNewTopicXAConnection(); - } - catch (JMSException e) - { - fail("cannot create queue connection: " + e.getMessage()); - } - // create standard session - try - { - _session = _topicConnection.createXATopicSession(); - } - catch (JMSException e) - { - fail("cannot create queue session: " + e.getMessage()); - } - // create a standard session - try - { - _nonXASession = _topicConnection.createTopicSession(true, Session.AUTO_ACKNOWLEDGE); - } - catch (JMSException e) - { - _logger.error("Error creating topic session", e); - } - init(_session, _topic); - } - } - - /** -------------------------------------------------------------------------------------- **/ - /** ----------------------------- Test Suite -------------------------------------------- **/ - /** -------------------------------------------------------------------------------------- **/ - - - /** - * Uses two transactions respectively with xid1 and xid2 that are use to send a message - * within xid1 and xid2. xid2 is committed and xid1 is used to receive the message that was sent within xid2. - * Xid is then committed and a standard transaction is used to receive the message that was sent within xid1. - */ - public void testProducer() - { - if (!isBroker08()) - { - _logger.debug("testProducer"); - Xid xid1 = getNewXid(); - Xid xid2 = getNewXid(); - try - { - Session nonXASession = _nonXASession; - MessageConsumer nonXAConsumer = nonXASession.createConsumer(_topic); - _producer.setDeliveryMode(DeliveryMode.PERSISTENT); - // start the xaResource for xid1 - try - { - _logger.debug("starting tx branch xid1"); - _xaResource.start(xid1, XAResource.TMNOFLAGS); - } - catch (XAException e) - { - _logger.error("cannot start the transaction with xid1", e); - fail("cannot start the transaction with xid1: " + e.getMessage()); - } - try - { - // start the connection - _topicConnection.start(); - _logger.debug("produce a message with sequence number 1"); - _message.setLongProperty(_sequenceNumberPropertyName, 1); - _producer.send(_message); - } - catch (JMSException e) - { - fail(" cannot send persistent message: " + e.getMessage()); - } - _logger.debug("suspend the transaction branch xid1"); - try - { - _xaResource.end(xid1, XAResource.TMSUSPEND); - } - catch (XAException e) - { - fail("Cannot end the transaction with xid1: " + e.getMessage()); - } - _logger.debug("start the xaResource for xid2"); - try - { - _xaResource.start(xid2, XAResource.TMNOFLAGS); - } - catch (XAException e) - { - fail("cannot start the transaction with xid2: " + e.getMessage()); - } - try - { - _logger.debug("produce a message"); - _message.setLongProperty(_sequenceNumberPropertyName, 2); - _producer.send(_message); - } - catch (JMSException e) - { - fail(" cannot send second persistent message: " + e.getMessage()); - } - _logger.debug("end xid2 and start xid1"); - try - { - _xaResource.end(xid2, XAResource.TMSUCCESS); - _xaResource.start(xid1, XAResource.TMRESUME); - } - catch (XAException e) - { - fail("Exception when ending and starting transactions: " + e.getMessage()); - } - _logger.debug("two phases commit transaction with xid2"); - try - { - int resPrepare = _xaResource.prepare(xid2); - if (resPrepare != XAResource.XA_OK) - { - fail("prepare returned: " + resPrepare); - } - _xaResource.commit(xid2, false); - } - catch (XAException e) - { - fail("Exception thrown when preparing transaction with xid2: " + e.getMessage()); - } - _logger.debug("receiving a message from topic test we expect it to be the second one"); - try - { - TextMessage message = (TextMessage) _consumer.receive(1000); - if (message == null) - { - fail("did not receive second message as expected "); - } - else - { - if (message.getLongProperty(_sequenceNumberPropertyName) != 2) - { - fail("receive wrong message its sequence number is: " + message - .getLongProperty(_sequenceNumberPropertyName)); - } - } - } - catch (JMSException e) - { - fail("Exception when receiving second message: " + e.getMessage()); - } - _logger.debug("end and one phase commit the first transaction"); - try - { - _xaResource.end(xid1, XAResource.TMSUCCESS); - _xaResource.commit(xid1, true); - } - catch (XAException e) - { - fail("Exception thrown when commiting transaction with xid1"); - } - _logger.debug("We should now be able to receive the first and second message"); - try - { - TextMessage message1 = (TextMessage) nonXAConsumer.receive(1000); - if (message1 == null) - { - fail("did not receive first message as expected "); - } - else - { - if (message1.getLongProperty(_sequenceNumberPropertyName) != 2) - { - fail("receive wrong message its sequence number is: " + message1 - .getLongProperty(_sequenceNumberPropertyName)); - } - } - message1 = (TextMessage) nonXAConsumer.receive(1000); - if (message1 == null) - { - fail("did not receive first message as expected "); - } - else - { - if (message1.getLongProperty(_sequenceNumberPropertyName) != 1) - { - fail("receive wrong message its sequence number is: " + message1 - .getLongProperty(_sequenceNumberPropertyName)); - } - } - _logger.debug("commit transacted session"); - nonXASession.commit(); - _logger.debug("Test that the topic is now empty"); - message1 = (TextMessage) nonXAConsumer.receive(1000); - if (message1 != null) - { - fail("receive an unexpected message "); - } - } - catch (JMSException e) - { - fail("Exception thrown when emptying the queue: " + e.getMessage()); - } - } - catch (JMSException e) - { - fail("cannot create standard consumer: " + e.getMessage()); - } - } - } - - - /** - * strategy: Produce a message within Tx1 and commit tx1. consume this message within tx2 and abort tx2. - * Consume the same message within tx3 and commit it. Check that no more message is available. - */ - public void testDurSub() - { - if (!isBroker08()) - { - Xid xid1 = getNewXid(); - Xid xid2 = getNewXid(); - Xid xid3 = getNewXid(); - Xid xid4 = getNewXid(); - String durSubName = "xaSubDurable"; - try - { - TopicSubscriber xaDurSub = _session.createDurableSubscriber(_topic, durSubName); - try - { - _topicConnection.start(); - _logger.debug("start xid1"); - _xaResource.start(xid1, XAResource.TMNOFLAGS); - // start the connection - _topicConnection.start(); - _logger.debug("produce a message with sequence number 1"); - _message.setLongProperty(_sequenceNumberPropertyName, 1); - _producer.send(_message); - _logger.debug("2 phases commit xid1"); - _xaResource.end(xid1, XAResource.TMSUCCESS); - if (_xaResource.prepare(xid1) != XAResource.XA_OK) - { - fail("Problem when preparing tx1 "); - } - _xaResource.commit(xid1, false); - } - catch (Exception e) - { - _logger.error("Exception when working with xid1", e); - fail("Exception when working with xid1: " + e.getMessage()); - } - try - { - _logger.debug("start xid2"); - _xaResource.start(xid2, XAResource.TMNOFLAGS); - _logger.debug("receive the previously produced message"); - TextMessage message = (TextMessage) xaDurSub.receive(1000); - if (message == null) - { - fail("no message received "); - } - else if (message.getLongProperty(_sequenceNumberPropertyName) != 1) - { - fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); - } - _logger.debug("rollback xid2"); - boolean rollbackOnFailure = false; - try - { - _xaResource.end(xid2, XAResource.TMFAIL); - } - catch (XAException e) - { - if (e.errorCode != XAException.XA_RBROLLBACK) - { - fail("Exception when working with xid2: " + e.getMessage()); - } - rollbackOnFailure = true; - } - if (!rollbackOnFailure) - { - if (_xaResource.prepare(xid2) != XAResource.XA_OK) - { - fail("Problem when preparing tx2 "); - } - _xaResource.rollback(xid2); - } - } - catch (Exception e) - { - _logger.error("Exception when working with xid2", e); - fail("Exception when working with xid2: " + e.getMessage()); - } - try - { - _logger.debug("start xid3"); - _xaResource.start(xid3, XAResource.TMNOFLAGS); - _logger.debug(" receive the previously aborted consumed message"); - TextMessage message = (TextMessage) xaDurSub.receive(1000); - if (message == null) - { - fail("no message received "); - } - else if (message.getLongProperty(_sequenceNumberPropertyName) != 1) - { - fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); - } - _logger.debug("commit xid3"); - _xaResource.end(xid3, XAResource.TMSUCCESS); - if (_xaResource.prepare(xid3) != XAResource.XA_OK) - { - fail("Problem when preparing tx3 "); - } - _xaResource.commit(xid3, false); - } - catch (Exception e) - { - _logger.error("Exception when working with xid3", e); - fail("Exception when working with xid3: " + e.getMessage()); - } - try - { - _logger.debug("start xid4"); - _xaResource.start(xid4, XAResource.TMNOFLAGS); - _logger.debug("check that topic is empty"); - TextMessage message = (TextMessage) xaDurSub.receive(1000); - if (message != null) - { - fail("An unexpected message was received "); - } - _logger.debug("commit xid4"); - _xaResource.end(xid4, XAResource.TMSUCCESS); - _xaResource.commit(xid4, true); - } - catch (Exception e) - { - _logger.error("Exception when working with xid4", e); - fail("Exception when working with xid4: " + e.getMessage()); - } - } - catch (Exception e) - { - _logger.error("problem when creating dur sub", e); - fail("problem when creating dur sub: " + e.getMessage()); - } - finally - { - try - { - _session.unsubscribe(durSubName); - } - catch (JMSException e) - { - _logger.error("problem when unsubscribing dur sub", e); - fail("problem when unsubscribing dur sub: " + e.getMessage()); - } - } - } - } - - /** - * strategy: create a XA durable subscriber dusSub, produce 7 messages with the standard session, - * consume 2 messages respectively with tx1, tx2 and tx3 - * abort tx2, we now expect to receive messages 3 and 4 first! Receive 3 messages within tx1 i.e. 34 and 7! - * commit tx3 - * abort tx1: we now expect that only messages 5 and 6 are definitly consumed! - * start tx4 and consume messages 1 - 4 and 7 - * commit tx4 - * Now the topic should be empty! - */ - public void testMultiMessagesDurSub() - { - if (!isBroker08()) - { - Xid xid1 = getNewXid(); - Xid xid2 = getNewXid(); - Xid xid3 = getNewXid(); - Xid xid4 = getNewXid(); - Xid xid6 = getNewXid(); - String durSubName = "xaSubDurable"; - TextMessage message; - try - { - TopicSubscriber xaDurSub = _session.createDurableSubscriber(_topic, durSubName); - try - { - Session txSession = _nonXASession; - MessageProducer txProducer = txSession.createProducer(_topic); - _logger.debug("produce 10 persistent messages"); - txProducer.setDeliveryMode(DeliveryMode.PERSISTENT); - _topicConnection.start(); - for (int i = 1; i <= 7; i++) - { - _message.setLongProperty(_sequenceNumberPropertyName, i); - txProducer.send(_message); - } - // commit txSession - txSession.commit(); - } - catch (JMSException e) - { - _logger.error("Exception thrown when producing messages", e); - fail("Exception thrown when producing messages: " + e.getMessage()); - } - - try - { - _logger.debug(" consume 2 messages respectively with tx1, tx2 and tx3"); - //----- start xid1 - _xaResource.start(xid1, XAResource.TMNOFLAGS); - // receive the 2 first messages - for (int i = 1; i <= 2; i++) - { - message = (TextMessage) xaDurSub.receive(1000); - if (message == null) - { - fail("no message received! expected: " + i); - } - else if (message.getLongProperty(_sequenceNumberPropertyName) != i) - { - fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); - } - } - _xaResource.end(xid1, XAResource.TMSUSPEND); - //----- start xid2 - _xaResource.start(xid2, XAResource.TMNOFLAGS); - // receive the 2 first messages - for (int i = 3; i <= 4; i++) - { - message = (TextMessage) xaDurSub.receive(1000); - if (message == null) - { - fail("no message received! expected: " + i); - } - else if (message.getLongProperty(_sequenceNumberPropertyName) != i) - { - fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); - } - } - _xaResource.end(xid2, XAResource.TMSUSPEND); - //----- start xid3 - _xaResource.start(xid3, XAResource.TMNOFLAGS); - // receive the 2 first messages - for (int i = 5; i <= 6; i++) - { - message = (TextMessage) xaDurSub.receive(1000); - if (message == null) - { - fail("no message received! expected: " + i); - } - else if (message.getLongProperty(_sequenceNumberPropertyName) != i) - { - fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); - } - } - _xaResource.end(xid3, XAResource.TMSUCCESS); - } - catch (Exception e) - { - _logger.error("Exception thrown when consumming 6 first messages", e); - fail("Exception thrown when consumming 6 first messages: " + e.getMessage()); - } - try - { - _logger.debug("abort tx2, we now expect to receive messages 3, 4 and 7"); - _xaResource.start(xid2, XAResource.TMRESUME); - _xaResource.end(xid2, XAResource.TMSUCCESS); - _xaResource.prepare(xid2); - _xaResource.rollback(xid2); - // receive 3 message within tx1: 3, 4 and 7 - _xaResource.start(xid1, XAResource.TMRESUME); - _logger.debug(" 3, 4 and 7"); - for (int i = 1; i <= 3; i++) - { - message = (TextMessage) xaDurSub.receive(1000); - if (message == null) - { - fail("no message received! expected: " + 3); - } - else if (message.getLongProperty(_sequenceNumberPropertyName) <= 2 || 5 == message - .getLongProperty(_sequenceNumberPropertyName) || message - .getLongProperty(_sequenceNumberPropertyName) == 6) - { - fail("wrong sequence number: " + message - .getLongProperty(_sequenceNumberPropertyName)); - } - } - } - catch (Exception e) - { - _logger.error("Exception thrown when consumming message: 3, 4 and 7", e); - fail("Exception thrown when consumming message: 3, 4 and 7: " + e.getMessage()); - } - - try - { - _xaResource.end(xid1, XAResource.TMSUCCESS); - _logger.debug(" commit tx3"); - _xaResource.commit(xid3, true); - _logger.debug("abort tx1"); - _xaResource.prepare(xid1); - _xaResource.rollback(xid1); - } - catch (XAException e) - { - _logger.error("XAException thrown when committing tx3 or aborting tx1", e); - fail("XAException thrown when committing tx3 or aborting tx1: " + e.getMessage()); - } - - try - { - // consume messages 1 - 4 + 7 - //----- start xid1 - _xaResource.start(xid4, XAResource.TMNOFLAGS); - for (int i = 1; i <= 5; i++) - { - - message = (TextMessage) xaDurSub.receive(1000); - - if(message != null) - { - _logger.debug(" received message: " + message.getLongProperty(_sequenceNumberPropertyName)); - } - - if (message == null) - { - fail("no message received! expected: " + i); - } - else if (message.getLongProperty(_sequenceNumberPropertyName) == 5 || message - .getLongProperty(_sequenceNumberPropertyName) == 6) - { - fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); - } - } - _xaResource.end(xid4, XAResource.TMSUCCESS); - _xaResource.prepare(xid4); - _xaResource.commit(xid4, false); - } - catch (Exception e) - { - _logger.error("Exception thrown in last phase", e); - fail("Exception thrown in last phase: " + e.getMessage()); - } - // now the topic should be empty!! - try - { - // start xid6 - _xaResource.start(xid6, XAResource.TMNOFLAGS); - // should now be empty - message = (TextMessage) xaDurSub.receive(1000); - if (message != null) - { - fail("An unexpected message was received " + message - .getLongProperty(_sequenceNumberPropertyName)); - } - // commit xid6 - _xaResource.end(xid6, XAResource.TMSUCCESS); - _xaResource.commit(xid6, true); - } - catch (Exception e) - { - _logger.error("Exception when working with xid6", e); - fail("Exception when working with xid6: " + e.getMessage()); - } - } - catch (Exception e) - { - _logger.error("problem when creating dur sub", e); - fail("problem when creating dur sub: " + e.getMessage()); - } - finally - { - try - { - _session.unsubscribe(durSubName); - } - catch (JMSException e) - { - _logger.error("problem when unsubscribing dur sub", e); - fail("problem when unsubscribing dur sub: " + e.getMessage()); - } - } - } - } - - /** - * strategy: create a XA durable subscriber dusSub, produce 10 messages with the standard session, - * consume 2 messages respectively with tx1, tx2 and tx3 - * prepare xid2 and xid3 - * crash the server - * Redo the job for xid1 that has been aborted by server crash - * abort tx2, we now expect to receive messages 3 and 4 first! Receive 3 messages within tx1 i.e. 34 and 7! - * commit tx3 - * abort tx1: we now expect that only messages 5 and 6 are definitly consumed! - * start tx4 and consume messages 1 - 4 - * start tx5 and consume messages 7 - 10 - * abort tx4 - * consume messages 1-4 with tx5 - * commit tx5 - * Now the topic should be empty! - */ - public void testMultiMessagesDurSubCrash() - { - if (!isBroker08()) - { - Xid xid1 = getNewXid(); - Xid xid2 = getNewXid(); - Xid xid3 = getNewXid(); - Xid xid4 = getNewXid(); - Xid xid5 = getNewXid(); - Xid xid6 = getNewXid(); - String durSubName = "xaSubDurable"; - TextMessage message; - try - { - TopicSubscriber xaDurSub = _session.createDurableSubscriber(_topic, durSubName); - try - { - Session txSession = _nonXASession; - MessageProducer txProducer = txSession.createProducer(_topic); - // produce 10 persistent messages - txProducer.setDeliveryMode(DeliveryMode.PERSISTENT); - _topicConnection.start(); - for (int i = 1; i <= 10; i++) - { - _message.setLongProperty(_sequenceNumberPropertyName, i); - txProducer.send(_message); - } - // commit txSession - txSession.commit(); - } - catch (JMSException e) - { - _logger.error("Exception thrown when producing messages", e); - fail("Exception thrown when producing messages: " + e.getMessage()); - } - try - { - // consume 2 messages respectively with tx1, tx2 and tx3 - //----- start xid1 - _xaResource.start(xid1, XAResource.TMNOFLAGS); - // receive the 2 first messages - for (int i = 1; i <= 2; i++) - { - message = (TextMessage) xaDurSub.receive(1000); - if (message == null) - { - fail("no message received! expected: " + i); - } - else if (message.getLongProperty(_sequenceNumberPropertyName) != i) - { - fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); - } - } - _xaResource.end(xid1, XAResource.TMSUCCESS); - //----- start xid2 - _xaResource.start(xid2, XAResource.TMNOFLAGS); - // receive the 2 first messages - for (int i = 3; i <= 4; i++) - { - message = (TextMessage) xaDurSub.receive(1000); - if (message == null) - { - fail("no message received! expected: " + i); - } - else if (message.getLongProperty(_sequenceNumberPropertyName) != i) - { - fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); - } - } - _xaResource.end(xid2, XAResource.TMSUCCESS); - //----- start xid3 - _xaResource.start(xid3, XAResource.TMNOFLAGS); - // receive the 2 first messages - for (int i = 5; i <= 6; i++) - { - message = (TextMessage) xaDurSub.receive(1000); - if (message == null) - { - fail("no message received! expected: " + i); - } - else if (message.getLongProperty(_sequenceNumberPropertyName) != i) - { - fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); - } - } - _xaResource.end(xid3, XAResource.TMSUCCESS); - // prepare tx2 and tx3 - - _xaResource.prepare(xid2); - _xaResource.prepare(xid3); - } - catch (Exception e) - { - _logger.error("Exception thrown when consumming 6 first messages", e); - fail("Exception thrown when consumming 6 first messages: " + e.getMessage()); - } - /////// stop the broker now !! - try - { - restartBroker(); - init(); - } - catch (Exception e) - { - fail("Exception when stopping and restarting the server"); - } - // get the list of in doubt transactions - try - { - _topicConnection.start(); - // reconnect to dursub! - xaDurSub = _session.createDurableSubscriber(_topic, durSubName); - Xid[] inDoubt = _xaResource.recover(XAResource.TMSTARTRSCAN); - if (inDoubt == null) - { - fail("the array of in doubt transactions should not be null "); - } - // At that point we expect only two indoubt transactions: - if (inDoubt.length != 2) - { - fail("in doubt transaction size is diffenrent than 2, there are " + inDoubt.length + "in doubt transactions"); - } - } - catch (XAException e) - { - _logger.error("exception thrown when recovering transactions", e); - fail("exception thrown when recovering transactions " + e.getMessage()); - } - try - { - // xid1 has been aborted redo the job! - // consume 2 messages with tx1 - //----- start xid1 - _xaResource.start(xid1, XAResource.TMNOFLAGS); - // receive the 2 first messages - for (int i = 1; i <= 2; i++) - { - message = (TextMessage) xaDurSub.receive(1000); - if (message == null) - { - fail("no message received! expected: " + i); - } - else if (message.getLongProperty(_sequenceNumberPropertyName) != i) - { - fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); - } - } - _xaResource.end(xid1, XAResource.TMSUSPEND); - // abort tx2, we now expect to receive messages 3 and 4 first! - _xaResource.rollback(xid2); - - // receive 3 message within tx1: 3, 4 and 7 - _xaResource.start(xid1, XAResource.TMRESUME); - // receive messages 3, 4 and 7 - Set expected = new HashSet(); - expected.add(3L); - expected.add(4L); - expected.add(7L); - message = (TextMessage) xaDurSub.receive(1000); - if (message == null) - { - fail("no message received! expected one of: " + expected); - } - else if (!expected.remove(message.getLongProperty(_sequenceNumberPropertyName))) - { - fail("wrong sequence number: " + message - .getLongProperty(_sequenceNumberPropertyName) + " expected one from " + expected); - } - message = (TextMessage) xaDurSub.receive(1000); - if (message == null) - { - fail("no message received! expected one of: " + expected); - } - else if (!expected.remove(message.getLongProperty(_sequenceNumberPropertyName))) - { - - fail("wrong sequence number: " + message - .getLongProperty(_sequenceNumberPropertyName) + " expected one from " + expected); - } - message = (TextMessage) xaDurSub.receive(1000); - if (message == null) - { - fail("no message received! expected one of: " + expected); - } - else if (!expected.remove(message.getLongProperty(_sequenceNumberPropertyName))) - { - fail("wrong sequence number: " + message - .getLongProperty(_sequenceNumberPropertyName) + " expected one from " + expected); - } - } - catch (Exception e) - { - _logger.error("Exception thrown when consumming message: 3, 4 and 7", e); - fail("Exception thrown when consumming message: 3, 4 and 7: " + e.getMessage()); - } - - try - { - _xaResource.end(xid1, XAResource.TMSUSPEND); - // commit tx3 - _xaResource.commit(xid3, false); - // abort tx1 - _xaResource.prepare(xid1); - _xaResource.rollback(xid1); - } - catch (XAException e) - { - _logger.error("XAException thrown when committing tx3 or aborting tx1", e); - fail("XAException thrown when committing tx3 or aborting tx1: " + e.getMessage()); - } - - try - { - // consume messages: could be any from (1 - 4, 7-10) - //----- start xid4 - Set expected = new HashSet(); - Set xid4msgs = new HashSet(); - for(long l = 1; l <= 4l; l++) - { - expected.add(l); - } - for(long l = 7; l <= 10l; l++) - { - expected.add(l); - } - _xaResource.start(xid4, XAResource.TMNOFLAGS); - for (int i = 1; i <= 4; i++) - { - message = (TextMessage) xaDurSub.receive(1000); - if (message == null) - { - fail("no message received! expected: " + i); - } - - long seqNo = message.getLongProperty(_sequenceNumberPropertyName); - xid4msgs.add(seqNo); - - if (!expected.remove(seqNo)) - { - fail("wrong sequence number: " + seqNo + - " expected one from " + expected); - } - } - _xaResource.end(xid4, XAResource.TMSUSPEND); - // consume messages 8 - 10 - _xaResource.start(xid5, XAResource.TMNOFLAGS); - for (int i = 7; i <= 10; i++) - { - message = (TextMessage) xaDurSub.receive(1000); - if (message == null) - { - fail("no message received! expected: " + i); - } - else if (!expected.remove(message.getLongProperty(_sequenceNumberPropertyName))) - { - fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName) - + " expected one from " + expected); - } - } - _xaResource.end(xid5, XAResource.TMSUSPEND); - // abort tx4 - _xaResource.prepare(xid4); - _xaResource.rollback(xid4); - expected.addAll(xid4msgs); - // consume messages 1-4 with tx5 - _xaResource.start(xid5, XAResource.TMRESUME); - for (int i = 1; i <= 4; i++) - { - message = (TextMessage) xaDurSub.receive(1000); - if (message == null) - { - fail("no message received! expected: " + i); - } - else if (!expected.remove(message.getLongProperty(_sequenceNumberPropertyName))) - { - fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName) - + " expected one from " + expected); - } - } - _xaResource.end(xid5, XAResource.TMSUSPEND); - // commit tx5 - - _xaResource.prepare(xid5); - _xaResource.commit(xid5, false); - } - catch (Exception e) - { - _logger.error("Exception thrown in last phase", e); - fail("Exception thrown in last phase: " + e.getMessage()); - } - // now the topic should be empty!! - try - { - // start xid6 - _xaResource.start(xid6, XAResource.TMNOFLAGS); - // should now be empty - message = (TextMessage) xaDurSub.receive(1000); - if (message != null) - { - fail("An unexpected message was received " + message - .getLongProperty(_sequenceNumberPropertyName)); - } - // commit xid6 - _xaResource.end(xid6, XAResource.TMSUSPEND); - _xaResource.commit(xid6, true); - } - catch (Exception e) - { - _logger.error("Exception when working with xid6", e); - fail("Exception when working with xid6: " + e.getMessage()); - } - } - catch (Exception e) - { - _logger.error("problem when creating dur sub", e); - fail("problem when creating dur sub: " + e.getMessage()); - } - finally - { - try - { - _session.unsubscribe(durSubName); - } - catch (JMSException e) - { - _logger.error("problem when unsubscribing dur sub", e); - fail("problem when unsubscribing dur sub: " + e.getMessage()); - } - } - } - } - - - /** - * strategy: Produce a message within Tx1 and commit tx1. a durable subscriber then receives that message within tx2 - * that is then prepared. - * Shutdown the server and get the list of in doubt transactions: - * we expect tx2, Tx2 is aborted and the message consumed within tx3 that is committed we then check that the topic is empty. - */ - public void testDurSubCrash() - { - if (!isBroker08()) - { - Xid xid1 = getNewXid(); - Xid xid2 = getNewXid(); - Xid xid3 = getNewXid(); - Xid xid4 = getNewXid(); - String durSubName = "xaSubDurable"; - try - { - TopicSubscriber xaDurSub = _session.createDurableSubscriber(_topic, durSubName); - try - { - _topicConnection.start(); - //----- start xid1 - _xaResource.start(xid1, XAResource.TMNOFLAGS); - // start the connection - _topicConnection.start(); - // produce a message with sequence number 1 - _message.setLongProperty(_sequenceNumberPropertyName, 1); - _producer.send(_message); - // commit - _xaResource.end(xid1, XAResource.TMSUCCESS); - if (_xaResource.prepare(xid1) != XAResource.XA_OK) - { - fail("Problem when preparing tx1 "); - } - _xaResource.commit(xid1, false); - } - catch (Exception e) - { - _logger.error("Exception when working with xid1", e); - fail("Exception when working with xid1: " + e.getMessage()); - } - try - { - // start xid2 - _xaResource.start(xid2, XAResource.TMNOFLAGS); - // receive the previously produced message - TextMessage message = (TextMessage) xaDurSub.receive(1000); - if (message == null) - { - fail("no message received "); - } - else if (message.getLongProperty(_sequenceNumberPropertyName) != 1) - { - fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); - } - // prepare xid2 - _xaResource.end(xid2, XAResource.TMSUCCESS); - if (_xaResource.prepare(xid2) != XAResource.XA_OK) - { - fail("Problem when preparing tx2 "); - } - } - catch (Exception e) - { - _logger.error("Exception when working with xid2", e); - fail("Exception when working with xid2: " + e.getMessage()); - } - - /////// stop the server now !! - try - { - restartBroker(); - init(); - } - catch (Exception e) - { - fail("Exception when stopping and restarting the server"); - } - - // get the list of in doubt transactions - try - { - _topicConnection.start(); - // reconnect to dursub! - xaDurSub = _session.createDurableSubscriber(_topic, durSubName); - Xid[] inDoubt = _xaResource.recover(XAResource.TMSTARTRSCAN); - if (inDoubt == null) - { - fail("the array of in doubt transactions should not be null "); - } - // At that point we expect only two indoubt transactions: - if (inDoubt.length != 1) - { - fail("in doubt transaction size is diffenrent than 2, there are " + inDoubt.length + "in doubt transactions"); - } - - // commit them - for (Xid anInDoubt : inDoubt) - { - if (anInDoubt.equals(xid2)) - { - _logger.info("aborting xid2 "); - try - { - _xaResource.rollback(anInDoubt); - } - catch (Exception e) - { - _logger.error("exception when aborting xid2 ", e); - fail("exception when aborting xid2 "); - } - } - else - { - _logger.info("XID2 is not in doubt "); - } - } - } - catch (XAException e) - { - _logger.error("exception thrown when recovering transactions", e); - fail("exception thrown when recovering transactions " + e.getMessage()); - } - - try - { - // start xid3 - _xaResource.start(xid3, XAResource.TMNOFLAGS); - // receive the previously produced message and aborted - TextMessage message = (TextMessage) xaDurSub.receive(1000); - if (message == null) - { - fail("no message received "); - } - else if (message.getLongProperty(_sequenceNumberPropertyName) != 1) - { - fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); - } - // commit xid3 - _xaResource.end(xid3, XAResource.TMSUCCESS); - if (_xaResource.prepare(xid3) != XAResource.XA_OK) - { - fail("Problem when preparing tx3 "); - } - _xaResource.commit(xid3, false); - } - catch (Exception e) - { - _logger.error("Exception when working with xid3", e); - fail("Exception when working with xid3: " + e.getMessage()); - } - try - { - // start xid4 - _xaResource.start(xid4, XAResource.TMNOFLAGS); - // should now be empty - TextMessage message = (TextMessage) xaDurSub.receive(1000); - if (message != null) - { - fail("An unexpected message was received " + message - .getLongProperty(_sequenceNumberPropertyName)); - } - // commit xid4 - _xaResource.end(xid4, XAResource.TMSUCCESS); - _xaResource.commit(xid4, true); - } - catch (Exception e) - { - _logger.error("Exception when working with xid4", e); - fail("Exception when working with xid4: " + e.getMessage()); - } - } - catch (Exception e) - { - _logger.error("problem when creating dur sub", e); - fail("problem when creating dur sub: " + e.getMessage()); - } - finally - { - try - { - _session.unsubscribe(durSubName); - } - catch (JMSException e) - { - _logger.error("problem when unsubscribing dur sub", e); - fail("problem when unsubscribing dur sub: " + e.getMessage()); - } - } - } - } - - /** - * strategy: Produce a message within Tx1 and prepare tx1. Shutdown the server and get the list of indoubt transactions: - * we expect tx1, Tx1 is committed so we expect the test topic not to be empty! - */ - public void testRecover() - { - if (!isBroker08()) - { - Xid xid1 = getNewXid(); - String durSubName = "test1"; - try - { - // create a dummy durable subscriber to be sure that messages are persisted! - _nonXASession.createDurableSubscriber(_topic, durSubName); - // start the xaResource for xid1 - try - { - _xaResource.start(xid1, XAResource.TMNOFLAGS); - } - catch (XAException e) - { - fail("cannot start the transaction with xid1: " + e.getMessage()); - } - try - { - // start the connection - _topicConnection.start(); - // produce a message with sequence number 1 - _message.setLongProperty(_sequenceNumberPropertyName, 1); - _producer.send(_message); - } - catch (JMSException e) - { - fail(" cannot send persistent message: " + e.getMessage()); - } - // suspend the transaction - try - { - _xaResource.end(xid1, XAResource.TMSUCCESS); - } - catch (XAException e) - { - fail("Cannot end the transaction with xid1: " + e.getMessage()); - } - // prepare the transaction with xid1 - try - { - _xaResource.prepare(xid1); - } - catch (XAException e) - { - fail("Exception when preparing xid1: " + e.getMessage()); - } - - /////// stop the server now !! - try - { - restartBroker(); - init(); - } - catch (Exception e) - { - fail("Exception when stopping and restarting the server"); - } - - try - { - MessageConsumer nonXAConsumer = _nonXASession.createDurableSubscriber(_topic, durSubName); - _topicConnection.start(); - // get the list of in doubt transactions - try - { - Xid[] inDoubt = _xaResource.recover(XAResource.TMSTARTRSCAN); - if (inDoubt == null) - { - fail("the array of in doubt transactions should not be null "); - } - // At that point we expect only two indoubt transactions: - if (inDoubt.length != 1) - { - fail("in doubt transaction size is diffenrent thatn 2, there are " + inDoubt.length + "in doubt transactions"); - } - // commit them - for (Xid anInDoubt : inDoubt) - { - if (anInDoubt.equals(xid1)) - { - _logger.debug("committing xid1 "); - try - { - _xaResource.commit(anInDoubt, false); - } - catch (Exception e) - { - _logger.error("PB when aborted xid1"); - fail("exception when committing xid1 "); - } - } - else - { - _logger.debug("XID1 is not in doubt "); - } - } - } - catch (XAException e) - { - _logger.error("exception thrown when recovering transactions ", e); - fail("exception thrown when recovering transactions " + e.getMessage()); - } - _logger.debug("the topic should not be empty"); - TextMessage message1 = (TextMessage) nonXAConsumer.receive(1000); - if (message1 == null) - { - fail("The topic is empty! "); - } - } - catch (Exception e) - { - _logger.error("Exception thrown when testin that queue test is empty", e); - fail("Exception thrown when testin that queue test is empty: " + e.getMessage()); - } - } - catch (JMSException e) - { - _logger.error("cannot create dummy durable subscriber", e); - fail("cannot create dummy durable subscriber: " + e.getMessage()); - } - finally - { - try - { - // unsubscribe the dummy durable subscriber - TopicSession nonXASession = _nonXASession; - nonXASession.unsubscribe(durSubName); - } - catch (JMSException e) - { - fail("cannot unsubscribe durable subscriber: " + e.getMessage()); - } - } - } - } - - /** - * strategy: - * create a standard durable subscriber - * produce 3 messages - * consume the first message with that durable subscriber - * close the standard session that deactivates the durable subscriber - * migrate the durable subscriber to an xa one - * consume the second message with that xa durable subscriber - * close the xa session that deactivates the durable subscriber - * reconnect to the durable subscriber with a standard session - * consume the two remaining messages and check that the topic is empty! - */ - public void testMigrateDurableSubscriber() - { - if (!isBroker08()) - { - Xid xid1 = getNewXid(); - Xid xid2 = getNewXid(); - String durSubName = "DurableSubscriberMigrate"; - try - { - Session stSession = _nonXASession; - MessageProducer producer = stSession.createProducer(_topic); - _logger.debug("Create a standard durable subscriber!"); - TopicSubscriber durSub = stSession.createDurableSubscriber(_topic, durSubName); - TopicSubscriber durSub1 = stSession.createDurableSubscriber(_topic, durSubName + "_second"); - TextMessage message; - producer.setDeliveryMode(DeliveryMode.PERSISTENT); - _topicConnection.start(); - _logger.debug("produce 3 messages"); - for (int i = 1; i <= 3; i++) - { - _message.setLongProperty(_sequenceNumberPropertyName, i); - //producer.send( _message ); - producer.send(_message, DeliveryMode.PERSISTENT, 9 - i, 0); - stSession.commit(); - } - _logger.debug("consume the first message with that durable subscriber"); - message = (TextMessage) durSub.receive(1000); - if (message == null) - { - fail("no message received "); - } - else if (message.getLongProperty(_sequenceNumberPropertyName) != 1) - { - fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); - } - // commit the standard session - stSession.commit(); - _logger.debug("first message consumed "); - // close the session that deactivates the durable subscriber - stSession.close(); - _logger.debug("migrate the durable subscriber to an xa one"); - _xaResource.start(xid1, XAResource.TMNOFLAGS); - durSub = _session.createDurableSubscriber(_topic, durSubName); - _logger.debug(" consume the second message with that xa durable subscriber and abort it"); - message = (TextMessage) durSub.receive(1000); - if (message == null) - { - fail("no message received "); - } - else if (message.getLongProperty(_sequenceNumberPropertyName) != 2) - { - _logger.info("wrong sequence number, 2 expected, received: " + message - .getLongProperty(_sequenceNumberPropertyName)); - } - _xaResource.end(xid1, XAResource.TMSUCCESS); - _xaResource.prepare(xid1); - _xaResource.rollback(xid1); - _logger.debug("close the session that deactivates the durable subscriber"); - _session.close(); - _logger.debug("create a new standard session"); - stSession = _topicConnection.createTopicSession(true, 1); - _logger.debug("reconnect to the durable subscriber"); - durSub = stSession.createDurableSubscriber(_topic, durSubName); - durSub1 = stSession.createDurableSubscriber(_topic, durSubName + "_second"); - _logger.debug("Reconnected to durablse subscribers"); - _logger.debug(" consume the 2 remaining messages"); - message = (TextMessage) durSub.receive(1000); - if (message == null) - { - fail("no message received "); - } - else if (message.getLongProperty(_sequenceNumberPropertyName) != 2) - { - _logger.info("wrong sequence number, 2 expected, received: " + message - .getLongProperty(_sequenceNumberPropertyName)); - } - // consume the third message with that xa durable subscriber - message = (TextMessage) durSub.receive(1000); - if (message == null) - { - fail("no message received "); - } - else if (message.getLongProperty(_sequenceNumberPropertyName) != 3) - { - _logger.info("wrong sequence number, 3 expected, received: " + message - .getLongProperty(_sequenceNumberPropertyName)); - } - stSession.commit(); - _logger.debug("the topic should be empty now"); - message = (TextMessage) durSub.receive(1000); - if (message != null) - { - fail("Received unexpected message "); - } - stSession.commit(); - _logger.debug(" use dursub1 to receive all the 3 messages"); - for (int i = 1; i <= 3; i++) - { - message = (TextMessage) durSub1.receive(1000); - if (message == null) - { - _logger.debug("no message received "); - } - else if (message.getLongProperty(_sequenceNumberPropertyName) != i) - { - fail("wrong sequence number, " + i + " expected, received: " + message - .getLongProperty(_sequenceNumberPropertyName)); - } - } - stSession.commit(); - // send a non persistent message to check that all persistent messages are deleted - producer = stSession.createProducer(_topic); - producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); - producer.send(_message); - stSession.commit(); - message = (TextMessage) durSub.receive(1000); - if (message == null) - { - fail("message not received "); - } - message = (TextMessage) durSub1.receive(1000); - if (message == null) - { - fail("message not received "); - } - stSession.commit(); - stSession.close(); - _logger.debug(" now create a standard non transacted session and reconnect to the durable xubscriber"); - TopicConnection stConnection = - _topicConnection; //_topicFactory.createTopicConnection("guest", "guest"); - TopicSession autoAclSession = stConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); - TopicPublisher publisher = autoAclSession.createPublisher(_topic); - durSub = autoAclSession.createDurableSubscriber(_topic, durSubName); - stConnection.start(); - // produce 3 persistent messages - for (int i = 1; i <= 3; i++) - { - _message.setLongProperty(_sequenceNumberPropertyName, i); - //producer.send( _message ); - publisher.send(_message, DeliveryMode.PERSISTENT, 9 - i, 0); - } - _logger.debug(" use dursub to receive all the 3 messages"); - for (int i = 1; i <= 3; i++) - { - message = (TextMessage) durSub.receive(1000); - if (message == null) - { - _logger.info("no message received "); - } - else if (message.getLongProperty(_sequenceNumberPropertyName) != i) - { - _logger.info("wrong sequence number, " + i + " expected, received: " + message - .getLongProperty(_sequenceNumberPropertyName)); - } - } - - _logger.debug("now set a message listener"); - AtomicBoolean lock = new AtomicBoolean(true); - reset(); - stConnection.stop(); - durSub.setMessageListener(new TopicListener(1, 3, lock)); - _logger.debug(" produce 3 persistent messages"); - for (int i = 1; i <= 3; i++) - { - _message.setLongProperty(_sequenceNumberPropertyName, i); - //producer.send( _message ); - publisher.send(_message, DeliveryMode.PERSISTENT, 9 - i, 0); - } - // start the connection - stConnection.start(); - while (lock.get()) - { - synchronized (lock) - { - lock.wait(); - } - } - if (getFailureStatus()) - { - fail("problem with message listener"); - } - stConnection.stop(); - durSub.setMessageListener(null); - _logger.debug(" do the same with an xa session"); - // produce 3 persistent messages - for (int i = 1; i <= 3; i++) - { - _message.setLongProperty(_sequenceNumberPropertyName, i); - //producer.send( _message ); - publisher.send(_message, DeliveryMode.PERSISTENT, 9 - i, 0); - } - //stConnection.close(); - autoAclSession.close(); - _logger.debug(" migrate the durable subscriber to an xa one"); - _session = _topicConnection.createXATopicSession(); - _xaResource = _session.getXAResource(); - _xaResource.start(xid2, XAResource.TMNOFLAGS); - durSub = _session.createDurableSubscriber(_topic, durSubName); - lock = new AtomicBoolean(); - reset(); - _topicConnection.stop(); - durSub.setMessageListener(new TopicListener(1, 3, lock)); - // start the connection - _topicConnection.start(); - while (lock.get()) - { - synchronized (lock) - { - lock.wait(); - } - } - if (getFailureStatus()) - { - fail("problem with XA message listener"); - } - _xaResource.end(xid2, XAResource.TMSUCCESS); - _xaResource.commit(xid2, true); - _session.close(); - } - catch (Exception e) - { - _logger.error("Exception thrown", e); - fail("Exception thrown: " + e.getMessage()); - } - finally - { - try - { - _topicConnection.createXASession().unsubscribe(durSubName); - _topicConnection.createXASession().unsubscribe(durSubName + "_second"); - } - catch (JMSException e) - { - fail("Exception thrown when unsubscribing durable subscriber " + e.getMessage()); - } - } - } - } - - /** -------------------------------------------------------------------------------------- **/ - /** ----------------------------- Utility methods --------------------------------------- **/ - /** -------------------------------------------------------------------------------------- **/ - - /** - * get a new queue connection - * - * @return a new queue connection - * @throws javax.jms.JMSException If the JMS provider fails to create the queue connection - * due to some internal error or in case of authentication failure - */ - private XATopicConnection getNewTopicXAConnection() throws JMSException - { - return _topicFactory.createXATopicConnection("guest", "guest"); - } - - public static void failure() - { - _failure = true; - } - - public static void reset() - { - _failure = false; - } - - public static boolean getFailureStatus() - { - return _failure; - } - - private class TopicListener implements MessageListener - { - private long _counter; - private long _end; - private final AtomicBoolean _lock; - - public TopicListener(long init, long end, AtomicBoolean lock) - { - _counter = init; - _end = end; - _lock = lock; - } - - public void onMessage(Message message) - { - long seq = 0; - try - { - seq = message.getLongProperty(TopicTest._sequenceNumberPropertyName); - } - catch (JMSException e) - { - _logger.error("Error getting long property: " + TopicTest._sequenceNumberPropertyName , e); - TopicTest.failure(); - _lock.set(false); - synchronized (_lock) - { - _lock.notifyAll(); - } - } - if (seq != _counter) - { - _logger.info("received message " + seq + " expected " + _counter); - TopicTest.failure(); - _lock.set(false); - synchronized (_lock) - { - _lock.notifyAll(); - } - } - _counter++; - if (_counter > _end) - { - _lock.set(false); - synchronized (_lock) - { - _lock.notifyAll(); - } - } - } - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/BrokerCommandHelperTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/BrokerCommandHelperTest.java deleted file mode 100644 index 83c2f1e58d..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/BrokerCommandHelperTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.test.utils; - -import static org.mockito.Mockito.*; - -import java.io.File; - -public class BrokerCommandHelperTest extends QpidTestCase -{ - private static final String PATH_TO_QPID_EXECUTABLE = "/path / to (/qpid"; - private static final String ARGUMENT_WITH_SPACES = " blah / blah /blah"; - private static final String ARGUMENT_PORT = "-p"; - private static final String ARGUMENT_PORT_VALUE = "@PORT"; - private static final String ARGUMENT_STORE_PATH = "-sp"; - private static final String ARGUMENT_STORE_PATH_VALUE = "@STORE_PATH"; - private static final String ARGUMENT_STORE_TYPE = "-st"; - private static final String ARGUMENT_STORE_TYPE_VALUE = "@STORE_TYPE"; - private static final String ARGUMENT_LOG = "-l"; - private static final String ARGUMENT_LOG_VALUE = "@LOG_CONFIG_FILE"; - - private BrokerCommandHelper _brokerCommandHelper; - - private File _logConfigFile = mock(File.class); - - @Override - public void setUp() - { - when(_logConfigFile.getAbsolutePath()).thenReturn("log Config File"); - _brokerCommandHelper = new BrokerCommandHelper("\"" + PATH_TO_QPID_EXECUTABLE + "\" " + ARGUMENT_PORT + " " - + ARGUMENT_PORT_VALUE + " " + ARGUMENT_STORE_PATH + " " + ARGUMENT_STORE_PATH_VALUE + " " + ARGUMENT_STORE_TYPE - + " " + ARGUMENT_STORE_TYPE_VALUE + " " + ARGUMENT_LOG + " " + ARGUMENT_LOG_VALUE + " '" + ARGUMENT_WITH_SPACES - + "'"); - } - - public void testGetBrokerCommand() - { - String[] brokerCommand = _brokerCommandHelper.getBrokerCommand(1, "path to config file", "json", _logConfigFile); - - String[] expected = { PATH_TO_QPID_EXECUTABLE, ARGUMENT_PORT, "1", ARGUMENT_STORE_PATH, "path to config file", - ARGUMENT_STORE_TYPE, "json", ARGUMENT_LOG, "\"log Config File\"", ARGUMENT_WITH_SPACES }; - assertEquals("Unexpected broker command", expected.length, brokerCommand.length); - for (int i = 0; i < expected.length; i++) - { - assertEquals("Unexpected command part value at " + i,expected[i], brokerCommand[i] ); - } - } - - public void testRemoveBrokerCommandLog4JFile() - { - _brokerCommandHelper.removeBrokerCommandLog4JFile(); - String[] brokerCommand = _brokerCommandHelper.getBrokerCommand(1, "configFile", "json", _logConfigFile); - - String[] expected = { PATH_TO_QPID_EXECUTABLE, ARGUMENT_PORT, "1", ARGUMENT_STORE_PATH, "configFile", - ARGUMENT_STORE_TYPE, "json", ARGUMENT_WITH_SPACES }; - - assertEquals("Unexpected broker command", expected.length, brokerCommand.length); - for (int i = 0; i < expected.length; i++) - { - assertEquals("Unexpected command part value at " + i,expected[i], brokerCommand[i] ); - } - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/ConversationFactory.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/ConversationFactory.java deleted file mode 100644 index 3a9354d822..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/ConversationFactory.java +++ /dev/null @@ -1,484 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.utils; - -import org.apache.log4j.Logger; - -import javax.jms.Connection; -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 java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - -/** - * A conversation helper, uses a message correlation id pattern to match up sent and received messages as a conversation - * over JMS messaging. Incoming message traffic is divided up by correlation id. Each id has a queue (behaviour dependant - * on the queue implementation). Clients of this de-multiplexer can wait on messages, defined by message correlation ids. - * - *

One use of this is as a conversation synchronizer where multiple threads are carrying out conversations over a - * multiplexed messaging route. This can be usefull, as JMS sessions are not multi-threaded. Setting up the conversation - * with synchronous queues will allow these threads to be written in a synchronous style, but with their execution order - * governed by the asynchronous message flow. For example, something like the following code could run a multi-threaded - * conversation (the conversation methods can be called many times in parallel): - * - *

- * class Initiator
- * {
- * ConversationHelper conversation = new ConversationHelper(connection, null,
- *                                                          java.util.concurrent.LinkedBlockingQueue.class);
- *
- * initiateConversation()
- * {
- *  try {
- *   // Exchange greetings.
- *   conversation.send(sendDestination, conversation.getSession().createTextMessage("Hello."));
- *   Message greeting = conversation.receive();
- *
- *   // Exchange goodbyes.
- *   conversation.send(conversation.getSession().createTextMessage("Goodbye."));
- *   Message goodbye = conversation.receive();
- *  } finally {
- *   conversation.end();
- *  }
- * }
- * }
- *
- * class Responder
- * {
- * ConversationHelper conversation = new ConversationHelper(connection, receiveDestination,
- *                                                          java.util.concurrent.LinkedBlockingQueue.class);
- *
- * respondToConversation()
- * {
- *   try {
- *   // Exchange greetings.
- *   Message greeting = conversation.receive();
- *   conversation.send(conversation.getSession().createTextMessage("Hello."));
- *
- *   // Exchange goodbyes.
- *   Message goodbye = conversation.receive();
- *   conversation.send(conversation.getSession().createTextMessage("Goodbye."));
- *  } finally {
- *   conversation.end();
- *  }
- * }
- * }
- * 
- * - *

Conversation correlation id's are generated on a per thread basis. - * - *

The same controlSession is shared amongst all conversations. Calls to send are therefore synchronized because JMS - * sessions are not multi-threaded. - * - *

- *
CRC Card
Responsibilities Collaborations - *
Associate messages to an ongoing conversation using correlation ids. - *
Auto manage sessions for conversations. - *
Store messages not in a conversation in dead letter box. - *
- */ -public class ConversationFactory -{ - /** Used for debugging. */ - private static final Logger log = Logger.getLogger(ConversationFactory.class); - - /** Holds a map from correlation id's to queues. */ - private Map> idsToQueues = new HashMap>(); - - /** Holds the connection over which the conversation is conducted. */ - private Connection connection; - - /** Holds the controlSession over which the conversation is conduxted. */ - private Session session; - - /** The message consumer for incoming messages. */ - private MessageConsumer consumer; - - /** The message producer for outgoing messages. */ - private MessageProducer producer; - - /** The well-known or temporary destination to receive replies on. */ - private Destination receiveDestination; - - /** Holds the queue implementation class for the reply queue. */ - private Class queueClass; - - /** Used to hold any replies that are received outside of the context of a conversation. */ - private BlockingQueue deadLetterBox = new LinkedBlockingQueue(); - - /* Used to hold conversation state on a per thread basis. */ - /* - ThreadLocal threadLocals = - new ThreadLocal() - { - protected Conversation initialValue() - { - Conversation settings = new Conversation(); - settings.conversationId = conversationIdGenerator.getAndIncrement(); - - return settings; - } - }; - */ - - /** Generates new coversation id's as needed. */ - private AtomicLong conversationIdGenerator = new AtomicLong(); - - /** - * Creates a conversation helper on the specified connection with the default sending destination, and listening - * to the specified receiving destination. - * - * @param connection The connection to build the conversation helper on. - * @param receiveDestination The destination to listen to for incoming messages. This may be null to use a temporary - * queue. - * @param queueClass The queue implementation class. - * - * @throws JMSException All underlying JMSExceptions are allowed to fall through. - */ - public ConversationFactory(Connection connection, Destination receiveDestination, - Class queueClass) throws JMSException - { - log.debug("public ConversationFactory(Connection connection, Destination receiveDestination = " + receiveDestination - + ", Class queueClass = " + queueClass + "): called"); - - this.connection = connection; - this.queueClass = queueClass; - - session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - - // Check if a well-known receive destination has been provided, or use a temporary queue if not. - this.receiveDestination = (receiveDestination != null) ? receiveDestination : session.createTemporaryQueue(); - - consumer = session.createConsumer(receiveDestination); - producer = session.createProducer(null); - - consumer.setMessageListener(new Receiver()); - } - - /** - * Creates a new conversation context. - * - * @return A new conversation context. - */ - public Conversation startConversation() - { - log.debug("public Conversation startConversation(): called"); - - Conversation conversation = new Conversation(); - conversation.conversationId = conversationIdGenerator.getAndIncrement(); - - return conversation; - } - - /** - * Ensures that the reply queue for a conversation exists. - * - * @param conversationId The conversation correlation id. - */ - private void initQueueForId(long conversationId) - { - if (!idsToQueues.containsKey(conversationId)) - { - idsToQueues.put(conversationId, ReflectionUtils.newInstance(queueClass)); - } - } - - /** - * Clears the dead letter box, returning all messages that were in it. - * - * @return All messages in the dead letter box. - */ - public Collection emptyDeadLetterBox() - { - log.debug("public Collection emptyDeadLetterBox(): called"); - - Collection result = new ArrayList(); - deadLetterBox.drainTo(result); - - return result; - } - - /** - * Gets the controlSession over which the conversation is conducted. - * - * @return The controlSession over which the conversation is conducted. - */ - public Session getSession() - { - // Conversation settings = threadLocals.get(); - - return session; - } - - /** - * Used to hold a conversation context. This consists of a correlating id for the conversation, and a reply - * destination automatically updated to the last received reply-to destination. - */ - public class Conversation - { - /** Holds the correlation id for the context. */ - private long conversationId; - - /** - * Holds the send destination for the context. This will automatically be updated to the most recently received - * reply-to destination. - */ - private Destination sendDestination; - - /** - * Sends a message to the default sending location. The correlation id of the message will be assigned by this - * method, overriding any previously set value. - * - * @param sendDestination The destination to send to. This may be null to use the last received reply-to - * destination. - * @param message The message to send. - * - * @throws JMSException All undelying JMSExceptions are allowed to fall through. This will also be thrown if no - * send destination is specified and there is no most recent reply-to destination available - * to use. - */ - public void send(Destination sendDestination, Message message) throws JMSException - { - log.debug("public void send(Destination sendDestination = " + sendDestination + ", Message message = " - + message.getJMSMessageID() + "): called"); - - // Conversation settings = threadLocals.get(); - // long conversationId = conversationId; - message.setJMSCorrelationID(Long.toString(conversationId)); - message.setJMSReplyTo(receiveDestination); - - // Ensure that the reply queue for this conversation exists. - initQueueForId(conversationId); - - // Check if an overriding send to destination has been set or use the last reply-to if not. - Destination sendTo = null; - - if (sendDestination != null) - { - sendTo = sendDestination; - } - else - { - throw new JMSException("The send destination was specified, and no most recent reply-to available to use."); - } - - // Send the message. - synchronized (this) - { - producer.send(sendTo, message); - } - } - - /** - * Gets the next message in an ongoing conversation. This method may block until such a message is received. - * - * @return The next incoming message in the conversation. - * - * @throws JMSException All undelying JMSExceptions are allowed to fall through. Thrown if the received message - * did not have its reply-to destination set up. - */ - public Message receive() throws JMSException - { - log.debug("public Message receive(): called"); - - // Conversation settings = threadLocals.get(); - // long conversationId = settings.conversationId; - - // Ensure that the reply queue for this conversation exists. - initQueueForId(conversationId); - - BlockingQueue queue = idsToQueues.get(conversationId); - - try - { - Message result = queue.take(); - - // Keep the reply-to destination to send replies to. - sendDestination = result.getJMSReplyTo(); - - return result; - } - catch (InterruptedException e) - { - return null; - } - } - - /** - * Gets many messages in an ongoing conversation. If a limit is specified, then once that many messages are - * received they will be returned. If a timeout is specified, then all messages up to the limit, received within - * that timespan will be returned. At least one of the message count or timeout should be set to a value of - * 1 or greater. - * - * @param num The number of messages to receive, or all if this is less than 1. - * @param timeout The timeout in milliseconds to receive the messages in, or forever if this is less than 1. - * - * @return All messages received within the count limit and the timeout. - * - * @throws JMSException All undelying JMSExceptions are allowed to fall through. - */ - public Collection receiveAll(int num, long timeout) throws JMSException - { - log.debug("public Collection receiveAll(int num = " + num + ", long timeout = " + timeout - + "): called"); - - // Check that a timeout or message count was set. - if ((num < 1) && (timeout < 1)) - { - throw new IllegalArgumentException("At least one of message count (num) or timeout must be set."); - } - - // Ensure that the reply queue for this conversation exists. - initQueueForId(conversationId); - BlockingQueue queue = idsToQueues.get(conversationId); - - // Used to collect the received messages in. - Collection result = new ArrayList(); - - // Used to indicate when the timeout or message count has expired. - boolean receiveMore = true; - - int messageCount = 0; - - // Receive messages until the timeout or message count expires. - do - { - try - { - Message next = null; - - // Try to receive the message with a timeout if one has been set. - if (timeout > 0) - { - next = queue.poll(timeout, TimeUnit.MILLISECONDS); - - // Check if the timeout expired, and stop receiving if so. - if (next == null) - { - receiveMore = false; - } - } - // Receive the message without a timeout. - else - { - next = queue.take(); - } - - // Increment the message count if a message was received. - messageCount += (next != null) ? 1 : 0; - - // Check if all the requested messages were received, and stop receiving if so. - if ((num > 0) && (messageCount >= num)) - { - receiveMore = false; - } - - // Keep the reply-to destination to send replies to. - sendDestination = (next != null) ? next.getJMSReplyTo() : sendDestination; - - if (next != null) - { - result.add(next); - } - } - catch (InterruptedException e) - { - // Restore the threads interrupted status. - Thread.currentThread().interrupt(); - - // Stop receiving but return the messages received so far. - receiveMore = false; - } - } - while (receiveMore); - - return result; - } - - /** - * Completes the conversation. Any correlation id's pertaining to the conversation are no longer valid, and any - * incoming messages using them will go to the dead letter box. - */ - public void end() - { - log.debug("public void end(): called"); - - // Ensure that the thread local for the current thread is cleaned up. - // Conversation settings = threadLocals.get(); - // long conversationId = settings.conversationId; - // threadLocals.remove(); - - // Ensure that its queue is removed from the queue map. - BlockingQueue queue = idsToQueues.remove(conversationId); - - // Move any outstanding messages on the threads conversation id into the dead letter box. - queue.drainTo(deadLetterBox); - } - } - - /** - * Implements the message listener for this conversation handler. - */ - protected class Receiver implements MessageListener - { - /** - * Handles all incoming messages in the ongoing conversations. These messages are split up by correaltion id - * and placed into queues. - * - * @param message The incoming message. - */ - public void onMessage(Message message) - { - log.debug("public void onMessage(Message message = " + message + "): called"); - - try - { - Long conversationId = Long.parseLong(message.getJMSCorrelationID()); - - // Find the converstaion queue to place the message on. If there is no conversation for the message id, - // the the dead letter box queue is used. - BlockingQueue queue = idsToQueues.get(conversationId); - queue = (queue == null) ? deadLetterBox : queue; - - queue.put(message); - } - catch (JMSException e) - { - throw new RuntimeException(e); - } - catch (InterruptedException e) - { - throw new RuntimeException(e); - } - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java deleted file mode 100644 index f6c481431a..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.utils; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQConnectionFactory; -import org.apache.qpid.util.FileUtils; - -import javax.naming.NamingException; - -public class FailoverBaseCase extends QpidBrokerTestCase -{ - protected static final Logger _logger = LoggerFactory.getLogger(FailoverBaseCase.class); - - public static final long DEFAULT_FAILOVER_TIME = 10000L; - - protected void setUp() throws java.lang.Exception - { - super.setUp(); - startBroker(getFailingPort()); - } - - /** - * We are using failover factories - * - * @return a connection - * @throws Exception - */ - @Override - public AMQConnectionFactory getConnectionFactory() throws NamingException - { - _logger.info("get ConnectionFactory"); - if (_connectionFactory == null) - { - if (Boolean.getBoolean("profile.use_ssl")) - { - _connectionFactory = getConnectionFactory("failover.ssl"); - } - else - { - _connectionFactory = getConnectionFactory("failover"); - } - } - return _connectionFactory; - } - - public void tearDown() throws Exception - { - try - { - super.tearDown(); - } - finally - { - // Ensure we shutdown any secondary brokers, even if we are unable - // to cleanly tearDown the QTC. - stopBroker(getFailingPort()); - FileUtils.deleteDirectory(System.getProperty("QPID_WORK") + "/" + getFailingPort()); - } - } - - public void failBroker(int port) - { - try - { - //TODO: use killBroker instead - stopBroker(port); - } - catch (Exception e) - { - throw new RuntimeException(e); - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java index 82fcadfcf9..0f558f3abe 100755 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java @@ -848,7 +848,7 @@ public class QpidBrokerTestCase extends QpidTestCase * @param brokerPort broker port * @param virtualHostNodeName virtual host node name */ - protected void createTestVirtualHostNode(int brokerPort, String virtualHostNodeName) + protected void createTestVirtualHostNode(int brokerPort, String virtualHostNodeName, boolean withBlueprint) { String storeType = getTestProfileVirtualHostNodeType(); String storeDir = null; @@ -871,15 +871,24 @@ public class QpidBrokerTestCase extends QpidTestCase attributes.put(JsonVirtualHostNode.STORE_PATH, storeDir); } - final String blueprint = getTestProfileVirtualHostNodeBlueprint(); + if (withBlueprint) + { + final String blueprint = getTestProfileVirtualHostNodeBlueprint(); - attributes.put(ConfiguredObject.CONTEXT, Collections.singletonMap(AbstractVirtualHostNode.VIRTUALHOST_BLUEPRINT_CONTEXT_VAR, - blueprint)); + attributes.put(ConfiguredObject.CONTEXT, + Collections.singletonMap(AbstractVirtualHostNode.VIRTUALHOST_BLUEPRINT_CONTEXT_VAR, + blueprint)); + } int port = getPort(brokerPort); getBrokerConfiguration(port).addObjectConfiguration(VirtualHostNode.class, attributes); } + protected void createTestVirtualHostNode(int brokerPort, String virtualHostNodeName) + { + createTestVirtualHostNode(brokerPort, virtualHostNodeName, true); + } + /** * Set a System property that is to be applied only to the external test * broker. diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidClientConnection.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidClientConnection.java deleted file mode 100644 index 0e0032da64..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidClientConnection.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ - -package org.apache.qpid.test.utils; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.JMSAMQException; - -import javax.jms.Connection; -import javax.jms.ExceptionListener; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.Session; -import javax.jms.TextMessage; - -public class QpidClientConnection extends QpidBrokerTestCase implements ExceptionListener -{ - private static final Logger _logger = LoggerFactory.getLogger(QpidClientConnection.class); - - private boolean transacted = true; - private int ackMode = Session.CLIENT_ACKNOWLEDGE; - private Connection connection; - - private String virtualHost; - private String brokerlist; - private int prefetch; - protected Session session; - protected boolean connected; - - public QpidClientConnection(String broker) - { - super(); - setVirtualHost("/test"); - setBrokerList(broker); - setPrefetch(5000); - } - - - public Connection getConnection() - { - return connection; - } - - public void connect() throws JMSException - { - if (!connected) - { - /* - * amqp://[user:pass@][clientid]/virtualhost? - * brokerlist='[transport://]host[:port][?option='value'[&option='value']];' - * [&failover='method[?option='value'[&option='value']]'] - * [&option='value']" - */ - String brokerUrl = "amqp://guest:guest@" + virtualHost + "?brokerlist='" + brokerlist + "'"; - try - { - _logger.info("connecting to Qpid :" + brokerUrl); - connection = getConnection("guest", "guest") ; - // register exception listener - connection.setExceptionListener(this); - - session = ((AMQConnection) connection).createSession(transacted, ackMode, prefetch); - - _logger.info("starting connection"); - connection.start(); - - connected = true; - } - catch (Exception e) - { - throw new JMSAMQException("URL syntax error in [" + brokerUrl + "]: " + e.getMessage(), e); - } - } - } - - public void disconnect() throws Exception - { - if (connected) - { - session.commit(); - session.close(); - connection.close(); - connected = false; - _logger.info("disconnected"); - } - } - - public void disconnectWithoutCommit() throws JMSException - { - if (connected) - { - session.close(); - connection.close(); - connected = false; - _logger.info("disconnected without commit"); - } - } - - public String getBrokerList() - { - return brokerlist; - } - - public void setBrokerList(String brokerlist) - { - this.brokerlist = brokerlist; - } - - public String getVirtualHost() - { - return virtualHost; - } - - public void setVirtualHost(String virtualHost) - { - this.virtualHost = virtualHost; - } - - public void setPrefetch(int prefetch) - { - this.prefetch = prefetch; - } - - /** override as necessary */ - public void onException(JMSException exception) - { - _logger.info("ExceptionListener event: error " + exception.getErrorCode() + ", message: " + exception.getMessage()); - } - - public boolean isConnected() - { - return connected; - } - - public Session getSession() - { - return session; - } - - /** - * Put a String as a text messages, repeat n times. A null payload will result in a null message. - * - * @param queueName The queue name to put to - * @param payload the content of the payload - * @param copies the number of messages to put - * - * @throws javax.jms.JMSException any exception that occurs - */ - public void put(String queueName, String payload, int copies) throws JMSException - { - if (!connected) - { - connect(); - } - - _logger.info("putting to queue " + queueName); - Queue queue = session.createQueue(queueName); - - final MessageProducer sender = session.createProducer(queue); - - for (int i = 0; i < copies; i++) - { - Message m = session.createTextMessage(payload + i); - m.setIntProperty("index", i + 1); - sender.send(m); - } - - session.commit(); - sender.close(); - _logger.info("put " + copies + " copies"); - } - - /** - * GET the top message on a queue. Consumes the message. Accepts timeout value. - * - * @param queueName The quename to get from - * @param readTimeout The timeout to use - * - * @return the content of the text message if any - * - * @throws javax.jms.JMSException any exception that occured - */ - public Message getNextMessage(String queueName, long readTimeout) throws JMSException - { - if (!connected) - { - connect(); - } - - Queue queue = session.createQueue(queueName); - - final MessageConsumer consumer = session.createConsumer(queue); - - Message message = consumer.receive(readTimeout); - session.commit(); - consumer.close(); - - Message result; - - // all messages we consume should be TextMessages - if (message instanceof TextMessage) - { - result = ((TextMessage) message); - } - else if (null == message) - { - result = null; - } - else - { - _logger.info("warning: received non-text message"); - result = message; - } - - return result; - } - - /** - * GET the top message on a queue. Consumes the message. - * - * @param queueName The Queuename to get from - * - * @return The string content of the text message, if any received - * - * @throws javax.jms.JMSException any exception that occurs - */ - public Message getNextMessage(String queueName) throws JMSException - { - return getNextMessage(queueName, 0); - } - - /** - * Completely clears a queue. For readTimeout behaviour see Javadocs for javax.jms.MessageConsumer. - * - * @param queueName The Queue name to consume from - * @param readTimeout The timeout for each consume - * - * @throws javax.jms.JMSException Any exception that occurs during the consume - * @throws InterruptedException If the consume thread was interrupted during a consume. - */ - public void consume(String queueName, int readTimeout) throws JMSException, InterruptedException - { - if (!connected) - { - connect(); - } - - _logger.info("consuming queue " + queueName); - Queue queue = session.createQueue(queueName); - - final MessageConsumer consumer = session.createConsumer(queue); - int messagesReceived = 0; - - _logger.info("consuming..."); - while ((consumer.receive(readTimeout)) != null) - { - messagesReceived++; - } - - session.commit(); - consumer.close(); - _logger.info("consumed: " + messagesReceived); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/SpawnedBrokerHolder.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/SpawnedBrokerHolder.java index 507c994076..4b747e869c 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/SpawnedBrokerHolder.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/SpawnedBrokerHolder.java @@ -85,62 +85,61 @@ public class SpawnedBrokerHolder implements BrokerHolder try { Process p = Runtime.getRuntime().exec(new String[] {"wmic", "process", "list"}); - BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); - String line; - String headers = reader.readLine(); - int processIdOffset = headers.indexOf(" ProcessId") + 1; - int parentProcessIdOffset = headers.indexOf(" ParentProcessId") + 1; - String parentProcess = null; - Map> parentProcessMap = new HashMap>(); - - while ((line = reader.readLine()) != null) + try(BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()))) { - if(line.length() > processIdOffset) - { - String processIdStr = line.substring(processIdOffset); - processIdStr = processIdStr.substring(0, processIdStr.indexOf(' ')); - processIdStr = processIdStr.trim(); + String line; + String headers = reader.readLine(); + int processIdOffset = headers.indexOf(" ProcessId") + 1; + int parentProcessIdOffset = headers.indexOf(" ParentProcessId") + 1; + String parentProcess = null; + Map> parentProcessMap = new HashMap>(); - String parentProcessIdStr = line.substring(parentProcessIdOffset); - parentProcessIdStr = parentProcessIdStr.substring(0, parentProcessIdStr.indexOf(' ')); - parentProcessIdStr = parentProcessIdStr.trim(); - if(parentProcessIdStr.length() > 0 && (parentProcess == null || parentProcess.equals(parentProcessIdStr))) + while ((line = reader.readLine()) != null) + { + if (line.length() > processIdOffset) { - List children = parentProcessMap.get(parentProcessIdStr); - if(children == null) + String processIdStr = line.substring(processIdOffset); + processIdStr = processIdStr.substring(0, processIdStr.indexOf(' ')); + processIdStr = processIdStr.trim(); + + String parentProcessIdStr = line.substring(parentProcessIdOffset); + parentProcessIdStr = parentProcessIdStr.substring(0, parentProcessIdStr.indexOf(' ')); + parentProcessIdStr = parentProcessIdStr.trim(); + if (parentProcessIdStr.length() > 0 && (parentProcess == null || parentProcess.equals( + parentProcessIdStr))) { - children = new ArrayList(); - parentProcessMap.put(parentProcessIdStr,children); + List children = parentProcessMap.get(parentProcessIdStr); + if (children == null) + { + children = new ArrayList(); + parentProcessMap.put(parentProcessIdStr, children); + } + children.add(processIdStr); + } + if (line.substring(0, _brokerCommand.length() + 7) + .toLowerCase() + .contains(_brokerCommand.toLowerCase())) + { + parentProcess = processIdStr; } - children.add(processIdStr); - } - if(line.substring(0,_brokerCommand.length()+7).toLowerCase().contains(_brokerCommand.toLowerCase())) - { - parentProcess = processIdStr; - } - } - if(parentProcess != null) - { - List children = parentProcessMap.get(parentProcess); - if(children != null) + } + if (parentProcess != null) { - for(String child : children) + List children = parentProcessMap.get(parentProcess); + if (children != null) { - p = Runtime.getRuntime().exec(new String[] {"taskkill", "/PID", child, "/T", "/F"}); - reader = new BufferedReader(new InputStreamReader(p.getInputStream())); - while((line = reader.readLine()) != null) + for (String child : children) { + p = Runtime.getRuntime().exec(new String[]{"taskkill", "/PID", child, "/T", "/F"}); + consumeAllOutput(p); } } + p = Runtime.getRuntime().exec(new String[]{"taskkill", "/PID", parentProcess, "/T", "/F"}); + consumeAllOutput(p); } - p = Runtime.getRuntime().exec(new String[] {"taskkill", "/PID", parentProcess, "/T", "/F"}); - reader = new BufferedReader(new InputStreamReader(p.getInputStream())); - while((line = reader.readLine()) != null) - { - } - } + } } } catch (IOException e) @@ -149,6 +148,19 @@ public class SpawnedBrokerHolder implements BrokerHolder } } + private static void consumeAllOutput(Process p) throws IOException + { + try(InputStreamReader inputStreamReader = new InputStreamReader(p.getInputStream())) + { + try (BufferedReader reader = new BufferedReader(inputStreamReader)) + { + while (reader.readLine() != null) + { + } + } + } + } + @Override public void kill() { diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/transport/MaxFrameSizeTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/transport/MaxFrameSizeTest.java deleted file mode 100644 index 322b971487..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/transport/MaxFrameSizeTest.java +++ /dev/null @@ -1,349 +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.transport; - -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javax.naming.NamingException; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslClient; -import javax.security.sasl.SaslException; - -import org.apache.qpid.codec.MarkableDataInput; -import org.apache.qpid.framing.AMQBody; -import org.apache.qpid.framing.AMQDataBlockDecoder; -import org.apache.qpid.framing.AMQFrame; -import org.apache.qpid.framing.AMQFrameDecodingException; -import org.apache.qpid.framing.AMQProtocolVersionException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BodyFactory; -import org.apache.qpid.framing.ByteArrayDataInput; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.framing.ConnectionStartOkBody; -import org.apache.qpid.framing.ConnectionTuneOkBody; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.framing.amqp_0_91.ConnectionStartOkBodyImpl; -import org.apache.qpid.framing.amqp_0_91.ConnectionTuneOkBodyImpl; -import org.apache.qpid.framing.amqp_0_91.MethodRegistry_0_91; -import org.apache.qpid.jms.BrokerDetails; -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.Protocol; -import org.apache.qpid.server.protocol.v0_8.ProtocolEngineCreator_0_8; -import org.apache.qpid.server.protocol.v0_8.ProtocolEngineCreator_0_9; -import org.apache.qpid.server.protocol.v0_8.ProtocolEngineCreator_0_9_1; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.test.utils.TestBrokerConfiguration; - -public class MaxFrameSizeTest extends QpidBrokerTestCase -{ - - @Override - public void setUp() throws Exception - { - // don't call super.setup() as we want a change to set stuff up before the broker starts - // super.setUp(); - } - - public void testTooSmallFrameSize() throws Exception - { - - getBrokerConfiguration().setObjectAttribute(AuthenticationProvider.class, - TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, - "secureOnlyMechanisms", - "[]"); - super.setUp(); - - if(isBroker010()) - { - Connection conn = new Connection(); - final ConnectionSettings settings = new ConnectionSettings(); - BrokerDetails brokerDetails = getConnectionFactory().getConnectionURL().getAllBrokerDetails().get(0); - settings.setHost(brokerDetails.getHost()); - settings.setPort(brokerDetails.getPort()); - settings.setUsername(GUEST_USERNAME); - settings.setPassword(GUEST_PASSWORD); - final ConnectionDelegate clientDelegate = new TestClientDelegate(settings, 1024); - conn.setConnectionDelegate(clientDelegate); - try - { - conn.connect(settings); - fail("Connection should not be possible with a frame size < " + Constant.MIN_MAX_FRAME_SIZE); - } - catch(ConnectionException e) - { - // pass - } - - } - else - { - doAMQP08test(1024, new ResultEvaluator() - { - - @Override - public void evaluate(final Socket socket, final List frames) - { - if(!socket.isClosed()) - { - AMQFrame lastFrame = frames.get(frames.size() - 1); - assertTrue("Connection should not be possible with a frame size < " + Constant.MIN_MAX_FRAME_SIZE, lastFrame.getBodyFrame() instanceof ConnectionCloseBody); - } - } - }); - } - } - - - public void testTooLargeFrameSize() throws Exception - { - getBrokerConfiguration().setObjectAttribute(AuthenticationProvider.class, - TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, - "secureOnlyMechanisms", - "[]"); - setTestSystemProperty(Broker.BROKER_FRAME_SIZE, "8192"); - super.setUp(); - if(isBroker010()) - { - Connection conn = new Connection(); - final ConnectionSettings settings = new ConnectionSettings(); - BrokerDetails brokerDetails = getConnectionFactory().getConnectionURL().getAllBrokerDetails().get(0); - settings.setHost(brokerDetails.getHost()); - settings.setPort(brokerDetails.getPort()); - settings.setUsername(GUEST_USERNAME); - settings.setPassword(GUEST_PASSWORD); - final ConnectionDelegate clientDelegate = new TestClientDelegate(settings, 0xffff); - conn.setConnectionDelegate(clientDelegate); - try - { - conn.connect(settings); - fail("Connection should not be possible with a frame size larger than the broker requested"); - } - catch(ConnectionException e) - { - // pass - } - - } - else - { - doAMQP08test(10000, new ResultEvaluator() - { - - @Override - public void evaluate(final Socket socket, final List frames) - { - if(!socket.isClosed()) - { - AMQFrame lastFrame = frames.get(frames.size() - 1); - assertTrue("Connection should not be possible with a frame size larger than the broker requested", lastFrame.getBodyFrame() instanceof ConnectionCloseBody); - } - } - }); - } - } - - private static interface ResultEvaluator - { - void evaluate(Socket socket, List frames); - } - - private void doAMQP08test(int frameSize, ResultEvaluator evaluator) - throws NamingException, IOException, AMQFrameDecodingException, AMQProtocolVersionException - { - BrokerDetails brokerDetails = getConnectionFactory().getConnectionURL().getAllBrokerDetails().get(0); - - Socket socket = new Socket(brokerDetails.getHost(), brokerDetails.getPort()); - socket.setTcpNoDelay(true); - OutputStream os = socket.getOutputStream(); - - byte[] protocolHeader; - Protocol protocol = getBrokerProtocol(); - switch(protocol) - { - case AMQP_0_8: - protocolHeader = (ProtocolEngineCreator_0_8.getInstance().getHeaderIdentifier()); - break; - case AMQP_0_9: - protocolHeader = (ProtocolEngineCreator_0_9.getInstance().getHeaderIdentifier()); - break; - case AMQP_0_9_1: - protocolHeader = (ProtocolEngineCreator_0_9_1.getInstance().getHeaderIdentifier()); - break; - default: - throw new RuntimeException("Unexpected Protocol Version: " + protocol); - } - os.write(protocolHeader); - InputStream is = socket.getInputStream(); - - final byte[] response = new byte[2+GUEST_USERNAME.length()+GUEST_PASSWORD.length()]; - int i = 1; - for(byte b : GUEST_USERNAME.getBytes(StandardCharsets.US_ASCII)) - { - response[i++] = b; - } - i++; - for(byte b : GUEST_PASSWORD.getBytes(StandardCharsets.US_ASCII)) - { - response[i++] = b; - } - - ConnectionStartOkBody startOK = new ConnectionStartOkBodyImpl(new FieldTable(), AMQShortString.valueOf("PLAIN"), response, AMQShortString.valueOf("en_US")); - - DataOutputStream dos = new DataOutputStream(os); - new AMQFrame(0, startOK).writePayload(dos); - dos.flush(); - ConnectionTuneOkBody tuneOk = new ConnectionTuneOkBodyImpl(256, frameSize, 0); - new AMQFrame(0, tuneOk).writePayload(dos); - dos.flush(); - socket.setSoTimeout(5000); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] buffer = new byte[1024]; - int size; - while((size = is.read(buffer)) > 0) - { - baos.write(buffer,0,size); - } - - byte[] serverData = baos.toByteArray(); - ByteArrayDataInput badi = new ByteArrayDataInput(serverData); - AMQDataBlockDecoder datablockDecoder = new AMQDataBlockDecoder(); - final MethodRegistry_0_91 methodRegistry_0_91 = new MethodRegistry_0_91(); - BodyFactory methodBodyFactory = new BodyFactory() - { - @Override - public AMQBody createBody(final MarkableDataInput in, final long bodySize) - throws AMQFrameDecodingException, IOException - { - return methodRegistry_0_91.convertToBody(in, bodySize); - } - }; - - List frames = new ArrayList<>(); - while (datablockDecoder.decodable(badi)) - { - frames.add(datablockDecoder.createAndPopulateFrame(methodBodyFactory, badi)); - } - - evaluator.evaluate(socket, frames); - } - - private static class TestClientDelegate extends ClientDelegate - { - - private final int _maxFrameSize; - - public TestClientDelegate(final ConnectionSettings settings, final int maxFrameSize) - { - super(settings); - _maxFrameSize = maxFrameSize; - } - - @Override - protected SaslClient createSaslClient(final List brokerMechs) throws ConnectionException, SaslException - { - final CallbackHandler handler = new CallbackHandler() - { - @Override - public void handle(final Callback[] callbacks) throws IOException, UnsupportedCallbackException - { - for (int i = 0; i < callbacks.length; i++) - { - Callback cb = callbacks[i]; - if (cb instanceof NameCallback) - { - ((NameCallback)cb).setName(GUEST_USERNAME); - } - else if (cb instanceof PasswordCallback) - { - ((PasswordCallback)cb).setPassword(GUEST_PASSWORD.toCharArray()); - } - else - { - throw new UnsupportedCallbackException(cb); - } - } - - } - }; - String[] selectedMechs = {}; - for(String mech : new String[] { "ANONYMOUS", "PLAIN", "CRAM-MD5", "SCRAM-SHA-1", "SCRAM-SHA-256"}) - { - if(brokerMechs.contains(mech)) - { - selectedMechs = new String[] {mech}; - break; - } - } - - - return Sasl.createSaslClient(selectedMechs, - null, - getConnectionSettings().getSaslProtocol(), - getConnectionSettings().getSaslServerName(), - Collections.emptyMap(), - handler); - - } - - @Override - public void connectionTune(Connection conn, ConnectionTune tune) - { - int heartbeatInterval = getConnectionSettings().getHeartbeatInterval010(); - float heartbeatTimeoutFactor = getConnectionSettings().getHeartbeatTimeoutFactor(); - int actualHeartbeatInterval = calculateHeartbeatInterval(heartbeatInterval, - tune.getHeartbeatMin(), - tune.getHeartbeatMax()); - - conn.connectionTuneOk(tune.getChannelMax(), - _maxFrameSize, - actualHeartbeatInterval); - - int idleTimeout = (int)(actualHeartbeatInterval * 1000 * heartbeatTimeoutFactor); - conn.getNetworkConnection().setMaxReadIdle((int)(actualHeartbeatInterval*heartbeatTimeoutFactor)); - conn.getNetworkConnection().setMaxWriteIdle(actualHeartbeatInterval); - conn.setMaxFrameSize(_maxFrameSize); - - - conn.setIdleTimeout(idleTimeout); - - int channelMax = tune.getChannelMax(); - conn.setChannelMax(channelMax == 0 ? Connection.MAX_CHANNEL_MAX : channelMax); - - conn.connectionOpen(getConnectionSettings().getVhost(), null, Option.INSIST); - } - - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/util/ClasspathScanner.java b/qpid/java/systests/src/main/java/org/apache/qpid/util/ClasspathScanner.java deleted file mode 100644 index 151d1473ac..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/util/ClasspathScanner.java +++ /dev/null @@ -1,239 +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.util; - -import org.apache.log4j.Logger; - -import java.io.File; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * An ClasspathScanner scans the classpath for classes that implement an interface or extend a base class and have names - * that match a regular expression. - * - *

In order to test whether a class implements an interface or extends a class, the class must be loaded (unless - * the class files were to be scanned directly). Using this collector can cause problems when it scans the classpath, - * because loading classes will initialize their statics, which in turn may cause undesired side effects. For this - * reason, the collector should always be used with a regular expression, through which the class file names are - * filtered, and only those that pass this filter will be tested. For example, if you define tests in classes that - * end with the keyword "Test" then use the regular expression "Test$" to match this. - * - *

- *
CRC Card
Responsibilities Collaborations - *
Find all classes matching type and name pattern on the classpath. - *
- * - * @todo Add logic to scan jars as well as directories. - */ -public class ClasspathScanner -{ - private static final Logger log = Logger.getLogger(ClasspathScanner.class); - - /** - * Scans the classpath and returns all classes that extend a specified class and match a specified name. - * There is an flag that can be used to indicate that only Java Beans will be matched (that is, only those classes - * that have a default constructor). - * - * @param matchingClass The class or interface to match. - * @param matchingRegexp The regular expression to match against the class name. - * @param beanOnly Flag to indicate that onyl classes with default constructors should be matched. - * - * @return All the classes that match this collector. - */ - public static Collection> getMatches(Class matchingClass, String matchingRegexp, - boolean beanOnly) - { - log.debug("public static Collection> getMatches(Class matchingClass = " + matchingClass - + ", String matchingRegexp = " + matchingRegexp + ", boolean beanOnly = " + beanOnly + "): called"); - - // Build a compiled regular expression from the pattern to match. - Pattern matchPattern = Pattern.compile(matchingRegexp); - - String classPath = System.getProperty("java.class.path"); - Map> result = new HashMap>(); - - log.debug("classPath = " + classPath); - - // Find matching classes starting from all roots in the classpath. - for (String path : splitClassPath(classPath)) - { - gatherFiles(new File(path), "", result, matchPattern, matchingClass); - } - - return result.values(); - } - - /** - * Finds all matching classes rooted at a given location in the file system. If location is a directory it - * is recursively examined. - * - * @param classRoot The root of the current point in the file system being examined. - * @param classFileName The name of the current file or directory to examine. - * @param result The accumulated mapping from class names to classes that match the scan. - * - * @todo Recursion ok as file system depth is not likely to exhaust the stack. Might be better to replace with - * iteration. - */ - private static void gatherFiles(File classRoot, String classFileName, Map> result, - Pattern matchPattern, Class matchClass) - { - log.debug("private static void gatherFiles(File classRoot = " + classRoot + ", String classFileName = " - + classFileName + ", Map> result, Pattern matchPattern = " + matchPattern - + ", Class matchClass = " + matchClass + "): called"); - - File thisRoot = new File(classRoot, classFileName); - - // If the current location is a file, check if it is a matching class. - if (thisRoot.isFile()) - { - // Check that the file has a matching name. - if (matchesName(thisRoot.getName(), matchPattern)) - { - String className = classNameFromFile(thisRoot.getName()); - - // Check that the class has matching type. - try - { - Class candidateClass = Class.forName(className); - - Class matchedClass = matchesClass(candidateClass, matchClass); - - if (matchedClass != null) - { - result.put(className, matchedClass); - } - } - catch (ClassNotFoundException e) - { - // Ignore this. The matching class could not be loaded. - log.debug("Got ClassNotFoundException, ignoring.", e); - } - } - - return; - } - // Otherwise the current location is a directory, so examine all of its contents. - else - { - String[] contents = thisRoot.list(); - - if (contents != null) - { - for (String content : contents) - { - gatherFiles(classRoot, classFileName + File.separatorChar + content, result, matchPattern, matchClass); - } - } - } - } - - /** - * Checks if the specified class file name corresponds to a class with name matching the specified regular expression. - * - * @param classFileName The class file name. - * @param matchPattern The regular expression pattern to match. - * - * @return true if the class name matches, false otherwise. - */ - private static boolean matchesName(String classFileName, Pattern matchPattern) - { - String className = classNameFromFile(classFileName); - Matcher matcher = matchPattern.matcher(className); - - return matcher.matches(); - } - - /** - * Checks if the specified class to compare extends the base class being scanned for. - * - * @param matchingClass The base class to match against. - * @param toMatch The class to match against the base class. - * - * @return The class to check, cast as an instance of the class to match if the class extends the base class, or - * null otherwise. - */ - private static Class matchesClass(Class matchingClass, Class toMatch) - { - try - { - return matchingClass.asSubclass(toMatch); - } - catch (ClassCastException e) - { - return null; - } - } - - /** - * Takes a classpath (which is a series of paths) and splits it into its component paths. - * - * @param classPath The classpath to split. - * - * @return A list of the component paths that make up the class path. - */ - private static List splitClassPath(String classPath) - { - List result = new LinkedList(); - String separator = System.getProperty("path.separator"); - StringTokenizer tokenizer = new StringTokenizer(classPath, separator); - - while (tokenizer.hasMoreTokens()) - { - result.add(tokenizer.nextToken()); - } - - return result; - } - - /** - * Translates from the filename of a class to its fully qualified classname. Files are named using forward slash - * seperators and end in ".class", whereas fully qualified class names use "." sperators and no ".class" ending. - * - * @param classFileName The filename of the class to translate to a class name. - * - * @return The fully qualified class name. - */ - private static String classNameFromFile(String classFileName) - { - log.debug("private static String classNameFromFile(String classFileName = " + classFileName + "): called"); - - // Remove the .class ending. - String s = classFileName.substring(0, classFileName.length() - ".class".length()); - - // Turn / seperators in . seperators. - String s2 = s.replace(File.separatorChar, '.'); - - // Knock off any leading . caused by a leading /. - if (s2.startsWith(".")) - { - return s2.substring(1); - } - - return s2; - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/util/LogMonitor.java b/qpid/java/systests/src/main/java/org/apache/qpid/util/LogMonitor.java deleted file mode 100644 index d77731d09f..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/util/LogMonitor.java +++ /dev/null @@ -1,336 +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.util; - -import org.apache.log4j.FileAppender; -import org.apache.log4j.Logger; -import org.apache.log4j.SimpleLayout; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.io.LineNumberReader; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -/** - * Utility to simplify the monitoring of Log4j file output - * - * Monitoring of a given log file can be done alternatively the Monitor will - * add a new log4j FileAppender to the root Logger to gather all the available - * logging for monitoring - */ -public class LogMonitor -{ - private static final Logger _logger = Logger.getLogger(LogMonitor.class); - - // The file that the log statements will be written to. - private final File _logfile; - - // The appender we added to the get messages - private final FileAppender _appender; - - private int _linesToSkip = 0; - - /** - * Create a new LogMonitor that creates a new Log4j Appender and monitors - * all log4j output via the current configuration. - * - * @throws IOException if there is a problem creating the temporary file. - */ - public LogMonitor() throws IOException - { - this(null); - } - - /** - * Create a new LogMonitor on the specified file if the file does not exist - * or the value is null then a new Log4j appender will be added and - * monitoring set up on that appender. - * - * NOTE: for the appender to receive any value the RootLogger will need to - * have the level correctly configured.ng - * - * @param file the file to monitor - * - * @throws IOException if there is a problem creating a temporary file - */ - public LogMonitor(File file) throws IOException - { - if (file != null && file.exists()) - { - _logfile = file; - _appender = null; - } - else - { - // This is mostly for running the test outside of the ant setup - _logfile = File.createTempFile("LogMonitor", ".log"); - _appender = new FileAppender(new SimpleLayout(), - _logfile.getAbsolutePath()); - _appender.setFile(_logfile.getAbsolutePath()); - _appender.setImmediateFlush(true); - Logger.getRootLogger().addAppender(_appender); - } - - _logger.info("Created LogMonitor. Monitoring file: " + _logfile.getAbsolutePath()); - } - - /** - * Checks the log file for a given message to appear and returns all - * instances of that appearance. - * - * @param message the message to wait for in the log - * @param wait the time in ms to wait for the message to occur - * @return true if the message was found - * - * @throws java.io.FileNotFoundException if the Log file can no longer be found - * @throws IOException thrown when reading the log file - */ - public List waitAndFindMatches(String message, long wait) - throws FileNotFoundException, IOException - { - if (waitForMessage(message, wait)) - { - return findMatches(message); - } - else - { - return new LinkedList(); - } - } - - /** - * Checks the log for instances of the search string. If the caller - * has previously called {@link #markDiscardPoint()}, lines up until the discard - * point are not considered. - * - * The pattern parameter can take any valid argument used in String.contains() - * - * {@see String.contains(CharSequences)} - * - * @param pattern the search string - * - * @return a list of matching lines from the log - * - * @throws IOException if there is a problem with the file - */ - public List findMatches(String pattern) throws IOException - { - - List results = new LinkedList(); - - LineNumberReader reader = new LineNumberReader(new FileReader(_logfile)); - try - { - while (reader.ready()) - { - String line = reader.readLine(); - if (reader.getLineNumber() > _linesToSkip && line.contains(pattern)) - { - results.add(line); - } - } - } - finally - { - reader.close(); - } - - return results; - } - - public Map> findMatches(String... pattern) throws IOException - { - - Map> results= new HashMap>(); - for (String p : pattern) - { - results.put(p, new LinkedList()); - } - LineNumberReader reader = new LineNumberReader(new FileReader(_logfile)); - try - { - while (reader.ready()) - { - String line = reader.readLine(); - if (reader.getLineNumber() > _linesToSkip) - { - for (String p : pattern) - { - if (line.contains(p)) - { - results.get(p).add(line); - } - } - } - } - } - finally - { - reader.close(); - } - - return results; - } - /** - * Checks the log file for a given message to appear. If the caller - * has previously called {@link #markDiscardPoint()}, lines up until the discard - * point are not considered. - * - * @param message the message to wait for in the log - * @param wait the time in ms to wait for the message to occur - * @return true if the message was found - * - * @throws java.io.FileNotFoundException if the Log file can no longer be found - * @throws IOException thrown when reading the log file - */ - public boolean waitForMessage(String message, long wait) - throws FileNotFoundException, IOException - { - // Loop through alerts until we're done or wait ms seconds have passed, - // just in case the logfile takes a while to flush. - LineNumberReader reader = null; - try - { - reader = new LineNumberReader(new FileReader(_logfile)); - - boolean found = false; - long endtime = System.currentTimeMillis() + wait; - while (!found && System.currentTimeMillis() < endtime) - { - boolean ready = true; - while (ready = reader.ready()) - { - String line = reader.readLine(); - - if (reader.getLineNumber() > _linesToSkip) - { - if (line.contains(message)) - { - found = true; - break; - } - } - } - if (!ready) - { - try - { - Thread.sleep(50); - } - catch (InterruptedException ie) - { - Thread.currentThread().interrupt(); - } - } - } - return found; - - } - finally - { - if (reader != null) - { - reader.close(); - } - } - } - - /** - * Read the log file in to memory as a String - * - * @return the current contents of the log file - * - * @throws java.io.FileNotFoundException if the Log file can no longer be found - * @throws IOException thrown when reading the log file - */ - public String readFile() throws FileNotFoundException, IOException - { - return FileUtils.readFileAsString(_logfile); - } - - /** - * Return a File reference to the monitored file - * - * @return the file being monitored - */ - public File getMonitoredFile() - { - return _logfile; - } - - /** - * Marks the discard point in the log file. - * - * @throws java.io.FileNotFoundException if the Log file can no longer be found - * @throws IOException thrown if there is a problem with the log file - */ - public void markDiscardPoint() throws FileNotFoundException, IOException - { - _linesToSkip = countLinesInFile(); - } - - private int countLinesInFile() throws IOException - { - int lineCount = 0; - BufferedReader br = null; - try - { - br = new BufferedReader(new FileReader(_logfile)); - while(br.readLine() != null) - { - lineCount++; - } - - return lineCount; - } - finally - { - if (br != null) - { - br.close(); - } - } - } - - /** - * Stop monitoring this file. - * - * This is required to be called incase we added a new logger. - * - * If we don't call close then the new logger will continue to get log entries - * after our desired test has finished. - */ - public void close() - { - //Remove the custom appender we added for this logger - if (_appender != null) - { - Logger.getRootLogger().removeAppender(_appender); - } - } - -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/util/LogMonitorTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/util/LogMonitorTest.java deleted file mode 100644 index 89f707fbef..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/util/LogMonitorTest.java +++ /dev/null @@ -1,274 +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.util; - -import junit.framework.TestCase; -import org.apache.log4j.Logger; - -import java.io.File; -import java.io.IOException; -import java.util.List; - -public class LogMonitorTest extends TestCase -{ - - private LogMonitor _monitor; - - @Override - public void setUp() throws Exception - { - _monitor = new LogMonitor(); - _monitor.getMonitoredFile().deleteOnExit(); // Make sure we clean up - } - - /** - * Test that a new file is created when attempting to set up a monitor with - * the default constructor. - */ - public void testMonitor() - { - //Validate that the monitor is now running on a new file - assertTrue("New file does not have correct name:" + _monitor. - getMonitoredFile().getName(), - _monitor.getMonitoredFile().getName().contains("LogMonitor")); - } - - /** - * Test that creation of a monitor on an existing file is possible - * - * This also tests taht getMonitoredFile works - * - * @throws IOException if there is a problem creating the temporary file - */ - public void testMonitorNormalFile() throws IOException - { - File testFile = File.createTempFile("testMonitorFile", ".log"); - testFile.deleteOnExit(); - - //Ensure that we can create a monitor on a file - try - { - _monitor = new LogMonitor(testFile); - assertEquals(testFile, _monitor.getMonitoredFile()); - } - catch (IOException ioe) - { - fail("IOE thrown:" + ioe); - } - - } - - /** - * Test that a new file is created when attempting to set up a monitor on - * a null input value. - */ - public void testMonitorNullFile() - { - // Validate that a NPE is thrown with null input - try - { - LogMonitor montior = new LogMonitor(null); - //Validte that the monitor is now running on a new file - assertTrue("New file does not have correct name:" + montior. - getMonitoredFile().getName(), - montior.getMonitoredFile().getName().contains("LogMonitor")); - } - catch (IOException ioe) - { - fail("IOE thrown:" + ioe); - } - } - - /** - * Test that a new file is created when attempting to set up a monitor on - * a non existing file. - * - * @throws IOException if there is a problem setting up the nonexistent file - */ - public void testMonitorNonExistentFile() throws IOException - { - //Validate that we get a FileNotFound if the file does not exist - - File nonexist = File.createTempFile("nonexist", ".out"); - - assertTrue("Unable to delete file for our test", nonexist.delete()); - - assertFalse("Unable to test as our test file exists.", nonexist.exists()); - - try - { - LogMonitor montior = new LogMonitor(nonexist); - //Validte that the monitor is now running on a new file - assertTrue("New file does not have correct name:" + montior. - getMonitoredFile().getName(), - montior.getMonitoredFile().getName().contains("LogMonitor")); - } - catch (IOException ioe) - { - fail("IOE thrown:" + ioe); - } - } - - /** - * Test that Log file matches logged messages. - * - * @throws java.io.IOException if there is a problem creating LogMontior - */ - public void testFindMatches_Match() throws IOException - { - - String message = getName() + ": Test Message"; - - Logger.getRootLogger().warn(message); - - validateLogContainsMessage(_monitor, message); - } - - /** - * Test that Log file does not match a message not logged. - * - * @throws java.io.IOException if there is a problem creating LogMontior - */ - public void testFindMatches_NoMatch() throws IOException - { - String message = getName() + ": Test Message"; - - Logger.getRootLogger().warn(message); - - String notLogged = "This text was not logged"; - - validateLogDoesNotContainMessage(_monitor, notLogged); - } - - public void testWaitForMessage_Timeout() throws IOException - { - String message = getName() + ": Test Message"; - - long TIME_OUT = 2000; - - logMessageWithDelay(message, TIME_OUT); - - // Verify that we can time out waiting for a message - assertFalse("Message was logged ", - _monitor.waitForMessage(message, TIME_OUT / 2)); - - // Verify that the message did eventually get logged. - assertTrue("Message was never logged.", - _monitor.waitForMessage(message, TIME_OUT)); - } - - public void testDiscardPoint() throws IOException - { - String firstMessage = getName() + ": Test Message1"; - Logger.getRootLogger().warn(firstMessage); - - validateLogContainsMessage(_monitor, firstMessage); - - _monitor.markDiscardPoint(); - - validateLogDoesNotContainMessage(_monitor, firstMessage); - - String secondMessage = getName() + ": Test Message2"; - Logger.getRootLogger().warn(secondMessage); - validateLogContainsMessage(_monitor, secondMessage); - } - - public void testRead() throws IOException - { - String message = getName() + ": Test Message"; - - Logger.getRootLogger().warn(message); - - String fileContents = _monitor.readFile(); - - assertTrue("Logged message not found when reading file.", - fileContents.contains(message)); - } - - /****************** Helpers ******************/ - - /** - * Validate that the LogMonitor does not match the given string in the log - * - * @param log The LogMonitor to check - * @param message The message to check for - * - * @throws IOException if a problems occurs - */ - protected void validateLogDoesNotContainMessage(LogMonitor log, String message) - throws IOException - { - List results = log.findMatches(message); - - assertNotNull("Null results returned.", results); - - assertEquals("Incorrect result set size", 0, results.size()); - } - - /** - * Validate that the LogMonitor can match the given string in the log - * - * @param log The LogMonitor to check - * @param message The message to check for - * - * @throws IOException if a problems occurs - */ - protected void validateLogContainsMessage(LogMonitor log, String message) - throws IOException - { - List results = log.findMatches(message); - - assertNotNull("Null results returned.", results); - - assertEquals("Incorrect result set size", 1, results.size()); - - assertTrue("Logged Message'" + message + "' not present in results:" - + results.get(0), results.get(0).contains(message)); - } - - /** - * Create a new thread to log the given message after the set delay - * - * @param message the messasge to log - * @param delay the delay (ms) to wait before logging - */ - private void logMessageWithDelay(final String message, final long delay) - { - new Thread(new Runnable() - { - - public void run() - { - try - { - Thread.sleep(delay); - } - catch (InterruptedException e) - { - //ignore - } - - Logger.getRootLogger().warn(message); - } - }).start(); - } - -} diff --git a/qpid/java/systests/src/main/java/systests.log4j b/qpid/java/systests/src/main/java/systests.log4j deleted file mode 100644 index 6d596d1d19..0000000000 --- a/qpid/java/systests/src/main/java/systests.log4j +++ /dev/null @@ -1,28 +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. -# -log4j.rootLogger=${root.logging.level} - - -log4j.logger.org.apache.qpid=${amqj.logging.level}, console -log4j.additivity.org.apache.qpid=false - -log4j.appender.console=org.apache.log4j.ConsoleAppender -log4j.appender.console.Threshold=all -log4j.appender.console.layout=org.apache.log4j.PatternLayout -log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.java new file mode 100644 index 0000000000..3025414e4a --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.java @@ -0,0 +1,145 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +public class AMQQueueDeferredOrderingTest extends QpidBrokerTestCase +{ + private Connection con; + private Session session; + private AMQQueue queue; + private MessageConsumer consumer; + private int numMessages; + + private static final Logger _logger = LoggerFactory.getLogger(AMQQueueDeferredOrderingTest.class); + + private ASyncProducer producerThread; + + private class ASyncProducer extends Thread + { + + private MessageProducer producer; + private final Logger _logger = LoggerFactory.getLogger(ASyncProducer.class); + private Session session; + private int start; + private int end; + + public ASyncProducer(AMQQueue q, int start, int end) throws Exception + { + this.session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + this._logger.info("Create Consumer of Q1"); + this.producer = this.session.createProducer(q); + this.start = start; + this.end = end; + } + + public void run() + { + try + { + this._logger.info("Starting to send messages"); + for (int i = start; i < end && !interrupted(); i++) + { + producer.send(session.createTextMessage(Integer.toString(i))); + ((AMQSession)session).sync(); + } + this._logger.info("Sent " + (end - start) + " messages"); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + } + + protected void setUp() throws Exception + { + super.setUp(); + + numMessages = isBrokerStorePersistent() ? 300 : 1000; + + _logger.info("Create Connection"); + con = getConnection(); + _logger.info("Create Session"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + _logger.info("Create Q"); + queue = new AMQQueue(new AMQShortString("amq.direct"), new AMQShortString("Q"), new AMQShortString("Q"), + false, true); + _logger.info("Create Consumer of Q"); + consumer = session.createConsumer(queue); + _logger.info("Start Connection"); + con.start(); + } + + public void testMessagesSentByTwoThreadsAreDeliveredInOrder() throws Exception + { + + // Setup initial messages + _logger.info("Creating first producer thread"); + producerThread = new ASyncProducer(queue, 0, numMessages / 2); + producerThread.start(); + // Wait for them to be done + producerThread.join(); + + // Setup second set of messages to produce while we consume + _logger.info("Creating second producer thread"); + producerThread = new ASyncProducer(queue, numMessages / 2, numMessages); + producerThread.start(); + + // Start consuming and checking they're in order + _logger.info("Consuming messages"); + for (int i = 0; i < numMessages; i++) + { + Message msg = consumer.receive(3000); + assertNotNull("Message " + i + " should not be null", msg); + assertTrue("Message " + i + " should be a text message", msg instanceof TextMessage); + assertEquals("Message content " + i + "does not match expected", Integer.toString(i), ((TextMessage) msg).getText()); + } + } + + protected void tearDown() throws Exception + { + _logger.info("Interuptting producer thread"); + producerThread.interrupt(); + _logger.info("Closing connection"); + con.close(); + + super.tearDown(); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(AMQQueueDeferredOrderingTest.class); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/client/AMQTestConnection_0_10.java b/qpid/java/systests/src/test/java/org/apache/qpid/client/AMQTestConnection_0_10.java new file mode 100644 index 0000000000..c5dd523214 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/client/AMQTestConnection_0_10.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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; + +import org.apache.qpid.transport.Connection; + +public class AMQTestConnection_0_10 extends AMQConnection +{ + public AMQTestConnection_0_10(String url) throws Exception + { + super(url); + } + + public Connection getConnection() + { + return((AMQConnectionDelegate_0_10)getDelegate()).getQpidConnection(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/client/AsynchMessageListenerTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/client/AsynchMessageListenerTest.java new file mode 100644 index 0000000000..a13bf71d5e --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/client/AsynchMessageListenerTest.java @@ -0,0 +1,362 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.util.LogMonitor; + +/** + * Tests the behaviour of JMS asynchronous message listeners as provided by + * {@link MessageListener#onMessage(Message)}. + * + */ +public class AsynchMessageListenerTest extends QpidBrokerTestCase +{ + private static final int MSG_COUNT = 10; + private static final long AWAIT_MESSAGE_TIMEOUT = 2000; + private static final long AWAIT_MESSAGE_TIMEOUT_NEGATIVE = 250; + private String _testQueueName; + private Connection _consumerConnection; + private Session _consumerSession; + private MessageConsumer _consumer; + private Queue _queue; + + protected void setUp() throws Exception + { + super.setUp(); + _testQueueName = getTestQueueName(); + _consumerConnection = getConnection(); + _consumerConnection.start(); + _consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _queue = _consumerSession.createQueue(_testQueueName); + _consumer = _consumerSession.createConsumer(_queue); + + // Populate queue + Connection producerConnection = getConnection(); + Session producerSession = producerConnection.createSession(true, Session.SESSION_TRANSACTED); + sendMessage(producerSession, _queue, MSG_COUNT); + producerConnection.close(); + + } + + public void testMessageListener() throws Exception + { + CountingMessageListener countingMessageListener = new CountingMessageListener(MSG_COUNT); + _consumer.setMessageListener(countingMessageListener); + countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT); + + assertEquals("Unexpected number of outstanding messages", 0, countingMessageListener.getOutstandingCount()); + } + + public void testSynchronousReceiveFollowedByMessageListener() throws Exception + { + // Receive initial message synchronously + assertNotNull("Could not receive first message synchronously", _consumer.receive(AWAIT_MESSAGE_TIMEOUT) != null); + final int numberOfMessagesToReceiveByMessageListener = MSG_COUNT - 1; + + // Consume remainder asynchronously + CountingMessageListener countingMessageListener = new CountingMessageListener(numberOfMessagesToReceiveByMessageListener); + _consumer.setMessageListener(countingMessageListener); + countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT); + + assertEquals("Unexpected number of outstanding messages", 0, countingMessageListener.getOutstandingCount()); + } + + public void testMessageListenerSetDisallowsSynchronousReceive() throws Exception + { + CountingMessageListener countingMessageListener = new CountingMessageListener(MSG_COUNT); + _consumer.setMessageListener(countingMessageListener); + + try + { + _consumer.receive(); + fail("Exception not thrown"); + } + catch (JMSException e) + { + // PASS + assertEquals("A listener has already been set.", e.getMessage()); + } + } + + + public void testConnectionStopThenStart() throws Exception + { + int messageToReceivedBeforeConnectionStop = 2; + CountingMessageListener countingMessageListener = new CountingMessageListener(MSG_COUNT, messageToReceivedBeforeConnectionStop); + + // Consume at least two messages + _consumer.setMessageListener(countingMessageListener); + countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT); + + _consumerConnection.stop(); + + assertTrue("Too few messages received afer Connection#stop()", countingMessageListener.getReceivedCount() >= messageToReceivedBeforeConnectionStop); + countingMessageListener.resetLatch(); + + // Restart connection + _consumerConnection.start(); + + // Consume the remainder + countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT); + + assertEquals("Unexpected number of outstanding messages", 0, countingMessageListener.getOutstandingCount()); + } + + public void testConnectionStopAndMessageListenerChange() throws Exception + { + int messageToReceivedBeforeConnectionStop = 2; + CountingMessageListener countingMessageListener1 = new CountingMessageListener(MSG_COUNT, messageToReceivedBeforeConnectionStop); + + // Consume remainder asynchronously + _consumer.setMessageListener(countingMessageListener1); + countingMessageListener1.awaitMessages(AWAIT_MESSAGE_TIMEOUT); + + _consumerConnection.stop(); + assertTrue("Too few messages received afer Connection#stop()", countingMessageListener1.getReceivedCount() >= messageToReceivedBeforeConnectionStop); + + CountingMessageListener countingMessageListener2 = new CountingMessageListener(countingMessageListener1.getOutstandingCount()); + + // Reset Message Listener + _consumer.setMessageListener(countingMessageListener2); + + _consumerConnection.start(); + + // Consume the remainder + countingMessageListener2.awaitMessages(AWAIT_MESSAGE_TIMEOUT); + + assertEquals("Unexpected number of outstanding messages", 0, countingMessageListener2.getOutstandingCount()); + + } + + public void testConnectionStopHaltsDeliveryToListener() throws Exception + { + int messageToReceivedBeforeConnectionStop = 2; + CountingMessageListener countingMessageListener = new CountingMessageListener(MSG_COUNT, messageToReceivedBeforeConnectionStop); + + // Consume at least two messages + _consumer.setMessageListener(countingMessageListener); + countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT); + + _consumerConnection.stop(); + + // Connection should now be stopped and listener should receive no more + final int outstandingCountAtStop = countingMessageListener.getOutstandingCount(); + countingMessageListener.resetLatch(); + countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT_NEGATIVE); + + assertEquals("Unexpected number of outstanding messages", outstandingCountAtStop, countingMessageListener.getOutstandingCount()); + } + + public void testSessionCloseHaltsDelivery() throws Exception + { + int messageToReceivedBeforeConnectionStop = 2; + CountingMessageListener countingMessageListener = new CountingMessageListener(MSG_COUNT, messageToReceivedBeforeConnectionStop); + + // Consume at least two messages + _consumer.setMessageListener(countingMessageListener); + countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT); + + _consumerSession.close(); + + // Once a session is closed, the listener should receive no more + final int outstandingCountAtClose = countingMessageListener.getOutstandingCount(); + countingMessageListener.resetLatch(); + countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT_NEGATIVE); + + assertEquals("Unexpected number of outstanding messages", outstandingCountAtClose, countingMessageListener.getOutstandingCount()); + } + + public void testImmediatePrefetchWithMessageListener() throws Exception + { + // Close connection provided by setup so we can set IMMEDIATE_PREFETCH + _consumerConnection.close(); + setTestClientSystemProperty(AMQSession.IMMEDIATE_PREFETCH, "true"); + + _consumerConnection = getConnection(); + _consumerConnection.start(); + _consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _consumer = _consumerSession.createConsumer(_queue); + CountingMessageListener countingMessageListener = new CountingMessageListener(MSG_COUNT); + _consumer.setMessageListener(countingMessageListener); + + countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT); + + assertEquals("Unexpected number of messages received", MSG_COUNT, countingMessageListener.getReceivedCount()); + } + + public void testReceiveTwoConsumers() throws Exception + { + Session consumerSession2 = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer _consumer2 = consumerSession2.createConsumer(_queue); + + CountingMessageListener countingMessageListener = new CountingMessageListener(MSG_COUNT); + _consumer.setMessageListener(countingMessageListener); + _consumer2.setMessageListener(countingMessageListener); + + countingMessageListener.awaitMessages(AWAIT_MESSAGE_TIMEOUT); + assertEquals("Unexpected number of messages received", MSG_COUNT, countingMessageListener.getReceivedCount()); + } + + /** + * Tests the case where the message listener throws an java.lang.Error. + * TODO - a useful test?. + */ + public void testMessageListenerThrowsError() throws Exception + { + int expectedMessages = 1; // The error will kill the dispatcher so only one message will be delivered. + final CountDownLatch awaitMessages = new CountDownLatch(expectedMessages); + final AtomicInteger receivedCount = new AtomicInteger(0); + final String javaLangErrorMessageText = "MessageListener failed with java.lang.Error"; + CountingExceptionListener countingExceptionListener = new CountingExceptionListener(); + _consumerConnection.setExceptionListener(countingExceptionListener); + + _consumer.setMessageListener(new MessageListener() + { + @Override + public void onMessage(Message message) + { + try + { + throw new Error(javaLangErrorMessageText); + } + finally + { + receivedCount.incrementAndGet(); + awaitMessages.countDown(); + } + } + }); + + awaitMessages.await(AWAIT_MESSAGE_TIMEOUT, TimeUnit.MILLISECONDS); + + assertEquals("Unexpected number of messages received", expectedMessages, receivedCount.get()); + assertEquals("onException should NOT have been called", 0, countingExceptionListener.getErrorCount()); + + // Check that Error has been written to the application log. + + LogMonitor _monitor = new LogMonitor(_outputFile); + assertTrue("The expected message not written to log file.", + _monitor.waitForMessage(javaLangErrorMessageText, LOGMONITOR_TIMEOUT)); + + if (_consumerConnection != null) + { + try + { + _consumerConnection.close(); + } + catch (JMSException e) + { + // Ignore connection close errors for this test. + } + finally + { + _consumerConnection = null; + } + } + } + + private final class CountingExceptionListener implements ExceptionListener + { + private final AtomicInteger _errorCount = new AtomicInteger(); + + @Override + public void onException(JMSException arg0) + { + _errorCount.incrementAndGet(); + } + + public int getErrorCount() + { + return _errorCount.intValue(); + } + } + + private final class CountingMessageListener implements MessageListener + { + private volatile CountDownLatch _awaitMessages; + private final AtomicInteger _receivedCount; + private final AtomicInteger _outstandingMessageCount; + + public CountingMessageListener(final int totalExpectedMessageCount) + { + this(totalExpectedMessageCount, totalExpectedMessageCount); + } + + + public CountingMessageListener(int totalExpectedMessageCount, int numberOfMessagesToAwait) + { + _receivedCount = new AtomicInteger(0); + _outstandingMessageCount = new AtomicInteger(totalExpectedMessageCount); + _awaitMessages = new CountDownLatch(numberOfMessagesToAwait); + } + + public int getOutstandingCount() + { + return _outstandingMessageCount.get(); + } + + public int getReceivedCount() + { + return _receivedCount.get(); + } + + public void resetLatch() + { + _awaitMessages = new CountDownLatch(_outstandingMessageCount.get()); + } + + @Override + public void onMessage(Message message) + { + _receivedCount.incrementAndGet(); + _outstandingMessageCount.decrementAndGet(); + _awaitMessages.countDown(); + } + + public boolean awaitMessages(long timeout) + { + try + { + return _awaitMessages.await(timeout, TimeUnit.MILLISECONDS); + } + catch (InterruptedException e) + { + Thread.currentThread().interrupt(); + return false; + } + } + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/client/HeartbeatTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/client/HeartbeatTest.java new file mode 100644 index 0000000000..881a37a970 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/client/HeartbeatTest.java @@ -0,0 +1,224 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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; + +import static org.apache.qpid.configuration.ClientProperties.AMQJ_HEARTBEAT_DELAY; +import static org.apache.qpid.configuration.ClientProperties.IDLE_TIMEOUT_PROP_NAME; +import static org.apache.qpid.configuration.ClientProperties.QPID_HEARTBEAT_INTERVAL; + +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class HeartbeatTest extends QpidBrokerTestCase +{ + private static final Logger LOGGER = Logger.getLogger(HeartbeatTest.class); + + private static final String CONNECTION_URL_WITH_HEARTBEAT = "amqp://guest:guest@clientid/?brokerlist='localhost:%d?heartbeat='%d''"; + private TestListener _listener = new TestListener("listener"); + + @Override + public void setUp() throws Exception + { + if (getName().equals("testHeartbeatsEnabledBrokerSide")) + { + getBrokerConfiguration().setBrokerAttribute(Broker.CONNECTION_HEART_BEAT_DELAY, "1"); + } + super.setUp(); + } + + public void testHeartbeatsEnabledUsingUrl() throws Exception + { + final String url = String.format(CONNECTION_URL_WITH_HEARTBEAT, DEFAULT_PORT, 1); + AMQConnection conn = (AMQConnection) getConnection(new AMQConnectionURL(url)); + conn.setHeartbeatListener(_listener); + conn.start(); + + Thread.sleep(2500); + + assertTrue("Too few heartbeats received: "+_listener.getHeartbeatsReceived() +" (expected at least 2)", _listener.getHeartbeatsReceived() >=2); + assertTrue("Too few heartbeats sent "+_listener.getHeartbeatsSent() +" (expected at least 2)", _listener.getHeartbeatsSent() >=2); + + conn.close(); + } + + public void testHeartbeatsEnabledUsingSystemProperty() throws Exception + { + setTestSystemProperty(QPID_HEARTBEAT_INTERVAL, "1"); + AMQConnection conn = (AMQConnection) getConnection(); + conn.setHeartbeatListener(_listener); + conn.start(); + + Thread.sleep(2500); + + assertTrue("Too few heartbeats received: "+_listener.getHeartbeatsReceived() +" (expected at least 2)", _listener.getHeartbeatsReceived() >=2); + assertTrue("Too few heartbeats sent "+_listener.getHeartbeatsSent() +" (expected at least 2)", _listener.getHeartbeatsSent() >=2); + + conn.close(); + } + + public void testHeartbeatsDisabledUsingSystemProperty() throws Exception + { + setTestSystemProperty(QPID_HEARTBEAT_INTERVAL, "0"); + AMQConnection conn = (AMQConnection) getConnection(); + conn.setHeartbeatListener(_listener); + conn.start(); + + Thread.sleep(2500); + + assertEquals("Heartbeats unexpectedly received", 0, _listener.getHeartbeatsReceived()); + assertEquals("Heartbeats unexpectedly sent ", 0, _listener.getHeartbeatsSent()); + + conn.close(); + } + + /** + * This test carefully arranges message flow so that bytes flow only from producer to broker + * on the producer side and broker to consumer on the consumer side, deliberately leaving the + * reverse path quiet so heartbeats will flow. + */ + public void testUnidirectionalHeartbeating() throws Exception + { + setTestSystemProperty(QPID_HEARTBEAT_INTERVAL,"1"); + AMQConnection receiveConn = (AMQConnection) getConnection(); + AMQConnection sendConn = (AMQConnection) getConnection(); + Destination destination = getTestQueue(); + TestListener receiveListener = new TestListener("receiverListener"); + TestListener sendListener = new TestListener("senderListener"); + + + Session receiveSession = receiveConn.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Session senderSession = sendConn.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + MessageConsumer consumer = receiveSession.createConsumer(destination); + MessageProducer producer = senderSession.createProducer(destination); + + receiveConn.setHeartbeatListener(receiveListener); + sendConn.setHeartbeatListener(sendListener); + receiveConn.start(); + + for(int i = 0; i < 5; i++) + { + producer.send(senderSession.createTextMessage("Msg " + i)); + Thread.sleep(500); + assertNotNull("Expected to received message", consumer.receive(500)); + // Consumer does not ack the message in order to generate no bytes from consumer back to Broker + } + + assertTrue("Too few heartbeats sent "+ receiveListener.getHeartbeatsSent() +" (expected at least 2)", receiveListener.getHeartbeatsSent()>=2); + assertEquals("Unexpected number of heartbeats sent by the sender: ",0,sendListener.getHeartbeatsSent()); + + assertTrue("Too few heartbeats received at the sender "+ sendListener.getHeartbeatsReceived() +" (expected at least 2)", sendListener.getHeartbeatsReceived()>=2); + assertEquals("Unexpected number of heartbeats received by the receiver: ",0,receiveListener.getHeartbeatsReceived()); + + receiveConn.close(); + sendConn.close(); + } + + public void testHeartbeatsEnabledBrokerSide() throws Exception + { + + AMQConnection conn = (AMQConnection) getConnection(); + conn.setHeartbeatListener(_listener); + conn.start(); + + Thread.sleep(2500); + + assertTrue("Too few heartbeats received: "+_listener.getHeartbeatsReceived() +" (expected at least 2)", _listener.getHeartbeatsReceived()>=2); + assertTrue("Too few heartbeats sent "+ _listener.getHeartbeatsSent() +" (expected at least 2)", _listener.getHeartbeatsSent() >=2); + + conn.close(); + } + + + @SuppressWarnings("deprecation") + public void testHeartbeatsEnabledUsingAmqjLegacySystemProperty() throws Exception + { + setTestSystemProperty(AMQJ_HEARTBEAT_DELAY, "1"); + AMQConnection conn = (AMQConnection) getConnection(); + conn.setHeartbeatListener(_listener); + conn.start(); + + Thread.sleep(2500); + + assertTrue("Too few heartbeats received: "+_listener.getHeartbeatsReceived()+" (expected at least 2)", _listener.getHeartbeatsReceived()>=2); + assertTrue("Too few heartbeats sent "+_listener.getHeartbeatsSent() +" (expected at least 2)", _listener.getHeartbeatsSent()>=2); + + conn.close(); + } + + @SuppressWarnings("deprecation") + public void testHeartbeatsEnabledUsingOlderLegacySystemProperty() throws Exception + { + setTestSystemProperty(IDLE_TIMEOUT_PROP_NAME, "1000"); + AMQConnection conn = (AMQConnection) getConnection(); + conn.setHeartbeatListener(_listener); + conn.start(); + + Thread.sleep(2500); + + assertTrue("Too few heartbeats received: "+_listener.getHeartbeatsReceived() +" (expected at least 2)", _listener.getHeartbeatsReceived()>=2); + assertTrue("Too few heartbeats sent "+_listener.getHeartbeatsSent() +" (expected at least 2)", _listener.getHeartbeatsSent()>=2); + + conn.close(); + } + + private class TestListener implements HeartbeatListener + { + private final String _name; + private final AtomicInteger _heartbeatsReceived = new AtomicInteger(0); + private final AtomicInteger _heartbeatsSent = new AtomicInteger(0); + + public TestListener(String name) + { + _name = name; + } + + @Override + public void heartbeatReceived() + { + LOGGER.debug(_name + " heartbeat received"); + _heartbeatsReceived.incrementAndGet(); + } + + public int getHeartbeatsReceived() + { + return _heartbeatsReceived.get(); + } + + @Override + public void heartbeatSent() + { + LOGGER.debug(_name + " heartbeat sent"); + _heartbeatsSent.incrementAndGet(); + } + + public int getHeartbeatsSent() + { + return _heartbeatsSent.get(); + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/client/SessionCreateTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/client/SessionCreateTest.java new file mode 100644 index 0000000000..08ed2258b2 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/client/SessionCreateTest.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.client; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.Session; + + +/** + * Class to check that session creation on a connection has no accidental limit + */ +public class SessionCreateTest extends QpidBrokerTestCase +{ + private static final Logger LOGGER = LoggerFactory.getLogger(SessionCreateTest.class); + + private Connection _clientConnection; + protected int maxSessions = 65555; + + public void testSessionCreationLimit() throws Exception + { + // Create Client + _clientConnection = getConnection("guest", "guest"); + + _clientConnection.start(); + + for (int i=0; i < maxSessions; i++) + { + Session sess = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + assertNotNull(sess); + sess.close(); + LOGGER.debug("created session: " + i); + } + + _clientConnection.close(); + + } + +} \ No newline at end of file diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/client/SynchReceiveTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/client/SynchReceiveTest.java new file mode 100644 index 0000000000..bf147197e4 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/client/SynchReceiveTest.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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; + +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class SynchReceiveTest extends QpidBrokerTestCase +{ + private static final long AWAIT_MESSAGE_TIMEOUT = 2000; + private static final long AWAIT_MESSAGE_TIMEOUT_NEGATIVE = 250; + private static final int MSG_COUNT = 10; + private final String _testQueueName = getTestQueueName(); + private Connection _consumerConnection; + private Session _consumerSession; + private MessageConsumer _consumer; + private Queue _queue; + + protected void setUp() throws Exception + { + super.setUp(); + + _consumerConnection = getConnection(); + _consumerConnection.start(); + _consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _queue = _consumerSession.createQueue(_testQueueName); + _consumer = _consumerSession.createConsumer(_queue); + + // Populate queue + Connection producerConnection = getConnection(); + Session producerSession = producerConnection.createSession(true, Session.SESSION_TRANSACTED); + sendMessage(producerSession, _queue, MSG_COUNT); + producerConnection.close(); + } + + public void testReceiveWithTimeout() throws Exception + { + for (int msg = 0; msg < MSG_COUNT; msg++) + { + assertNotNull("Expected message number " + msg, _consumer.receive(AWAIT_MESSAGE_TIMEOUT)); + } + + assertNull("Received too many messages", _consumer.receive(500)); + } + + public void testReceiveNoWait() throws Exception + { + for (int msg = 0; msg < MSG_COUNT; msg++) + { + assertNotNull("Expected message number " + msg, _consumer.receiveNoWait()); + } + + assertNull("Received too many messages", _consumer.receive(500)); + } + + public void testTwoConsumersInterleaved() throws Exception + { + //create a new connection with prefetch set to 1 + _consumerConnection.close(); + setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, new Integer(1).toString()); + + _consumerConnection = getConnection(); + _consumerConnection.start(); + Session consumerSession1 = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer1 = consumerSession1.createConsumer(_queue); + + Session consumerSession2 = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer2 = consumerSession2.createConsumer(_queue); + + final int maxLoops = MSG_COUNT * 2; + int msg = 0; + int loops = 0; + while(msg < MSG_COUNT && loops < maxLoops) + { + if (consumer1.receive(AWAIT_MESSAGE_TIMEOUT) != null) + { + msg++; + } + + if (consumer2.receive(AWAIT_MESSAGE_TIMEOUT) != null) + { + msg++; + } + + loops++; + } + + assertEquals("Not all messages received.", MSG_COUNT, msg); + assertNull("Received too many messages", consumer1.receive(AWAIT_MESSAGE_TIMEOUT_NEGATIVE)); + assertNull("Received too many messages", consumer2.receive(AWAIT_MESSAGE_TIMEOUT_NEGATIVE)); + } + + public void testIdleSecondConsumer() throws Exception + { + Session idleSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + @SuppressWarnings("unused") + MessageConsumer idleConsumerOnSameQueue = idleSession.createConsumer(_queue); + + // Since we don't call receive on the idle consumer, all messages will flow to other + + for (int msg = 0; msg < MSG_COUNT; msg++) + { + assertNotNull("Expected message number " + msg, _consumer.receive(AWAIT_MESSAGE_TIMEOUT)); + } + + assertNull("Received too many messages", _consumer.receive(AWAIT_MESSAGE_TIMEOUT_NEGATIVE)); + } + + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/client/failover/AddressBasedFailoverBehaviourTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/client/failover/AddressBasedFailoverBehaviourTest.java new file mode 100644 index 0000000000..99fcbc5dc0 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/client/failover/AddressBasedFailoverBehaviourTest.java @@ -0,0 +1,34 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.failover; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Session; + +public class AddressBasedFailoverBehaviourTest extends FailoverBehaviourTest +{ + @Override + protected Destination createDestination(Session session) throws JMSException + { + return session.createQueue("ADDR:" +getTestQueueName() + "_" + System.currentTimeMillis() + "; {create: always}"); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/client/failover/FailoverBehaviourTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/client/failover/FailoverBehaviourTest.java new file mode 100644 index 0000000000..3331a8a665 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/client/failover/FailoverBehaviourTest.java @@ -0,0 +1,1436 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.failover; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQConnectionFactory; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.jms.BrokerDetails; +import org.apache.qpid.jms.ConnectionListener; +import org.apache.qpid.jms.FailoverPolicy; +import org.apache.qpid.test.utils.FailoverBaseCase; +import org.apache.qpid.url.URLSyntaxException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.ExceptionListener; +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.QueueBrowser; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.TransactionRolledBackException; +import javax.naming.NamingException; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Test suite to test all possible failover corner cases + */ +public class FailoverBehaviourTest extends FailoverBaseCase implements ConnectionListener, ExceptionListener +{ + protected static final Logger _LOGGER = LoggerFactory.getLogger(FailoverBehaviourTest.class); + + private static final String TEST_MESSAGE_FORMAT = "test message {0}"; + + /** Indicates whether tests are run against clustered broker */ + private static boolean CLUSTERED = Boolean.getBoolean("profile.clustered"); + + /** Default number of messages to send before failover */ + private static final int DEFAULT_NUMBER_OF_MESSAGES = 40; + + /** Actual number of messages to send before failover */ + protected int _messageNumber = Integer.getInteger("profile.failoverMsgCount", DEFAULT_NUMBER_OF_MESSAGES); + + /** Test connection */ + protected Connection _connection; + + /** + * Failover completion latch is used to wait till connectivity to broker is + * restored + */ + private CountDownLatch _failoverComplete; + + /** + * Consumer session + */ + private Session _consumerSession; + + /** + * Test destination + */ + private Destination _destination; + + /** + * Consumer + */ + private MessageConsumer _consumer; + + /** + * Producer session + */ + private Session _producerSession; + + /** + * Producer + */ + private MessageProducer _producer; + + /** + * Holds exception sent into {@link ExceptionListener} on failover + */ + private JMSException _exceptionListenerException; + + /** + * Latch to check that failover mutex is hold by a failover thread + */ + private CountDownLatch _failoverStarted; + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + _connection = getConnection(); + _connection.setExceptionListener(this); + ((AMQConnection) _connection).setConnectionListener(this); + _failoverComplete = new CountDownLatch(1); + _failoverStarted = new CountDownLatch(1); + } + + /** + * Test whether MessageProducer can successfully publish messages after + * failover and rollback transaction + */ + public void testMessageProducingAndRollbackAfterFailover() throws Exception + { + init(Session.SESSION_TRANSACTED, true); + produceMessages(); + causeFailure(); + + assertFailoverException(); + // producer should be able to send messages after failover + _producer.send(_producerSession.createTextMessage("test message " + _messageNumber)); + + // rollback after failover + _producerSession.rollback(); + + // tests whether sending and committing is working after failover + produceMessages(); + _producerSession.commit(); + + // tests whether receiving and committing is working after failover + consumeMessages(); + _consumerSession.commit(); + } + + /** + * Test whether {@link TransactionRolledBackException} is thrown on commit + * of dirty transacted session after failover. + *

+ * Verifies whether second after failover commit is successful. + */ + public void testTransactionRolledBackExceptionThrownOnCommitAfterFailoverOnProducingMessages() throws Exception + { + init(Session.SESSION_TRANSACTED, true); + produceMessages(); + causeFailure(); + + assertFailoverException(); + + // producer should be able to send messages after failover + _producer.send(_producerSession.createTextMessage("test message " + _messageNumber)); + + try + { + _producerSession.commit(); + fail("TransactionRolledBackException is expected on commit after failover with dirty session!"); + } + catch (JMSException t) + { + assertTrue("Expected TransactionRolledBackException but thrown " + t, + t instanceof TransactionRolledBackException); + } + + // simulate process of user replaying the transaction + produceMessages("replayed test message {0}", _messageNumber, false); + + // no exception should be thrown + _producerSession.commit(); + + // only messages sent after rollback should be received + consumeMessages("replayed test message {0}", _messageNumber); + + // no exception should be thrown + _consumerSession.commit(); + } + + /** + * Tests JMSException is not thrown on commit with a clean session after + * failover + */ + public void testNoJMSExceptionThrownOnCommitAfterFailoverWithCleanProducerSession() throws Exception + { + init(Session.SESSION_TRANSACTED, true); + + causeFailure(); + + assertFailoverException(); + + // should not throw an exception for a clean session + _producerSession.commit(); + + // tests whether sending and committing is working after failover + produceMessages(); + _producerSession.commit(); + + // tests whether receiving and committing is working after failover + consumeMessages(); + _consumerSession.commit(); + } + + /** + * Tests {@link TransactionRolledBackException} is thrown on commit of dirty + * transacted session after failover. + *

+ * Verifies whether second after failover commit is successful. + */ + public void testTransactionRolledBackExceptionThrownOnCommitAfterFailoverOnMessageReceiving() throws Exception + { + init(Session.SESSION_TRANSACTED, true); + produceMessages(); + _producerSession.commit(); + + // receive messages but do not commit + consumeMessages(); + + causeFailure(); + + assertFailoverException(); + + try + { + // should throw TransactionRolledBackException + _consumerSession.commit(); + fail("TransactionRolledBackException is expected on commit after failover"); + } + catch (Exception t) + { + assertTrue("Expected TransactionRolledBackException but thrown " + t, + t instanceof TransactionRolledBackException); + } + + resendMessagesIfNecessary(); + + // consume messages successfully + consumeMessages(); + _consumerSession.commit(); + } + + /** + * Tests JMSException is not thrown on commit with a clean session after failover + */ + public void testNoJMSExceptionThrownOnCommitAfterFailoverWithCleanConsumerSession() throws Exception + { + init(Session.SESSION_TRANSACTED, true); + produceMessages(); + _producerSession.commit(); + + consumeMessages(); + _consumerSession.commit(); + + causeFailure(); + + assertFailoverException(); + + // should not throw an exception with a clean consumer session + _consumerSession.commit(); + } + + /** + * Test that TransactionRolledBackException is thrown on commit of + * dirty session in asynchronous consumer after failover. + */ + public void testTransactionRolledBackExceptionThrownOnCommitAfterFailoverOnReceivingMessagesAsynchronously() + throws Exception + { + init(Session.SESSION_TRANSACTED, false); + FailoverTestMessageListener ml = new FailoverTestMessageListener(); + _consumer.setMessageListener(ml); + + _connection.start(); + + produceMessages(); + _producerSession.commit(); + + // wait for message receiving + ml.awaitForEnd(); + + assertEquals("Received unexpected number of messages!", _messageNumber, ml.getMessageCounter()); + + // assert messages + int counter = 0; + for (Message message : ml.getReceivedMessages()) + { + assertReceivedMessage(message, TEST_MESSAGE_FORMAT, counter++); + } + ml.reset(); + + causeFailure(); + assertFailoverException(); + + + try + { + _consumerSession.commit(); + fail("TransactionRolledBackException should be thrown!"); + } + catch (TransactionRolledBackException e) + { + // that is what is expected + } + + resendMessagesIfNecessary(); + + // wait for message receiving + ml.awaitForEnd(); + + assertEquals("Received unexpected number of messages!", _messageNumber, ml.getMessageCounter()); + + // assert messages + counter = 0; + for (Message message : ml.getReceivedMessages()) + { + assertReceivedMessage(message, TEST_MESSAGE_FORMAT, counter++); + } + + // commit again. It should be successful + _consumerSession.commit(); + } + + /** + * Test that {@link Session#rollback()} does not throw exception after failover + * and that we are able to consume messages. + */ + public void testRollbackAfterFailover() throws Exception + { + init(Session.SESSION_TRANSACTED, true); + + produceMessages(); + _producerSession.commit(); + + consumeMessages(); + + causeFailure(); + + assertFailoverException(); + + _consumerSession.rollback(); + + resendMessagesIfNecessary(); + + // tests whether receiving and committing is working after failover + consumeMessages(); + _consumerSession.commit(); + } + + /** + * Test that {@link Session#rollback()} does not throw exception after receiving further messages + * after failover, and we can receive published messages after rollback. + */ + public void testRollbackAfterReceivingAfterFailover() throws Exception + { + init(Session.SESSION_TRANSACTED, true); + + produceMessages(); + _producerSession.commit(); + + consumeMessages(); + causeFailure(); + + assertFailoverException(); + + resendMessagesIfNecessary(); + + consumeMessages(); + + _consumerSession.rollback(); + + // tests whether receiving and committing is working after failover + consumeMessages(); + _consumerSession.commit(); + } + + /** + * Test that {@link Session#recover()} does not throw an exception after failover + * and that we can consume messages after recover. + */ + public void testRecoverAfterFailover() throws Exception + { + init(Session.CLIENT_ACKNOWLEDGE, true); + + produceMessages(); + + // consume messages but do not acknowledge them + consumeMessages(); + + causeFailure(); + + assertFailoverException(); + + _consumerSession.recover(); + + resendMessagesIfNecessary(); + + // tests whether receiving and acknowledgment is working after recover + Message lastMessage = consumeMessages(); + lastMessage.acknowledge(); + } + + /** + * Test that receiving more messages after failover and then calling + * {@link Session#recover()} does not throw an exception + * and that we can consume messages after recover. + */ + public void testRecoverWithConsumedMessagesAfterFailover() throws Exception + { + init(Session.CLIENT_ACKNOWLEDGE, true); + + produceMessages(); + + // consume messages but do not acknowledge them + consumeMessages(); + + causeFailure(); + + assertFailoverException(); + + // publishing should work after failover + resendMessagesIfNecessary(); + + // consume messages again on a dirty session + consumeMessages(); + + // recover should successfully restore session + _consumerSession.recover(); + + // tests whether receiving and acknowledgment is working after recover + Message lastMessage = consumeMessages(); + lastMessage.acknowledge(); + } + + /** + * Test that first call to {@link Message#acknowledge()} after failover + * throws a JMSEXception if session is dirty. + */ + public void testAcknowledgeAfterFailover() throws Exception + { + init(Session.CLIENT_ACKNOWLEDGE, true); + + produceMessages(); + + // consume messages but do not acknowledge them + Message lastMessage = consumeMessages(); + causeFailure(); + + assertFailoverException(); + + try + { + // an implicit recover performed when acknowledge throws an exception due to failover + lastMessage.acknowledge(); + fail("JMSException should be thrown"); + } + catch (JMSException t) + { + // TODO: assert error code and/or expected exception type + } + + resendMessagesIfNecessary(); + + // tests whether receiving and acknowledgment is working after recover + lastMessage = consumeMessages(); + lastMessage.acknowledge(); + } + + /** + * Test that calling acknowledge before failover leaves the session + * clean for use after failover. + */ + public void testAcknowledgeBeforeFailover() throws Exception + { + init(Session.CLIENT_ACKNOWLEDGE, true); + + produceMessages(); + + // consume messages and acknowledge them + Message lastMessage = consumeMessages(); + lastMessage.acknowledge(); + + causeFailure(); + + assertFailoverException(); + + produceMessages(); + + // tests whether receiving and acknowledgment is working after recover + lastMessage = consumeMessages(); + lastMessage.acknowledge(); + } + + /** + * Test that receiving of messages after failover prior to calling + * {@link Message#acknowledge()} still results in acknowledge throwing an exception. + */ + public void testAcknowledgeAfterMessageReceivingAfterFailover() throws Exception + { + init(Session.CLIENT_ACKNOWLEDGE, true); + + produceMessages(); + + // consume messages but do not acknowledge them + consumeMessages(); + causeFailure(); + + assertFailoverException(); + + resendMessagesIfNecessary(); + + // consume again on dirty session + Message lastMessage = consumeMessages(); + try + { + // an implicit recover performed when acknowledge throws an exception due to failover + lastMessage.acknowledge(); + fail("JMSException should be thrown"); + } + catch (JMSException t) + { + // TODO: assert error code and/or expected exception type + } + + // tests whether receiving and acknowledgment is working on a clean session + lastMessage = consumeMessages(); + lastMessage.acknowledge(); + } + + /** + * Tests that call to {@link Message#acknowledge()} after failover throws an exception in asynchronous consumer + * and we can consume messages after acknowledge. + */ + public void testAcknowledgeAfterFailoverForAsynchronousConsumer() throws Exception + { + init(Session.CLIENT_ACKNOWLEDGE, false); + FailoverTestMessageListener ml = new FailoverTestMessageListener(); + _consumer.setMessageListener(ml); + _connection.start(); + + produceMessages(); + + // wait for message receiving + ml.awaitForEnd(); + + assertEquals("Received unexpected number of messages!", _messageNumber, ml.getMessageCounter()); + + // assert messages + int counter = 0; + Message currentMessage = null; + for (Message message : ml.getReceivedMessages()) + { + assertReceivedMessage(message, TEST_MESSAGE_FORMAT, counter++); + currentMessage = message; + } + ml.reset(); + + causeFailure(); + assertFailoverException(); + + + try + { + currentMessage.acknowledge(); + fail("JMSException should be thrown!"); + } + catch (JMSException e) + { + // TODO: assert error code and/or expected exception type + } + + resendMessagesIfNecessary(); + + // wait for message receiving + ml.awaitForEnd(); + + assertEquals("Received unexpected number of messages!", _messageNumber, ml.getMessageCounter()); + + // assert messages + counter = 0; + for (Message message : ml.getReceivedMessages()) + { + assertReceivedMessage(message, TEST_MESSAGE_FORMAT, counter++); + currentMessage = message; + } + + // acknowledge again. It should be successful + currentMessage.acknowledge(); + } + + /** + * Test whether {@link Session#recover()} works as expected after failover + * in AA mode. + */ + public void testRecoverAfterFailoverInAutoAcknowledgeMode() throws Exception + { + init(Session.AUTO_ACKNOWLEDGE, true); + + produceMessages(); + + // receive first message in order to start a dispatcher thread + Message receivedMessage = _consumer.receive(1000l); + assertReceivedMessage(receivedMessage, TEST_MESSAGE_FORMAT, 0); + + causeFailure(); + + assertFailoverException(); + + _consumerSession.recover(); + + resendMessagesIfNecessary(); + + // tests whether receiving is working after recover + consumeMessages(); + } + + public void testClientAcknowledgedSessionCloseAfterFailover() throws Exception + { + sessionCloseAfterFailoverImpl(Session.CLIENT_ACKNOWLEDGE); + } + + public void testTransactedSessionCloseAfterFailover() throws Exception + { + sessionCloseAfterFailoverImpl(Session.SESSION_TRANSACTED); + } + + public void testAutoAcknowledgedSessionCloseAfterFailover() throws Exception + { + sessionCloseAfterFailoverImpl(Session.AUTO_ACKNOWLEDGE); + } + + public void testPublishAutoAcknowledgedWhileFailover() throws Exception + { + publishWhileFailingOver(Session.AUTO_ACKNOWLEDGE); + } + + public void testPublishClientAcknowledgedWhileFailover() throws Exception + { + Message receivedMessage = publishWhileFailingOver(Session.CLIENT_ACKNOWLEDGE); + receivedMessage.acknowledge(); + } + + public void testPublishTransactedAcknowledgedWhileFailover() throws Exception + { + publishWhileFailingOver(Session.SESSION_TRANSACTED); + _consumerSession.commit(); + } + + public void testPublishAutoAcknowledgedWithFailoverMutex() throws Exception + { + publishWithFailoverMutex(Session.AUTO_ACKNOWLEDGE); + } + + public void testPublishClientAcknowledgedWithFailoverMutex() throws Exception + { + publishWithFailoverMutex(Session.CLIENT_ACKNOWLEDGE); + + } + + public void testPublishTransactedAcknowledgedWithFailoverMutex() throws Exception + { + publishWithFailoverMutex(Session.SESSION_TRANSACTED); + } + + public void testClientAcknowledgedSessionCloseWhileFailover() throws Exception + { + sessionCloseWhileFailoverImpl(Session.CLIENT_ACKNOWLEDGE); + } + + public void testTransactedSessionCloseWhileFailover() throws Exception + { + sessionCloseWhileFailoverImpl(Session.SESSION_TRANSACTED); + } + + public void testAutoAcknowledgedSessionCloseWhileFailover() throws Exception + { + sessionCloseWhileFailoverImpl(Session.AUTO_ACKNOWLEDGE); + } + + public void testClientAcknowledgedQueueBrowserCloseWhileFailover() throws Exception + { + browserCloseWhileFailoverImpl(Session.CLIENT_ACKNOWLEDGE); + } + + public void testTransactedQueueBrowserCloseWhileFailover() throws Exception + { + browserCloseWhileFailoverImpl(Session.SESSION_TRANSACTED); + } + + public void testAutoAcknowledgedQueueBrowserCloseWhileFailover() throws Exception + { + browserCloseWhileFailoverImpl(Session.AUTO_ACKNOWLEDGE); + } + + private Message publishWhileFailingOver(int autoAcknowledge) throws JMSException, InterruptedException + { + setDelayedFailoverPolicy(5); + init(autoAcknowledge, true); + + String text = MessageFormat.format(TEST_MESSAGE_FORMAT, 0); + Message message = _producerSession.createTextMessage(text); + + failBroker(getFailingPort()); + + if(!_failoverStarted.await(5, TimeUnit.SECONDS)) + { + fail("Did not receieve notification failover had started"); + } + + _producer.send(message); + + if (_producerSession.getTransacted()) + { + _producerSession.commit(); + } + + Message receivedMessage = _consumer.receive(1000l); + assertReceivedMessage(receivedMessage, TEST_MESSAGE_FORMAT, 0); + return receivedMessage; + } + + private void publishWithFailoverMutex(int autoAcknowledge) throws JMSException, InterruptedException + { + setDelayedFailoverPolicy(5); + init(autoAcknowledge, true); + + String text = MessageFormat.format(TEST_MESSAGE_FORMAT, 0); + Message message = _producerSession.createTextMessage(text); + + AMQConnection connection = (AMQConnection)_connection; + + // holding failover mutex should prevent the failover from + // proceeding before we try to send the message + synchronized(connection.getFailoverMutex()) + { + failBroker(getFailingPort()); + + // wait to make sure that connection is lost + while(!connection.isFailingOver()) + { + Thread.sleep(25l); + } + + try + { + _producer.send(message); + fail("Sending should fail because connection was lost and failover has not yet completed"); + } + catch(JMSException e) + { + // JMSException is expected + } + } + // wait for failover completion, thus ensuring it actually + //got started, before allowing the test to tear down + awaitForFailoverCompletion(DEFAULT_FAILOVER_TIME); + } + + /** + * This test only tests 0-8/0-9/0-9-1 failover timeout + */ + public void testFailoverHandlerTimeoutExpires() throws Exception + { + _connection.close(); + setTestSystemProperty("qpid.failover_method_timeout", "10000"); + AMQConnection connection = null; + try + { + connection = createConnectionWithFailover(); + + // holding failover mutex should prevent the failover from proceeding + synchronized(connection.getFailoverMutex()) + { + killBroker(); + startBroker(); + + // sleep interval exceeds failover timeout interval + Thread.sleep(11000l); + } + + // allows the failover thread to proceed + Thread.yield(); + assertFalse("Unexpected failover", _failoverComplete.await(2000l, TimeUnit.MILLISECONDS)); + assertTrue("Failover should not succeed due to timeout", connection.isClosed()); + } + finally + { + if (connection != null) + { + connection.close(); + } + } + } + + public void testFailoverHandlerTimeoutReconnected() throws Exception + { + _connection.close(); + setTestSystemProperty("qpid.failover_method_timeout", "10000"); + AMQConnection connection = null; + try + { + connection = createConnectionWithFailover(); + + // holding failover mutex should prevent the failover from proceeding + synchronized(connection.getFailoverMutex()) + { + killBroker(); + startBroker(); + } + + // allows the failover thread to proceed + Thread.yield(); + awaitForFailoverCompletion(DEFAULT_FAILOVER_TIME); + assertFalse("Failover should restore connectivity", connection.isClosed()); + } + finally + { + if (connection != null) + { + connection.close(); + } + } + } + + /** + * Tests that the producer flow control flag is reset when failover occurs while + * the producers are being blocked by the broker. + * + * Uses Java broker specific queue configuration to enabled PSFC. + */ + public void testFlowControlFlagResetOnFailover() throws Exception + { + // we do not need the connection failing to second broker + _connection.close(); + + // make sure that failover timeout is bigger than flow control timeout + setTestSystemProperty("qpid.failover_method_timeout", "60000"); + setTestSystemProperty("qpid.flow_control_wait_failure", "10000"); + + AMQConnection connection = null; + try + { + connection = createConnectionWithFailover(); + + final Session producerSession = connection.createSession(true, Session.SESSION_TRANSACTED); + final Queue queue = createAndBindQueueWithFlowControlEnabled(producerSession, getTestQueueName(), DEFAULT_MESSAGE_SIZE * 3, DEFAULT_MESSAGE_SIZE * 2); + final AtomicInteger counter = new AtomicInteger(); + // try to send 5 messages (should block after 4) + new Thread(new Runnable() + { + @Override + public void run() + { + try + { + MessageProducer producer = producerSession.createProducer(queue); + for (int i=0; i < 5; i++) + { + Message next = createNextMessage(producerSession, i); + producer.send(next); + producerSession.commit(); + counter.incrementAndGet(); + } + } + catch(Exception e) + { + // ignore + } + } + }).start(); + + long limit= 30000l; + long start = System.currentTimeMillis(); + + // wait until session is blocked + while(!((AMQSession)producerSession).isFlowBlocked() && System.currentTimeMillis() - start < limit) + { + Thread.sleep(100l); + } + + assertTrue("Flow is not blocked", ((AMQSession) producerSession).isFlowBlocked()); + // Message counter could be 3 or 4 depending on the progression of producing thread relative + // to the receipt of the ChannelFlow. + final int currentCounter = counter.get(); + assertTrue("Unexpected number of sent messages", currentCounter == 3 || currentCounter == 4); + + killBroker(); + startBroker(); + + // allows the failover thread to proceed + Thread.yield(); + awaitForFailoverCompletion(60000l); + + assertFalse("Flow is blocked", ((AMQSession) producerSession).isFlowBlocked()); + } + finally + { + if (connection != null) + { + connection.close(); + } + } + } + + private Queue createAndBindQueueWithFlowControlEnabled(Session session, String queueName, int capacity, int resumeCapacity) throws Exception + { + final Map arguments = new HashMap(); + arguments.put("x-qpid-capacity", capacity); + arguments.put("x-qpid-flow-resume-capacity", resumeCapacity); + ((AMQSession) session).createQueue(new AMQShortString(queueName), false, true, false, arguments); + Queue queue = session.createQueue("direct://amq.direct/" + queueName + "/" + queueName + "?durable='" + true + + "'&autodelete='" + false + "'"); + ((AMQSession) session).declareAndBind((AMQDestination) queue); + return queue; + } + + private AMQConnection createConnectionWithFailover() throws NamingException, JMSException, URLSyntaxException + { + BrokerDetails origBrokerDetails = ((AMQConnectionFactory) getConnectionFactory("default")).getConnectionURL().getBrokerDetails(0); + + String retries = "200"; + String connectdelay = "1000"; + String cycleCount = "2"; + + String newUrlFormat="amqp://username:password@clientid/test?brokerlist=" + + "'tcp://%s:%s?retries='%s'&connectdelay='%s''&failover='singlebroker?cyclecount='%s''"; + + String newUrl = String.format(newUrlFormat, origBrokerDetails.getHost(), origBrokerDetails.getPort(), + retries, connectdelay, cycleCount); + + ConnectionFactory connectionFactory = new AMQConnectionFactory(newUrl); + AMQConnection connection = (AMQConnection) connectionFactory.createConnection("admin", "admin"); + connection.setConnectionListener(this); + return connection; + } + + /** + * Tests {@link Session#close()} for session with given acknowledge mode + * to ensure that close works after failover. + * + * @param acknowledgeMode session acknowledge mode + * @throws JMSException + */ + private void sessionCloseAfterFailoverImpl(int acknowledgeMode) throws JMSException + { + init(acknowledgeMode, true); + produceMessages(TEST_MESSAGE_FORMAT, _messageNumber, false); + if (acknowledgeMode == Session.SESSION_TRANSACTED) + { + _producerSession.commit(); + } + + // intentionally receive message but do not commit or acknowledge it in + // case of transacted or CLIENT_ACK session + Message receivedMessage = _consumer.receive(1000l); + assertReceivedMessage(receivedMessage, TEST_MESSAGE_FORMAT, 0); + + causeFailure(); + + assertFailoverException(); + + // for transacted/client_ack session + // no exception should be thrown but transaction should be automatically + // rolled back + _consumerSession.close(); + } + + /** + * A helper method to instantiate produce and consumer sessions, producer + * and consumer. + * + * @param acknowledgeMode + * acknowledge mode + * @param startConnection + * indicates whether connection should be started + * @throws JMSException + */ + private void init(int acknowledgeMode, boolean startConnection) throws JMSException + { + boolean isTransacted = acknowledgeMode == Session.SESSION_TRANSACTED ? true : false; + + _consumerSession = _connection.createSession(isTransacted, acknowledgeMode); + _destination = createDestination(_consumerSession); + _consumer = _consumerSession.createConsumer(_destination); + + if (startConnection) + { + _connection.start(); + } + + _producerSession = _connection.createSession(isTransacted, acknowledgeMode); + _producer = _producerSession.createProducer(_destination); + + } + + protected Destination createDestination(Session session) throws JMSException + { + return session.createQueue(getTestQueueName() + "_" + System.currentTimeMillis()); + } + + /** + * Resends messages if reconnected to a non-clustered broker + * + * @throws JMSException + */ + private void resendMessagesIfNecessary() throws JMSException + { + if (!CLUSTERED) + { + // assert that a new broker does not have messages on a queue + if (_consumer.getMessageListener() == null) + { + Message message = _consumer.receive(100l); + assertNull("Received a message after failover with non-clustered broker!", message); + } + // re-sending messages if reconnected to a non-clustered broker + produceMessages(true); + } + } + + /** + * Produces a default number of messages with default text content into test + * queue + * + * @throws JMSException + */ + private void produceMessages() throws JMSException + { + produceMessages(false); + } + + private void produceMessages(boolean seperateProducer) throws JMSException + { + produceMessages(TEST_MESSAGE_FORMAT, _messageNumber, seperateProducer); + } + + /** + * Consumes a default number of messages and asserts their content. + * + * @return last consumed message + * @throws JMSException + */ + private Message consumeMessages() throws JMSException + { + return consumeMessages(TEST_MESSAGE_FORMAT, _messageNumber); + } + + /** + * Produces given number of text messages with content matching given + * content pattern + * + * @param messagePattern message content pattern + * @param messageNumber number of messages to send + * @param standaloneProducer whether to use the existing producer or a new one. + * @throws JMSException + */ + private void produceMessages(String messagePattern, int messageNumber, boolean standaloneProducer) throws JMSException + { + Session producerSession; + MessageProducer producer; + + if(standaloneProducer) + { + producerSession = _connection.createSession(true, Session.SESSION_TRANSACTED); + producer = producerSession.createProducer(_destination); + } + else + { + producerSession = _producerSession; + producer = _producer; + } + + for (int i = 0; i < messageNumber; i++) + { + String text = MessageFormat.format(messagePattern, i); + Message message = producerSession.createTextMessage(text); + producer.send(message); + _LOGGER.debug("Test message number " + i + " produced with text = " + text + ", and JMSMessageID = " + message.getJMSMessageID()); + } + + if(standaloneProducer) + { + producerSession.commit(); + } + } + + /** + * Consumes given number of text messages and asserts that their content + * matches given pattern + * + * @param messagePattern + * messages content pattern + * @param messageNumber + * message number to received + * @return last consumed message + * @throws JMSException + */ + private Message consumeMessages(String messagePattern, int messageNumber) throws JMSException + { + Message receivedMesssage = null; + for (int i = 0; i < messageNumber; i++) + { + receivedMesssage = _consumer.receive(1000l); + assertReceivedMessage(receivedMesssage, messagePattern, i); + } + return receivedMesssage; + } + + /** + * Asserts received message + * + * @param receivedMessage + * received message + * @param messagePattern + * messages content pattern + * @param messageIndex + * message index + */ + private void assertReceivedMessage(Message receivedMessage, String messagePattern, int messageIndex) throws JMSException + { + assertNotNull("Expected message [" + messageIndex + "] is not received!", receivedMessage); + assertTrue("Failure to receive message [" + messageIndex + "], expected TextMessage but received " + + receivedMessage, receivedMessage instanceof TextMessage); + String expectedText = MessageFormat.format(messagePattern, messageIndex); + String receivedText = null; + try + { + receivedText = ((TextMessage) receivedMessage).getText(); + } + catch (JMSException e) + { + fail("JMSException occured while getting message text:" + e.getMessage()); + } + _LOGGER.debug("Test message number " + messageIndex + " consumed with text = " + receivedText + ", and JMSMessageID = " + receivedMessage.getJMSMessageID()); + assertEquals("Failover is broken! Expected [" + expectedText + "] but got [" + receivedText + "]", + expectedText, receivedText); + } + + /** + * Causes failover and waits till connection is re-established. + */ + private void causeFailure() + { + causeFailure(getFailingPort(), DEFAULT_FAILOVER_TIME * 2); + } + + /** + * Causes failover by stopping broker on given port and waits till + * connection is re-established during given time interval. + * + * @param port + * broker port + * @param delay + * time interval to wait for connection re-establishement + */ + private void causeFailure(int port, long delay) + { + failBroker(port); + + awaitForFailoverCompletion(delay); + } + + private void awaitForFailoverCompletion(long delay) + { + _logger.info("Awaiting Failover completion.."); + try + { + if (!_failoverComplete.await(delay, TimeUnit.MILLISECONDS)) + { + fail("Failover did not complete"); + } + } + catch (InterruptedException e) + { + fail("Test was interrupted:" + e.getMessage()); + } + } + + private void assertFailoverException() + { + // TODO: assert exception is received (once implemented) + // along with error code and/or expected exception type + } + + @Override + public void bytesSent(long count) + { + } + + @Override + public void bytesReceived(long count) + { + } + + @Override + public boolean preFailover(boolean redirect) + { + _failoverStarted.countDown(); + return true; + } + + @Override + public boolean preResubscribe() + { + return true; + } + + @Override + public void failoverComplete() + { + _failoverComplete.countDown(); + } + + @Override + public void onException(JMSException e) + { + _exceptionListenerException = e; + } + + /** + * Causes 1 second delay before reconnect in order to test whether JMS + * methods block while failover is in progress + */ + private static class DelayingFailoverPolicy extends FailoverPolicy + { + + private CountDownLatch _suspendLatch; + private long _delay; + + public DelayingFailoverPolicy(AMQConnection connection, long delay) + { + super(connection.getConnectionURL(), connection); + _suspendLatch = new CountDownLatch(1); + _delay = delay; + } + + public void attainedConnection() + { + try + { + _suspendLatch.await(_delay, TimeUnit.SECONDS); + } + catch (InterruptedException e) + { + // continue + } + super.attainedConnection(); + } + + } + + + private class FailoverTestMessageListener implements MessageListener + { + // message counter + private AtomicInteger _counter = new AtomicInteger(); + + private List _receivedMessage = new ArrayList(); + + private volatile CountDownLatch _endLatch; + + public FailoverTestMessageListener() throws JMSException + { + _endLatch = new CountDownLatch(1); + } + + @Override + public void onMessage(Message message) + { + _receivedMessage.add(message); + if (_counter.incrementAndGet() % _messageNumber == 0) + { + _endLatch.countDown(); + } + } + + public void reset() + { + _receivedMessage.clear(); + _endLatch = new CountDownLatch(1); + _counter.set(0); + } + + public List getReceivedMessages() + { + return _receivedMessage; + } + + public Object awaitForEnd() throws InterruptedException + { + return _endLatch.await((long) _messageNumber, TimeUnit.SECONDS); + } + + public int getMessageCounter() + { + return _counter.get(); + } + } + + /** + * Tests {@link Session#close()} for session with given acknowledge mode + * to ensure that it blocks until failover implementation restores connection. + * + * @param acknowledgeMode session acknowledge mode + * @throws JMSException + */ + private void sessionCloseWhileFailoverImpl(int acknowledgeMode) throws Exception + { + initDelayedFailover(acknowledgeMode); + + // intentionally receive message but not commit or acknowledge it in + // case of transacted or CLIENT_ACK session + Message receivedMessage = _consumer.receive(1000l); + assertReceivedMessage(receivedMessage, TEST_MESSAGE_FORMAT, 0); + + failBroker(getFailingPort()); + + // wait until failover is started + _failoverStarted.await(5, TimeUnit.SECONDS); + + // test whether session#close blocks while failover is in progress + _consumerSession.close(); + + assertTrue("Failover has not completed yet but session was closed", _failoverComplete.await(5, TimeUnit.SECONDS)); + + assertFailoverException(); + } + + /** + * A helper method to instantiate {@link QueueBrowser} and publish test messages on a test queue for further browsing. + * + * @param acknowledgeMode session acknowledge mode + * @return queue browser + * @throws JMSException + */ + private QueueBrowser prepareQueueBrowser(int acknowledgeMode) throws JMSException, AMQException + { + init(acknowledgeMode, false); + _consumer.close(); + _connection.start(); + + produceMessages(TEST_MESSAGE_FORMAT, _messageNumber, false); + if (acknowledgeMode == Session.SESSION_TRANSACTED) + { + _producerSession.commit(); + } + else + { + ((AMQSession)_producerSession).sync(); + } + + QueueBrowser browser = _consumerSession.createBrowser((Queue) _destination); + return browser; + } + + /** + * Tests {@link QueueBrowser#close()} for session with given acknowledge mode + * to ensure that it blocks until failover implementation restores connection. + * + * @param acknowledgeMode session acknowledge mode + * @throws JMSException + */ + private void browserCloseWhileFailoverImpl(int acknowledgeMode) throws Exception + { + QueueBrowser browser = prepareQueueBrowser(acknowledgeMode); + + @SuppressWarnings("unchecked") + Enumeration messages = browser.getEnumeration(); + Message receivedMessage = (Message) messages.nextElement(); + assertReceivedMessage(receivedMessage, TEST_MESSAGE_FORMAT, 0); + + failBroker(getFailingPort()); + + // wait until failover is started + _failoverStarted.await(5, TimeUnit.SECONDS); + + browser.close(); + + assertTrue("Failover has not completed yet but browser was closed", _failoverComplete.await(5, TimeUnit.SECONDS)); + + assertFailoverException(); + } + + private DelayingFailoverPolicy initDelayedFailover(int acknowledgeMode) throws JMSException + { + DelayingFailoverPolicy failoverPolicy = setDelayedFailoverPolicy(); + init(acknowledgeMode, true); + produceMessages(TEST_MESSAGE_FORMAT, _messageNumber, false); + if (acknowledgeMode == Session.SESSION_TRANSACTED) + { + _producerSession.commit(); + } + return failoverPolicy; + } + + private DelayingFailoverPolicy setDelayedFailoverPolicy() + { + return setDelayedFailoverPolicy(2); + } + + private DelayingFailoverPolicy setDelayedFailoverPolicy(long delay) + { + AMQConnection amqConnection = (AMQConnection) _connection; + DelayingFailoverPolicy failoverPolicy = new DelayingFailoverPolicy(amqConnection, delay); + ((AMQConnection) _connection).setFailoverPolicy(failoverPolicy); + return failoverPolicy; + } + + @Override + public void failBroker(int port) + { + killBroker(port); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/client/failover/MultipleBrokersFailoverTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/client/failover/MultipleBrokersFailoverTest.java new file mode 100644 index 0000000000..15ec0f9a4d --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/client/failover/MultipleBrokersFailoverTest.java @@ -0,0 +1,288 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.failover; + +import java.io.File; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.log4j.Logger; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQConnectionURL; +import org.apache.qpid.jms.ConnectionListener; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.test.utils.TestUtils; +import org.apache.qpid.util.FileUtils; + +public class MultipleBrokersFailoverTest extends QpidBrokerTestCase implements ConnectionListener +{ + private static final Logger _logger = Logger.getLogger(MultipleBrokersFailoverTest.class); + + private static final String FAILOVER_VIRTUAL_HOST = "failover"; + private static final String NON_FAILOVER_VIRTUAL_HOST = "nonfailover"; + private static final String BROKER_PORTION_FORMAT = "tcp://localhost:%d?connectdelay='%d',retries='%d'"; + private static final int FAILOVER_RETRIES = 1; + private static final int FAILOVER_CONNECTDELAY = 1000; + private static final int FAILOVER_FACTOR = 4; + + private int[] _brokerPorts; + private AMQConnectionURL _connectionURL; + private Connection _connection; + private CountDownLatch _failoverComplete; + private CountDownLatch _failoverStarted; + private Session _consumerSession; + private Destination _destination; + private MessageConsumer _consumer; + private Session _producerSession; + private MessageProducer _producer; + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + int numBrokers = 4; + int port = findFreePort(); + _brokerPorts = new int[numBrokers]; + + // we need to create 4 brokers: + // 1st broker will be running in test JVM and will not have failover host (only tcp connection will established, amqp connection will be closed) + // 2d broker will be spawn in separate JVM and should have a failover host (amqp connection should be established) + // 3d broker will be spawn in separate JVM and should not have a failover host (only tcp connection will established, amqp connection will be closed) + // 4d broker will be spawn in separate JVM and should have a failover host (amqp connection should be established) + + // the test should connect to the second broker first and fail over to the forth broker + // after unsuccessful try to establish the connection to the 3d broker + for (int i = 0; i < numBrokers; i++) + { + if (i > 0) + { + port = getNextAvailable(port + 1); + } + _brokerPorts[i] = port; + + createBrokerConfiguration(port); + String host = null; + if (i == 1 || i == _brokerPorts.length - 1) + { + host = FAILOVER_VIRTUAL_HOST; + } + else + { + host = NON_FAILOVER_VIRTUAL_HOST; + } + createTestVirtualHostNode(port, host); + + startBroker(port); + revertSystemProperties(); + } + + _connectionURL = new AMQConnectionURL(generateUrlString(numBrokers)); + + _connection = getConnection(_connectionURL); + ((AMQConnection) _connection).setConnectionListener(this); + _failoverComplete = new CountDownLatch(1); + _failoverStarted = new CountDownLatch(1); + } + + public void startBroker() throws Exception + { + // noop, prevent the broker startup in super.setUp() + } + + private String generateUrlString(int numBrokers) + { + String baseString = "amqp://guest:guest@test/" + FAILOVER_VIRTUAL_HOST + + "?&failover='roundrobin?cyclecount='1''&brokerlist='"; + StringBuffer buffer = new StringBuffer(baseString); + + for(int i = 0; i< numBrokers ; i++) + { + if(i != 0) + { + buffer.append(";"); + } + + String broker = String.format(BROKER_PORTION_FORMAT, _brokerPorts[i], + FAILOVER_CONNECTDELAY, FAILOVER_RETRIES); + buffer.append(broker); + } + buffer.append("'"); + + return buffer.toString(); + } + + public void tearDown() throws Exception + { + try + { + super.tearDown(); + } + finally + { + for (int i = 0; i < _brokerPorts.length; i++) + { + if (_brokerPorts[i] > 0) + { + stopBrokerSafely(_brokerPorts[i]); + FileUtils.deleteDirectory(System.getProperty("QPID_WORK") + File.separator + getFailingPort()); + } + } + + } + } + + + public void testFailoverOnBrokerKill() throws Exception + { + init(Session.SESSION_TRANSACTED, true); + assertConnectionPort(_brokerPorts[1]); + + assertSendReceive(0); + + killBroker(_brokerPorts[1]); + + awaitForFailoverCompletion(FAILOVER_CONNECTDELAY * _brokerPorts.length * FAILOVER_FACTOR); + assertEquals("Failover is not started as expected", 0, _failoverStarted.getCount()); + + assertSendReceive(2); + assertConnectionPort(_brokerPorts[_brokerPorts.length - 1]); + } + + public void testFailoverOnBrokerStop() throws Exception + { + init(Session.SESSION_TRANSACTED, true); + assertConnectionPort(_brokerPorts[1]); + + assertSendReceive(0); + + stopBroker(_brokerPorts[1]); + + awaitForFailoverCompletion(FAILOVER_CONNECTDELAY * _brokerPorts.length * FAILOVER_FACTOR); + assertEquals("Failover is not started as expected", 0, _failoverStarted.getCount()); + + assertSendReceive(1); + assertConnectionPort(_brokerPorts[_brokerPorts.length - 1]); + } + + private void assertConnectionPort(int brokerPort) + { + int connectionPort = ((AMQConnection)_connection).getActiveBrokerDetails().getPort(); + assertEquals("Unexpected broker port", brokerPort, connectionPort); + } + + private void assertSendReceive(int index) throws JMSException + { + Message message = createNextMessage(_producerSession, index); + _producer.send(message); + if (_producerSession.getTransacted()) + { + _producerSession.commit(); + } + Message receivedMessage = _consumer.receive(1000l); + assertReceivedMessage(receivedMessage, index); + if (_consumerSession.getTransacted()) + { + _consumerSession.commit(); + } + } + + private void awaitForFailoverCompletion(long delay) + { + _logger.info("Awaiting Failover completion.."); + try + { + if (!_failoverComplete.await(delay, TimeUnit.MILLISECONDS)) + { + _logger.warn("Test thread stack:\n\n" + TestUtils.dumpThreads()); + fail("Failover did not complete"); + } + } + catch (InterruptedException e) + { + fail("Test was interrupted:" + e.getMessage()); + } + } + + private void assertReceivedMessage(Message receivedMessage, int messageIndex) + { + assertNotNull("Expected message [" + messageIndex + "] is not received!", receivedMessage); + assertTrue( + "Failure to receive message [" + messageIndex + "], expected TextMessage but received " + receivedMessage, + receivedMessage instanceof TextMessage); + } + + private void init(int acknowledgeMode, boolean startConnection) throws JMSException + { + boolean isTransacted = acknowledgeMode == Session.SESSION_TRANSACTED ? true : false; + + _consumerSession = _connection.createSession(isTransacted, acknowledgeMode); + _destination = _consumerSession.createQueue(getTestQueueName()); + _consumer = _consumerSession.createConsumer(_destination); + + if (startConnection) + { + _connection.start(); + } + + _producerSession = _connection.createSession(isTransacted, acknowledgeMode); + _producer = _producerSession.createProducer(_destination); + + } + + @Override + public void bytesSent(long count) + { + } + + @Override + public void bytesReceived(long count) + { + } + + @Override + public boolean preFailover(boolean redirect) + { + _failoverStarted.countDown(); + return true; + } + + @Override + public boolean preResubscribe() + { + return true; + } + + @Override + public void failoverComplete() + { + _failoverComplete.countDown(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/client/message/AMQPEncodedMapMessageTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/client/message/AMQPEncodedMapMessageTest.java new file mode 100644 index 0000000000..787e727e66 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/client/message/AMQPEncodedMapMessageTest.java @@ -0,0 +1,275 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.MapMessage; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + + +public class AMQPEncodedMapMessageTest extends QpidBrokerTestCase +{ + private Connection _connection; + private Session _session; + private MessageConsumer _consumer; + private MessageProducer _producer; + private UUID myUUID = UUID.randomUUID(); + + public void setUp() throws Exception + { + super.setUp(); + + //Create Connection + _connection = getConnection(); + + //Create Session + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + //Create Queue + String queueName = getTestQueueName(); + Queue queue = _session.createQueue(queueName); + + //Create Consumer + _consumer = _session.createConsumer(queue); + + //Create Producer + _producer = _session.createProducer(queue); + + _connection.start(); + } + + public void testEmptyMessage() throws JMSException + { + MapMessage m = _session.createMapMessage(); + _producer.send(m); + AMQPEncodedMapMessage msg = (AMQPEncodedMapMessage)_consumer.receive(RECEIVE_TIMEOUT); + assertNotNull("Message was not received on time",msg); + assertEquals("Message content-type is incorrect", + AMQPEncodedMapMessage.MIME_TYPE, + ((AbstractJMSMessage)msg).getContentType()); + + assertEquals("Message content should be an empty map", + Collections.EMPTY_MAP, + ((AMQPEncodedMapMessage)msg).getMap()); + } + + public void testNullMessage() throws JMSException + { + MapMessage m = _session.createMapMessage(); + ((AMQPEncodedMapMessage)m).setMap(null); + _producer.send(m); + AMQPEncodedMapMessage msg = (AMQPEncodedMapMessage)_consumer.receive(RECEIVE_TIMEOUT); + assertNotNull("Message was not received on time",msg); + assertEquals("Message content-type is incorrect", + AMQPEncodedMapMessage.MIME_TYPE, + ((AbstractJMSMessage)msg).getContentType()); + + assertEquals("Message content should be null", + null, + ((AMQPEncodedMapMessage)msg).getMap()); + + } + + public void testMessageWithContent() throws JMSException + { + MapMessage m = _session.createMapMessage(); + m.setBoolean("Boolean", true); + m.setByte("Byte", (byte)5); + byte[] bytes = new byte[]{(byte)5,(byte)8}; + m.setBytes("Bytes", bytes); + m.setChar("Char", 'X'); + m.setDouble("Double", 56.84); + m.setFloat("Float", Integer.MAX_VALUE + 5000); + m.setInt("Int", Integer.MAX_VALUE - 5000); + m.setShort("Short", (short)58); + m.setString("String", "Hello"); + m.setObject("uuid", myUUID); + _producer.send(m); + + AMQPEncodedMapMessage msg = (AMQPEncodedMapMessage)_consumer.receive(RECEIVE_TIMEOUT); + assertNotNull("Message was not received on time",msg); + assertEquals("Message content-type is incorrect", + AMQPEncodedMapMessage.MIME_TYPE, + ((AbstractJMSMessage)msg).getContentType()); + + assertEquals(true,m.getBoolean("Boolean")); + assertEquals((byte)5,m.getByte("Byte")); + byte[] bytesRcv = m.getBytes("Bytes"); + assertNotNull("Byte array is null",bytesRcv); + assertEquals((byte)5,bytesRcv[0]); + assertEquals((byte)8,bytesRcv[1]); + assertEquals('X',m.getChar("Char")); + assertEquals(56.84,m.getDouble("Double")); + //assertEquals(Integer.MAX_VALUE + 5000,m.getFloat("Float")); + assertEquals(Integer.MAX_VALUE - 5000,m.getInt("Int")); + assertEquals((short)58,m.getShort("Short")); + assertEquals("Hello",m.getString("String")); + assertEquals(myUUID,(UUID)m.getObject("uuid")); + } + + + public void testMessageWithListEntries() throws JMSException + { + MapMessage m = _session.createMapMessage(); + + List myList = getList(); + + m.setObject("List", myList); + + List uuidList = new ArrayList(); + uuidList.add(myUUID); + m.setObject("uuid-list", uuidList); + _producer.send(m); + + AMQPEncodedMapMessage msg = (AMQPEncodedMapMessage)_consumer.receive(RECEIVE_TIMEOUT); + assertNotNull("Message was not received on time",msg); + assertEquals("Message content-type is incorrect", + AMQPEncodedMapMessage.MIME_TYPE, + ((AbstractJMSMessage)msg).getContentType()); + + List list = (List)msg.getObject("List"); + assertNotNull("List not received",list); + Collections.sort(list); + int i = 1; + for (Integer j: list) + { + assertEquals(i,j.intValue()); + i++; + } + + List list2 = (List)msg.getObject("uuid-list"); + assertNotNull("UUID List not received",list2); + assertEquals(myUUID,list2.get(0)); + } + + public void testMessageWithMapEntries() throws JMSException + { + MapMessage m = _session.createMapMessage(); + + Map myMap = getMap(); + m.setObject("Map", myMap); + + Map uuidMap = new HashMap(); + uuidMap.put("uuid", myUUID); + m.setObject("uuid-map", uuidMap); + + _producer.send(m); + + AMQPEncodedMapMessage msg = (AMQPEncodedMapMessage)_consumer.receive(RECEIVE_TIMEOUT); + assertNotNull("Message was not received on time",msg); + assertEquals("Message content-type is incorrect", + AMQPEncodedMapMessage.MIME_TYPE, + ((AbstractJMSMessage)msg).getContentType()); + + Map map = (Map)msg.getObject("Map"); + assertNotNull("Map not received",map); + for (int i=1; i <4; i++ ) + { + assertEquals("String" + i,map.get("Key" + i)); + i++; + } + + Map map2 = (Map)msg.getObject("uuid-map"); + assertNotNull("Map not received",map2); + assertEquals(myUUID,map2.get("uuid")); + } + + public void testMessageWithNestedListsAndMaps() throws JMSException + { + MapMessage m = _session.createMapMessage(); + + Map myMap = new HashMap(); + myMap.put("map", getMap()); + myMap.put("list", getList()); + + m.setObject("Map", myMap); + _producer.send(m); + + AMQPEncodedMapMessage msg = (AMQPEncodedMapMessage)_consumer.receive(RECEIVE_TIMEOUT); + assertNotNull("Message was not received on time",msg); + assertEquals("Message content-type is incorrect", + AMQPEncodedMapMessage.MIME_TYPE, + ((AbstractJMSMessage)msg).getContentType()); + + Map mainMap = (Map)msg.getObject("Map"); + assertNotNull("Main Map not received",mainMap); + + Map map = (Map)mainMap.get("map"); + assertNotNull("Nested Map not received",map); + for (int i=1; i <4; i++ ) + { + assertEquals("String" + i,map.get("Key" + i)); + i++; + } + + List list = (List)mainMap.get("list"); + assertNotNull("Nested List not received",list); + Collections.sort(list); + + int i = 1; + for (Integer j: list) + { + assertEquals(i,j.intValue()); + i++; + } + } + + private List getList() + { + List myList = new ArrayList(); + myList.add(1); + myList.add(2); + myList.add(3); + + return myList; + } + + private Map getMap() + { + Map myMap = new HashMap(); + myMap.put("Key1","String1"); + myMap.put("Key2","String2"); + myMap.put("Key3","String3"); + + return myMap; + } + + public void tearDown() throws Exception + { + //clean up + _connection.close(); + + super.tearDown(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/client/message/NonQpidObjectMessage.java b/qpid/java/systests/src/test/java/org/apache/qpid/client/message/NonQpidObjectMessage.java new file mode 100644 index 0000000000..3aabfa1c40 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/client/message/NonQpidObjectMessage.java @@ -0,0 +1,235 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.client.message; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.ObjectMessage; +import javax.jms.Session; +import java.io.Serializable; +import java.util.Enumeration; + +public class NonQpidObjectMessage implements ObjectMessage { + + private ObjectMessage _realMessage; + private String _contentString; + + /** + * Allows us to construct a JMS message which + * does not inherit from the Qpid message superclasses + * and expand our unit testing of MessageConverter et al + * @param session + */ + public NonQpidObjectMessage(Session session) throws JMSException + { + _realMessage = session.createObjectMessage(); + } + + public String getJMSMessageID() throws JMSException { + return _realMessage.getJMSMessageID(); + } + + public void setJMSMessageID(String string) throws JMSException { + _realMessage.setJMSMessageID(string); + } + + public long getJMSTimestamp() throws JMSException { + return _realMessage.getJMSTimestamp(); + } + + public void setJMSTimestamp(long l) throws JMSException { + _realMessage.setJMSTimestamp(l); + } + + public byte[] getJMSCorrelationIDAsBytes() throws JMSException { + return _realMessage.getJMSCorrelationIDAsBytes(); + } + + public void setJMSCorrelationIDAsBytes(byte[] bytes) throws JMSException { + _realMessage.setJMSCorrelationIDAsBytes(bytes); + } + + public void setJMSCorrelationID(String string) throws JMSException { + _realMessage.setJMSCorrelationID(string); + } + + public String getJMSCorrelationID() throws JMSException { + return _realMessage.getJMSCorrelationID(); + } + + public Destination getJMSReplyTo() throws JMSException { + return _realMessage.getJMSReplyTo(); + } + + public void setJMSReplyTo(Destination destination) throws JMSException { + _realMessage.setJMSReplyTo(destination); + } + + public Destination getJMSDestination() throws JMSException { + return _realMessage.getJMSDestination(); + } + + public void setJMSDestination(Destination destination) throws JMSException { + _realMessage.setJMSDestination(destination); + } + + public int getJMSDeliveryMode() throws JMSException { + return _realMessage.getJMSDeliveryMode(); + } + + public void setJMSDeliveryMode(int i) throws JMSException { + _realMessage.setJMSDeliveryMode(i); + } + + public boolean getJMSRedelivered() throws JMSException { + return _realMessage.getJMSRedelivered(); + } + + public void setJMSRedelivered(boolean b) throws JMSException { + _realMessage.setJMSRedelivered(b); + } + + public String getJMSType() throws JMSException { + return _realMessage.getJMSType(); + } + + public void setJMSType(String string) throws JMSException { + _realMessage.setJMSType(string); + } + + public long getJMSExpiration() throws JMSException { + return _realMessage.getJMSExpiration(); + } + + public void setJMSExpiration(long l) throws JMSException { + _realMessage.setJMSExpiration(l); + } + + public int getJMSPriority() throws JMSException { + return _realMessage.getJMSPriority(); + } + + public void setJMSPriority(int i) throws JMSException { + _realMessage.setJMSPriority(i); + } + + public void clearProperties() throws JMSException { + _realMessage.clearProperties(); + } + + public boolean propertyExists(String string) throws JMSException { + return _realMessage.propertyExists(string); + } + + public boolean getBooleanProperty(String string) throws JMSException { + return _realMessage.getBooleanProperty(string); + } + + public byte getByteProperty(String string) throws JMSException { + return _realMessage.getByteProperty(string); + } + + public short getShortProperty(String string) throws JMSException { + return _realMessage.getShortProperty(string); + } + + public int getIntProperty(String string) throws JMSException { + return _realMessage.getIntProperty(string); + } + + public long getLongProperty(String string) throws JMSException { + return _realMessage.getLongProperty(string); + } + + public float getFloatProperty(String string) throws JMSException { + return _realMessage.getFloatProperty(string); + } + + public double getDoubleProperty(String string) throws JMSException { + return _realMessage.getDoubleProperty(string); + } + + public String getStringProperty(String string) throws JMSException { + return _realMessage.getStringProperty(string); + } + + public Object getObjectProperty(String string) throws JMSException { + return _realMessage.getObjectProperty(string); + } + + public Enumeration getPropertyNames() throws JMSException { + return _realMessage.getPropertyNames(); + } + + public void setBooleanProperty(String string, boolean b) throws JMSException { + _realMessage.setBooleanProperty(string,b); + } + + public void setByteProperty(String string, byte b) throws JMSException { + _realMessage.setByteProperty(string,b); + } + + public void setShortProperty(String string, short i) throws JMSException { + _realMessage.setShortProperty(string,i); + } + + public void setIntProperty(String string, int i) throws JMSException { + _realMessage.setIntProperty(string,i); + } + + public void setLongProperty(String string, long l) throws JMSException { + _realMessage.setLongProperty(string,l); + } + + public void setFloatProperty(String string, float v) throws JMSException { + _realMessage.setFloatProperty(string,v); + } + + public void setDoubleProperty(String string, double v) throws JMSException { + _realMessage.setDoubleProperty(string,v); + } + + public void setStringProperty(String string, String string1) throws JMSException { + _realMessage.setStringProperty(string,string1); + } + + public void setObjectProperty(String string, Object object) throws JMSException { + _realMessage.setObjectProperty(string,object); + } + + public void acknowledge() throws JMSException { + _realMessage.acknowledge(); + } + + public void clearBody() throws JMSException { + _realMessage.clearBody(); + } + + public void setObject(Serializable serializable) throws JMSException { + if (serializable instanceof String) + { + _contentString = (String)serializable; + } + } + + public Serializable getObject() throws JMSException { + return _contentString; } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java new file mode 100644 index 0000000000..69441d2be6 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java @@ -0,0 +1,235 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.client.prefetch; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.Destination; +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 java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + + +public class PrefetchBehaviourTest extends QpidBrokerTestCase +{ + protected static final Logger _logger = LoggerFactory.getLogger(PrefetchBehaviourTest.class); + private Connection _normalConnection; + private AtomicBoolean _exceptionCaught; + private CountDownLatch _processingStarted; + private CountDownLatch _processingCompleted; + + protected void setUp() throws Exception + { + super.setUp(); + _normalConnection = getConnection(); + _exceptionCaught = new AtomicBoolean(); + _processingStarted = new CountDownLatch(1); + _processingCompleted = new CountDownLatch(1); + } + + /** + * Verifies that a slow processing asynchronous transacted consumer with prefetch=1 only + * gets 1 of the messages sent, with the second consumer picking up the others while the + * slow consumer is processing, i.e that prefetch=1 actually does what it says on the tin. + */ + public void testPrefetchOneWithAsynchronousTransactedConsumer() throws Exception + { + final long processingTime = 5000; + + //create a second connection with prefetch set to 1 + setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, new Integer(1).toString()); + Connection prefetch1Connection = getConnection(); + + prefetch1Connection.start(); + _normalConnection.start(); + + //create an asynchronous consumer with simulated slow processing + final Session prefetch1session = prefetch1Connection.createSession(true, Session.SESSION_TRANSACTED); + Queue queue = prefetch1session.createQueue(getTestQueueName()); + MessageConsumer prefetch1consumer = prefetch1session.createConsumer(queue); + prefetch1consumer.setMessageListener(new MessageListener() + { + public void onMessage(Message message) + { + try + { + _logger.debug("starting processing"); + _processingStarted.countDown(); + _logger.debug("processing started"); + + //simulate message processing + Thread.sleep(processingTime); + + prefetch1session.commit(); + + _processingCompleted.countDown(); + } + catch(Exception e) + { + _logger.error("Exception caught in message listener"); + _exceptionCaught.set(true); + } + } + }); + + //create producer and send 5 messages + Session producerSession = _normalConnection.createSession(true, Session.SESSION_TRANSACTED); + MessageProducer producer = producerSession.createProducer(queue); + + for (int i = 0; i < 5; i++) + { + producer.send(producerSession.createTextMessage("test")); + } + producerSession.commit(); + + //wait for the first message to start being processed by the async consumer + assertTrue("Async processing failed to start in allowed timeframe", _processingStarted.await(2000, TimeUnit.MILLISECONDS)); + _logger.debug("proceeding with test"); + + //try to consumer the other messages with another consumer while the async procesisng occurs + Session normalSession = _normalConnection.createSession(true, Session.AUTO_ACKNOWLEDGE); + MessageConsumer normalConsumer = normalSession.createConsumer(queue); + + Message msg; + // Check that other consumer gets the other 4 messages + for (int i = 0; i < 4; i++) + { + msg = normalConsumer.receive(1500); + assertNotNull("Consumer should receive 4 messages",msg); + } + msg = normalConsumer.receive(250); + assertNull("Consumer should not have received a 5th message",msg); + + //wait for the other consumer to finish to ensure it completes ok + _logger.debug("waiting for async consumer to complete"); + assertTrue("Async processing failed to complete in allowed timeframe", _processingStarted.await(processingTime + 2000, TimeUnit.MILLISECONDS)); + assertFalse("Unexpected exception during async message processing",_exceptionCaught.get()); + } + + /** + * This test was originally known as AMQConnectionTest#testPrefetchSystemProperty. + * + */ + public void testMessagesAreDistributedBetweenConsumersWithLowPrefetch() throws Exception + { + Queue queue = getTestQueue(); + + setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, new Integer(2).toString()); + + Connection connection = getConnection(); + connection.start(); + // Create Consumer A + Session consSessA = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumerA = consSessA.createConsumer(queue); + + // ensure message delivery to consumer A is started (required for 0-8..0-9-1) + final Message msg = consumerA.receiveNoWait(); + assertNull(msg); + + Session producerSession = connection.createSession(true, Session.SESSION_TRANSACTED); + sendMessage(producerSession, queue, 3); + + // Create Consumer B + MessageConsumer consumerB = null; + if (isBroker010()) + { + // 0-10 prefetch is per consumer so we create Consumer B on the same session as Consumer A + consumerB = consSessA.createConsumer(queue); + } + else + { + // 0-8..0-9-1 prefetch is per session so we create Consumer B on a separate session + Session consSessB = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + consumerB = consSessB.createConsumer(queue); + } + + // As message delivery to consumer A is already started, the first two messages should + // now be with consumer A. The last message will still be on the Broker as consumer A's + // credit is exhausted and message delivery for consumer B is not yet running. + + // As described by QPID-3747, for 0-10 we *must* check Consumer B before Consumer A. + // If we were to reverse the order, the SessionComplete will restore Consumer A's credit, + // and the third message could be delivered to either Consumer A or Consumer B. + + // Check that consumer B gets the last (third) message. + final Message msgConsumerB = consumerB.receive(1500); + assertNotNull("Consumer B should have received a message", msgConsumerB); + assertEquals("Consumer B received message with unexpected index", 2, msgConsumerB.getIntProperty(INDEX)); + + // Now check that consumer A has indeed got the first two messages. + for (int i = 0; i < 2; i++) + { + final Message msgConsumerA = consumerA.receive(1500); + assertNotNull("Consumer A should have received a message " + i, msgConsumerA); + assertEquals("Consumer A received message with unexpected index", i, msgConsumerA.getIntProperty(INDEX)); + } + } + + /** + * Test Goal: Verify if connection stop releases all messages in it's prefetch buffer. + * Test Strategy: Send 10 messages to a queue. Create a consumer with maxprefetch of 5, but never consume them. + * Stop the connection. Create a new connection and a consumer with maxprefetch 10 on the same queue. + * Try to receive all 10 messages. + */ + public void testConnectionStop() throws Exception + { + setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, "10"); + Connection con = getConnection(); + con.start(); + Session ssn = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination queue = ssn.createQueue("ADDR:my-queue;{create: always}"); + + MessageProducer prod = ssn.createProducer(queue); + for (int i=0; i<10;i++) + { + prod.send(ssn.createTextMessage("Msg" + i)); + } + + MessageConsumer consumer = ssn.createConsumer(queue); + // This is to ensure we get the first client to prefetch. + Message msg = consumer.receive(1000); + assertNotNull("The first consumer should get one message",msg); + con.stop(); + + Connection con2 = getConnection(); + con2.start(); + Session ssn2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer2 = ssn2.createConsumer(queue); + for (int i=0; i<9;i++) + { + TextMessage m = (TextMessage)consumer2.receive(1000); + assertNotNull("The second consumer should get 9 messages, but received only " + i,m); + } + } +} + diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/client/redelivered/RedeliveredMessageTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/client/redelivered/RedeliveredMessageTest.java new file mode 100644 index 0000000000..0f12c8c7e6 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/client/redelivered/RedeliveredMessageTest.java @@ -0,0 +1,71 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.redelivered; + +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Session; + +public class RedeliveredMessageTest extends QpidBrokerTestCase +{ + private Connection _connection; + + public void setUp() throws Exception + { + super.setUp(); + _connection = getConnection(); + } + + public void testRedeliveredFlagOnSessionClose() throws Exception + { + Session session = _connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Destination destination = session.createQueue(getTestQueueName()); + MessageConsumer consumer = session.createConsumer(destination); + + final int numberOfMessages = 3; + sendMessage(session, destination, numberOfMessages); + + _connection.start(); + + for(int i = 0; i < numberOfMessages; i++) + { + final Message m = consumer.receive(1000l); + assertNotNull("Message is not recieved at " + i, m); + assertFalse("Redelivered should be not set", m.getJMSRedelivered()); + } + + session.close(); + session = _connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + destination = session.createQueue(getTestQueueName()); + consumer = session.createConsumer(destination); + + for(int i = 0; i < numberOfMessages; i++) + { + final Message m = consumer.receive(1000l); + assertNotNull("Message is not recieved at " + i, m); + assertTrue("Redelivered should be set", m.getJMSRedelivered()); + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/client/session/QueueDeclareTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/client/session/QueueDeclareTest.java new file mode 100644 index 0000000000..fefed5b4ab --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/client/session/QueueDeclareTest.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.client.session; + +import java.util.Collections; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Session; + +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.url.AMQBindingURL; + +public class QueueDeclareTest extends QpidBrokerTestCase +{ + private Connection _connection; + private AMQSession _session; + + protected void setUp() throws Exception + { + super.setUp(); + + _connection = getConnection(); + _session = (AMQSession) _connection.createSession(true, Session.SESSION_TRANSACTED); + } + + public void testDeclareAndBindWhenQueueIsNotSpecifiedInDestinationUrl() throws Exception + { + AMQQueue destination = new AMQQueue(new AMQBindingURL("topic://amq.topic//?routingkey='testTopic'")); + + assertEquals("Queue name is generated in parser", AMQShortString.EMPTY_STRING, destination.getAMQQueueName()); + + _session.declareAndBind(destination, FieldTable.convertToFieldTable(Collections. emptyMap())); + + assertFalse("Unexpected queue name: [" + destination.getAMQQueueName() + "]", AMQShortString.EMPTY_STRING.equals(destination.getAMQQueueName())); + + sendMessage(_session, destination, 1); + + MessageConsumer consumer = _session.createConsumer(destination); + _connection.start(); + Message message = consumer.receive(1000l); + assertNotNull("Message not received", message); + _session.commit(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/client/ssl/SSLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/client/ssl/SSLTest.java new file mode 100644 index 0000000000..eb61e5a084 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/client/ssl/SSLTest.java @@ -0,0 +1,485 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.ssl; + +import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE; +import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE_PASSWORD; +import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE; +import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Session; + +import org.apache.qpid.client.AMQConnectionURL; +import org.apache.qpid.client.AMQTestConnection_0_10; +import org.apache.qpid.jms.ConnectionURL; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Transport; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SSLTest extends QpidBrokerTestCase +{ + private static final Logger LOGGER = LoggerFactory.getLogger(SSLTest.class); + + private static final String CERT_ALIAS_APP1 = "app1"; + private static final String CERT_ALIAS_APP2 = "app2"; + + @Override + protected void setUp() throws Exception + { + setSystemProperty("javax.net.debug", "ssl"); + + setSslStoreSystemProperties(); + + //We dont call super.setUp, the tests start the broker after deciding + //whether to run and then configuring it appropriately + } + + public void testCreateSSLConnectionUsingConnectionURLParams() throws Exception + { + if (shouldPerformTest()) + { + clearSslStoreSystemProperties(); + + //Start the broker (NEEDing client certificate authentication) + configureJavaBrokerIfNecessary(true, true, true, false, false); + super.setUp(); + + String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s" + + "?ssl='true'" + + "&key_store='%s'&key_store_password='%s'" + + "&trust_store='%s'&trust_store_password='%s'" + + "'"; + + url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT, + KEYSTORE,KEYSTORE_PASSWORD,TRUSTSTORE,TRUSTSTORE_PASSWORD); + + Connection con = getConnection(new AMQConnectionURL(url)); + assertNotNull("connection should be successful", con); + Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE); + assertNotNull("create session should be successful", ssn); + } + } + + public void testHostVerificationIsOnByDefault() throws Exception + { + if (shouldPerformTest()) + { + clearSslStoreSystemProperties(); + + //Start the broker (NEEDing client certificate authentication) + configureJavaBrokerIfNecessary(true, true, true, false, false); + super.setUp(); + + String url = "amqp://guest:guest@test/?brokerlist='tcp://127.0.0.1:%s" + + "?ssl='true'" + + "&key_store='%s'&key_store_password='%s'" + + "&trust_store='%s'&trust_store_password='%s'" + + "'"; + + url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT, + KEYSTORE,KEYSTORE_PASSWORD,TRUSTSTORE,TRUSTSTORE_PASSWORD); + + try + { + getConnection(new AMQConnectionURL(url)); + } + catch(JMSException e) + { + assertTrue("Unexpected exception message", e.getMessage().contains("SSL hostname verification failed")); + } + + url = "amqp://guest:guest@test/?brokerlist='tcp://127.0.0.1:%s" + + "?ssl='true'&ssl_verify_hostname='false'" + + "&key_store='%s'&key_store_password='%s'" + + "&trust_store='%s'&trust_store_password='%s'" + + "'"; + url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT, + KEYSTORE,KEYSTORE_PASSWORD,TRUSTSTORE,TRUSTSTORE_PASSWORD); + + Connection con = getConnection(new AMQConnectionURL(url)); + assertNotNull("connection should be successful", con); + Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE); + assertNotNull("create session should be successful", ssn); + } + } + + /** + * Create an SSL connection using the SSL system properties for the trust and key store, but using + * the {@link ConnectionURL} ssl='true' option to indicate use of SSL at a Connection level, + * without specifying anything at the {@link ConnectionURL#OPTIONS_BROKERLIST} level. + */ + public void testSslConnectionOption() throws Exception + { + if (shouldPerformTest()) + { + //Start the broker (NEEDing client certificate authentication) + configureJavaBrokerIfNecessary(true, true, true, false, false); + super.setUp(); + + //Create URL enabling SSL at the connection rather than brokerlist level + String url = "amqp://guest:guest@test/?ssl='true'&brokerlist='tcp://localhost:%s'"; + url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT); + + Connection con = getConnection(new AMQConnectionURL(url)); + assertNotNull("connection should be successful", con); + Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE); + assertNotNull("create session should be successful", ssn); + } + } + + /** + * Create an SSL connection using the SSL system properties for the trust and key store, but using + * the {@link ConnectionURL} ssl='true' option to indicate use of SSL at a Connection level, + * overriding the false setting at the {@link ConnectionURL#OPTIONS_BROKERLIST} level. + */ + public void testSslConnectionOptionOverridesBrokerlistOption() throws Exception + { + if (shouldPerformTest()) + { + //Start the broker (NEEDing client certificate authentication) + configureJavaBrokerIfNecessary(true, true, true, false, false); + super.setUp(); + + //Create URL enabling SSL at the connection, overriding the false at the brokerlist level + String url = "amqp://guest:guest@test/?ssl='true'&brokerlist='tcp://localhost:%s?ssl='false''"; + url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT); + + Connection con = getConnection(new AMQConnectionURL(url)); + assertNotNull("connection should be successful", con); + Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE); + assertNotNull("create session should be successful", ssn); + } + } + + public void testCreateSSLConnectionUsingSystemProperties() throws Exception + { + if (shouldPerformTest()) + { + //Start the broker (NEEDing client certificate authentication) + configureJavaBrokerIfNecessary(true, true, true, false, false); + super.setUp(); + + String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s?ssl='true''"; + + url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT); + + Connection con = getConnection(new AMQConnectionURL(url)); + assertNotNull("connection should be successful", con); + Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE); + assertNotNull("create session should be successful", ssn); + } + } + + public void testMultipleCertsInSingleStore() throws Exception + { + if (shouldPerformTest()) + { + //Start the broker (NEEDing client certificate authentication) + configureJavaBrokerIfNecessary(true, true, true, false, false); + super.setUp(); + + String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:" + + QpidBrokerTestCase.DEFAULT_SSL_PORT + + "?ssl='true'&ssl_cert_alias='" + CERT_ALIAS_APP1 + "''"; + + AMQTestConnection_0_10 con = new AMQTestConnection_0_10(url); + org.apache.qpid.transport.Connection transportCon = con.getConnection(); + String userID = transportCon.getSecurityLayer().getUserID(); + assertEquals("The correct certificate was not choosen","app1@acme.org",userID); + con.close(); + + url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:" + + QpidBrokerTestCase.DEFAULT_SSL_PORT + + "?ssl='true'&ssl_cert_alias='" + CERT_ALIAS_APP2 + "''"; + + con = new AMQTestConnection_0_10(url); + transportCon = con.getConnection(); + userID = transportCon.getSecurityLayer().getUserID(); + assertEquals("The correct certificate was not choosen","app2@acme.org",userID); + con.close(); + } + } + + public void testVerifyHostNameWithIncorrectHostname() throws Exception + { + if (shouldPerformTest()) + { + //Start the broker (WANTing client certificate authentication) + configureJavaBrokerIfNecessary(true, true, false, true, false); + super.setUp(); + + String url = "amqp://guest:guest@test/?brokerlist='tcp://127.0.0.1:" + + QpidBrokerTestCase.DEFAULT_SSL_PORT + + "?ssl='true''"; + + try + { + getConnection(new AMQConnectionURL(url)); + fail("Hostname verification failed. No exception was thrown"); + } + catch (Exception e) + { + verifyExceptionCausesContains(e, "SSL hostname verification failed"); + } + } + } + + private void verifyExceptionCausesContains(Exception e, String expectedString) + { + LOGGER.debug("verifying that the following exception contains " + expectedString, e); + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bout)); + String strace = bout.toString(); + assertTrue("Correct exception not thrown", strace.contains(expectedString)); + } + + public void testVerifyLocalHost() throws Exception + { + if (shouldPerformTest()) + { + //Start the broker (WANTing client certificate authentication) + configureJavaBrokerIfNecessary(true, true, false, true, false); + super.setUp(); + + String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:" + + QpidBrokerTestCase.DEFAULT_SSL_PORT + + "?ssl='true''"; + + Connection con = getConnection(new AMQConnectionURL(url)); + assertNotNull("connection should have been created", con); + } + } + + public void testVerifyLocalHostLocalDomain() throws Exception + { + if (shouldPerformTest()) + { + //Start the broker (WANTing client certificate authentication) + configureJavaBrokerIfNecessary(true, true, false, true, false); + super.setUp(); + + String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost.localdomain:" + + QpidBrokerTestCase.DEFAULT_SSL_PORT + + "?ssl='true''"; + + Connection con = getConnection(new AMQConnectionURL(url)); + assertNotNull("connection should have been created", con); + } + } + + public void testCreateSSLConnectionUsingConnectionURLParamsTrustStoreOnly() throws Exception + { + if (shouldPerformTest()) + { + clearSslStoreSystemProperties(); + + //Start the broker (WANTing client certificate authentication) + configureJavaBrokerIfNecessary(true, true, false, true, false); + super.setUp(); + + + String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s" + + "?ssl='true'" + + "&trust_store='%s'&trust_store_password='%s'" + + "'"; + + url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT, TRUSTSTORE,TRUSTSTORE_PASSWORD); + + Connection con = getConnection(new AMQConnectionURL(url)); + assertNotNull("connection should be successful", con); + Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE); + assertNotNull("create session should be successful", ssn); + } + } + + /** + * Verifies that when the broker is configured to NEED client certificates, + * a client which doesn't supply one fails to connect. + */ + public void testClientCertMissingWhilstNeeding() throws Exception + { + missingClientCertWhileNeedingOrWantingTestImpl(true, false, false); + } + + /** + * Verifies that when the broker is configured to WANT client certificates, + * a client which doesn't supply one succeeds in connecting. + */ + public void testClientCertMissingWhilstWanting() throws Exception + { + missingClientCertWhileNeedingOrWantingTestImpl(false, true, true); + } + + /** + * Verifies that when the broker is configured to WANT and NEED client certificates + * that a client which doesn't supply one fails to connect. + */ + public void testClientCertMissingWhilstWantingAndNeeding() throws Exception + { + missingClientCertWhileNeedingOrWantingTestImpl(true, true, false); + } + + private void missingClientCertWhileNeedingOrWantingTestImpl(boolean needClientCerts, + boolean wantClientCerts, boolean shouldSucceed) throws Exception + { + if (shouldPerformTest()) + { + clearSslStoreSystemProperties(); + + //Start the broker + configureJavaBrokerIfNecessary(true, true, needClientCerts, wantClientCerts, false); + super.setUp(); + + String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s" + + "?ssl='true'&trust_store='%s'&trust_store_password='%s''"; + + url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT,TRUSTSTORE,TRUSTSTORE_PASSWORD); + try + { + Connection con = getConnection(new AMQConnectionURL(url)); + if(!shouldSucceed) + { + fail("Connection succeeded, expected exception was not thrown"); + } + else + { + //Use the connection to verify it works + con.createSession(true, Session.SESSION_TRANSACTED); + } + } + catch(JMSException e) + { + if(shouldSucceed) + { + _logger.error("Caught unexpected exception",e); + fail("Connection failed, unexpected exception thrown"); + } + else + { + //expected + verifyExceptionCausesContains(e, "Caused by: javax.net.ssl.SSLException:"); + } + } + } + } + + /** + * Test running TLS and unencrypted on the same port works and both TLS and non-TLS connections can be established + * + */ + public void testCreateSSLandTCPonSamePort() throws Exception + { + if (shouldPerformTest()) + { + clearSslStoreSystemProperties(); + + //Start the broker (NEEDing client certificate authentication) + configureJavaBrokerIfNecessary(true, false, false, false, true); + super.setUp(); + + String url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s" + + "?ssl='true'&ssl_verify_hostname='true'" + + "&key_store='%s'&key_store_password='%s'" + + "&trust_store='%s'&trust_store_password='%s'" + + "'"; + + url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT, + KEYSTORE,KEYSTORE_PASSWORD,TRUSTSTORE,TRUSTSTORE_PASSWORD); + + Connection con = getConnection(new AMQConnectionURL(url)); + assertNotNull("connection should be successful", con); + Session ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE); + assertNotNull("create session should be successful", ssn); + + url = "amqp://guest:guest@test/?brokerlist='tcp://localhost:%s'"; + + url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT); + + con = getConnection(new AMQConnectionURL(url)); + assertNotNull("connection should be successful", con); + ssn = con.createSession(false,Session.AUTO_ACKNOWLEDGE); + assertNotNull("create session should be successful", ssn); + + } + } + + + private boolean shouldPerformTest() + { + // We run the SSL tests on all the Java broker profiles + if(isJavaBroker()) + { + setTestClientSystemProperty(PROFILE_USE_SSL, "true"); + } + + return Boolean.getBoolean(PROFILE_USE_SSL); + } + + private void configureJavaBrokerIfNecessary(boolean sslEnabled, + boolean sslOnly, + boolean needClientAuth, + boolean wantClientAuth, + boolean samePort) throws Exception + { + if(isJavaBroker()) + { + Map sslPortAttributes = new HashMap(); + sslPortAttributes.put(Port.TRANSPORTS, samePort ? Arrays.asList(Transport.SSL, Transport.TCP) + : Collections.singleton(Transport.SSL)); + sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT); + sslPortAttributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); + sslPortAttributes.put(Port.NEED_CLIENT_AUTH, needClientAuth); + sslPortAttributes.put(Port.WANT_CLIENT_AUTH, wantClientAuth); + sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT); + sslPortAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); + sslPortAttributes.put(Port.TRUST_STORES, Collections.singleton(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE)); + getBrokerConfiguration().addObjectConfiguration(Port.class,sslPortAttributes); + } + } + + private void setSslStoreSystemProperties() + { + setSystemProperty("javax.net.ssl.keyStore", KEYSTORE); + setSystemProperty("javax.net.ssl.keyStorePassword", KEYSTORE_PASSWORD); + setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); + setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); + } + + private void clearSslStoreSystemProperties() + { + setSystemProperty("javax.net.ssl.keyStore", null); + setSystemProperty("javax.net.ssl.keyStorePassword", null); + setSystemProperty("javax.net.ssl.trustStore", null); + setSystemProperty("javax.net.ssl.trustStorePassword", null); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/jms/xa/XAResourceTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/jms/xa/XAResourceTest.java new file mode 100644 index 0000000000..e18f70b01d --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/jms/xa/XAResourceTest.java @@ -0,0 +1,158 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.jms.xa; + +import org.apache.qpid.client.AMQConnectionFactory; +import org.apache.qpid.jms.ConnectionURL; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.util.FileUtils; +import org.apache.qpid.test.unit.xa.AbstractXATestCase; +import org.apache.qpid.client.AMQXAResource; + +import org.apache.qpid.dtx.XidImpl; + +import javax.jms.XAConnection; +import javax.jms.XAConnectionFactory; +import javax.jms.XASession; +import javax.transaction.xa.XAException; +import javax.transaction.xa.XAResource; +import javax.transaction.xa.Xid; + +public class XAResourceTest extends AbstractXATestCase +{ + + private static final String FACTORY_NAME = "default"; + private static final String ALT_FACTORY_NAME = "connection2"; + + public void init() throws Exception + { + } + + public void testIsSameRMJoin() throws Exception + { + XAConnectionFactory factory = getConnectionFactory(FACTORY_NAME); + XAConnection conn1 = factory.createXAConnection("guest", "guest"); + XAConnection conn2 = factory.createXAConnection("guest", "guest"); + XAConnection conn3 = factory.createXAConnection("guest", "guest"); + + XASession session1 = conn1.createXASession(); + XASession session2 = conn2.createXASession(); + XASession session3 = conn3.createXASession(); + + AMQXAResource xaResource1 = (AMQXAResource)session1.getXAResource(); + AMQXAResource xaResource2 = (AMQXAResource)session2.getXAResource(); + AMQXAResource xaResource3 = (AMQXAResource)session3.getXAResource(); + + Xid xid = getNewXid(); + + xaResource1.start(xid, XAResource.TMNOFLAGS); + assertTrue("XAResource isSameRM", xaResource1.isSameRM(xaResource2)); + xaResource2.start(xid, XAResource.TMJOIN); + assertTrue("AMQXAResource siblings should be 1", xaResource1.getSiblings().size() == 1); + + assertTrue("AMQXAResource TMJOIN resource siblings should be 0", xaResource2.getSiblings().size() == 0); + + assertTrue("XAResource isSameRM", xaResource2.isSameRM(xaResource3)); + + + xaResource3.start(xid, XAResource.TMJOIN); + assertTrue("AMQXAResource siblings should be 1", xaResource2.getSiblings().size() == 1); + + xaResource1.end(xid, XAResource.TMSUCCESS); + assertTrue("AMQXAResource TMJOIN resource siblings should be 0", xaResource1.getSiblings().size() == 0); + + xaResource1.prepare(xid); + xaResource1.commit(xid, false); + + conn3.close(); + conn2.close(); + conn1.close(); + } + + /* + * Test with multiple XAResources originating from the same connection factory. XAResource(s) will be equal, + * as they originate from the same session. + */ + public void testIsSameRMSingleCF() throws Exception + { + XAConnectionFactory factory = getConnectionFactory(FACTORY_NAME); + XAConnection conn = factory.createXAConnection("guest","guest"); + XASession session = conn.createXASession(); + XAResource xaResource1 = session.getXAResource(); + XAResource xaResource2 = session.getXAResource(); + + assertEquals("XAResource objects not equal", xaResource1, xaResource2); + assertTrue("isSameRM not true for identical objects", xaResource1.isSameRM(xaResource2)); + + session.close(); + conn.close(); + } + + /* + * Test with multiple XAResources originating from different connection factory's and different sessions. XAResources will not be + * equal as they do not originate from the same session. As the UUID from the broker will be the same, isSameRM will be true. + * + */ + public void testIsSameRMMultiCF() throws Exception + { + startBroker(FAILING_PORT); + ConnectionURL url = getConnectionFactory(FACTORY_NAME).getConnectionURL(); + XAConnectionFactory factory = new AMQConnectionFactory(url); + XAConnectionFactory factory2 = new AMQConnectionFactory(url); + XAConnectionFactory factory3 = getConnectionFactory(ALT_FACTORY_NAME); + + XAConnection conn = factory.createXAConnection("guest","guest"); + XAConnection conn2 = factory2.createXAConnection("guest","guest"); + XAConnection conn3 = factory3.createXAConnection("guest","guest"); + + XASession session = conn.createXASession(); + XASession session2 = conn2.createXASession(); + XASession session3 = conn3.createXASession(); + + XAResource xaResource1 = session.getXAResource(); + XAResource xaResource2 = session2.getXAResource(); + XAResource xaResource3 = session3.getXAResource(); + + assertFalse("XAResource objects should not be equal", xaResource1.equals(xaResource2)); + assertTrue("isSameRM not true for identical objects", xaResource1.isSameRM(xaResource2)); + assertFalse("isSameRM true for XA Resources created by two different brokers", xaResource1.isSameRM(xaResource3)); + + conn.close(); + conn2.close(); + conn3.close(); + } + + @Override + public void tearDown() throws Exception + { + try + { + super.tearDown(); + } + finally + { + // Ensure we shutdown any secondary brokers + stopBroker(FAILING_PORT); + FileUtils.deleteDirectory(System.getProperty("QPID_WORK") + "/" + getFailingPort()); + } + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/ra/QpidRAConnectionTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/ra/QpidRAConnectionTest.java new file mode 100644 index 0000000000..daee2842fa --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/ra/QpidRAConnectionTest.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.ra; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Message; +import javax.jms.Session; + +import org.apache.log4j.Logger; + +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class QpidRAConnectionTest extends QpidBrokerTestCase +{ + private static final Logger _logger = Logger.getLogger(QpidRAConnectionTest.class); + + private static final String BROKER_PORT = "15672"; + + private static final String URL = "amqp://guest:guest@client/test?brokerlist='tcp://localhost:" + BROKER_PORT + "?sasl_mechs='PLAIN%25252520CRAM-MD5''"; + + public void testSessionCommitOnClosedConnectionThrowsException() throws Exception + { + QpidResourceAdapter ra = new QpidResourceAdapter(); + QpidRAManagedConnectionFactory mcf = new QpidRAManagedConnectionFactory(); + mcf.setConnectionURL(URL); + mcf.setResourceAdapter(ra); + ConnectionFactory cf = new QpidRAConnectionFactoryImpl(mcf, null); + Connection c = cf.createConnection(); + Session s = c.createSession(true, Session.SESSION_TRANSACTED); + c.close(); + + try + { + s.commit(); + fail("Exception should be thrown"); + } + catch(Exception e) + { + _logger.error("Commit threw exception", e); + assertTrue(e instanceof javax.jms.IllegalStateException); + } + + } + + public void testMessageAck() throws Exception + { + QpidResourceAdapter ra = new QpidResourceAdapter(); + QpidRAManagedConnectionFactory mcf = new QpidRAManagedConnectionFactory(); + mcf.setConnectionURL(URL); + mcf.setResourceAdapter(ra); + ConnectionFactory cf = new QpidRAConnectionFactoryImpl(mcf, null); + Connection c = cf.createConnection(); + Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE); + Message m = s.createTextMessage(); + + try + { + m.acknowledge(); + } + catch(Exception e) + { + fail("Acknowledge should not throw an exception"); + } + finally + { + s.close(); + c.close(); + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/ra/QpidRAXAResourceTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/ra/QpidRAXAResourceTest.java new file mode 100644 index 0000000000..8f20a59b60 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/ra/QpidRAXAResourceTest.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.ra; + +import javax.jms.XAConnection; +import javax.jms.XAConnectionFactory; +import javax.jms.XASession; + +import org.apache.qpid.client.AMQXAResource; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class QpidRAXAResourceTest extends QpidBrokerTestCase +{ + private static final String FACTORY_NAME = "default"; + private static final String BROKER_PORT = "15672"; + private static final String URL = "amqp://guest:guest@client/test?brokerlist='tcp://localhost:" + BROKER_PORT + "?sasl_mechs='PLAIN%2520CRAM-MD5''"; + + public void testXAResourceIsSameRM() throws Exception + { + QpidResourceAdapter ra = new QpidResourceAdapter(); + QpidRAManagedConnectionFactory mcf = new QpidRAManagedConnectionFactory(); + mcf.setConnectionURL(URL); + mcf.setResourceAdapter(ra); + QpidRAManagedConnection mc = (QpidRAManagedConnection)mcf.createManagedConnection(null, null); + AMQXAResource xa1 = (AMQXAResource)mc.getXAResource(); + + XAConnectionFactory factory = getConnectionFactory(FACTORY_NAME); + XAConnection connection = factory.createXAConnection("guest", "guest"); + XASession s2 = connection.createXASession(); + AMQXAResource xaResource = (AMQXAResource)connection.createXASession().getXAResource(); + + assertTrue("QpidRAXAResource and XAResource should be from the same RM", xa1.isSameRM(xaResource)); + assertTrue("XAResource and QpidRAXAResource should be from the same RM", xaResource.isSameRM(xa1)); + + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxyTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxyTest.java new file mode 100644 index 0000000000..7161cf1652 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/ra/admin/QpidConnectionFactoryProxyTest.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.ra.admin; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.QueueConnection; +import javax.jms.QueueConnectionFactory; +import javax.jms.TopicConnection; +import javax.jms.TopicConnectionFactory; + +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class QpidConnectionFactoryProxyTest extends QpidBrokerTestCase +{ + private static final String BROKER_PORT = "15672"; + + private static final String URL = "amqp://guest:guest@client/test?brokerlist='tcp://localhost:" + BROKER_PORT + "?sasl_mechs='PLAIN%2520CRAM-MD5''"; + + public void testQueueConnectionFactory() throws Exception + { + QueueConnectionFactory cf = null; + QueueConnection c = null; + + try + { + cf = new QpidConnectionFactoryProxy(); + ((QpidConnectionFactoryProxy)cf).setConnectionURL(URL); + c = cf.createQueueConnection(); + assertTrue(c instanceof QueueConnection); + + } + finally + { + if(c != null) + { + c.close(); + } + } + } + + public void testTopicConnectionFactory() throws Exception + { + TopicConnectionFactory cf = null; + TopicConnection c = null; + + try + { + cf = new QpidConnectionFactoryProxy(); + ((QpidConnectionFactoryProxy)cf).setConnectionURL(URL); + c = cf.createTopicConnection(); + assertTrue(c instanceof TopicConnection); + + } + finally + { + if(c != null) + { + c.close(); + } + } + try + { + + } + finally + { + + } + } + + public void testConnectionFactory() throws Exception + { + ConnectionFactory cf = null; + Connection c = null; + + try + { + cf = new QpidConnectionFactoryProxy(); + ((QpidConnectionFactoryProxy)cf).setConnectionURL(URL); + c = cf.createConnection(); + assertTrue(c instanceof Connection); + + } + finally + { + if(c != null) + { + c.close(); + } + + } + } +} + diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/scripts/QpidPasswdTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/scripts/QpidPasswdTest.java new file mode 100644 index 0000000000..e483660f4c --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/scripts/QpidPasswdTest.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.scripts; + +import java.io.File; +import java.util.concurrent.TimeUnit; + +import org.apache.qpid.test.utils.Piper; +import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpid.util.SystemUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class QpidPasswdTest extends QpidTestCase +{ + private static final Logger LOGGER = LoggerFactory.getLogger(QpidPasswdTest.class); + + private static final String PASSWD_SCRIPT = "qpid-passwd"; + private static final String EXPECTED_OUTPUT = "user1:rL0Y20zC+Fzt72VPzMSk2A=="; + + public void testRunScript() throws Exception + { + if(SystemUtils.isWindows()) + { + return; + } + Process process = null; + try + { + String scriptPath = + QpidTestCase.QPID_HOME + File.separatorChar + + "bin" + File.separatorChar + + PASSWD_SCRIPT; + + LOGGER.info("About to run script: " + scriptPath); + + ProcessBuilder pb = new ProcessBuilder(scriptPath, "user1", "foo"); + pb.redirectErrorStream(true); + process = pb.start(); + + Piper piper = new Piper(process.getInputStream(), System.out, EXPECTED_OUTPUT, EXPECTED_OUTPUT); + piper.start(); + + boolean finishedSuccessfully = piper.await(2, TimeUnit.SECONDS); + assertTrue( + "Script should have completed with expected output " + EXPECTED_OUTPUT + ". Check standard output for actual output.", + finishedSuccessfully); + process.waitFor(); + piper.join(); + + assertEquals("Unexpected exit value from backup script", 0, process.exitValue()); + } + finally + { + if (process != null) + { + process.getErrorStream().close(); + process.getInputStream().close(); + process.getOutputStream().close(); + } + } + + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/BrokerStartupTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/BrokerStartupTest.java new file mode 100644 index 0000000000..9f5dd2ec39 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/BrokerStartupTest.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.server; + +import java.io.File; +import java.util.List; + +import javax.jms.Connection; +import javax.jms.Queue; +import javax.jms.Session; + +import junit.framework.AssertionFailedError; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; + +import org.apache.qpid.client.AMQConnectionURL; +import org.apache.qpid.server.logging.AbstractTestLogging; +import org.apache.qpid.util.LogMonitor; + +/** + * Series of tests to validate the external Java broker starts up as expected. + */ +public class BrokerStartupTest extends AbstractTestLogging +{ + public void setUp() throws Exception + { + // We either do this here or have a null check in tearDown. + // As when this test is run against profiles other than java it will NPE + _monitor = new LogMonitor(_outputFile); + //We explicitly do not call super.setUp as starting up the broker is + //part of the test case. + } + + /** + * This test simply tests that the broker will startup even if there is no config file (i.e. that it can use the + * currently packaged initial config file (all system tests by default generate their own config file). + * + * + * @throws Exception + */ + public void testStartupWithNoConfig() throws Exception + { + if (isJavaBroker()) + { + int port = getPort(0); + int managementPort = getManagementPort(port); + int connectorServerPort = managementPort + JMXPORT_CONNECTORSERVER_OFFSET; + + setTestSystemProperty("qpid.amqp_port",String.valueOf(port)); + setTestSystemProperty("qpid.jmx_port",String.valueOf(managementPort)); + setTestSystemProperty("qpid.rmi_port",String.valueOf(connectorServerPort)); + setTestSystemProperty("qpid.http_port",String.valueOf(DEFAULT_HTTP_MANAGEMENT_PORT)); + + File brokerConfigFile = new File(getTestConfigFile(port)); + if (brokerConfigFile.exists()) + { + // Config exists from previous test run, delete it. + brokerConfigFile.delete(); + } + + startBroker(port, null); + + AMQConnectionURL url = new AMQConnectionURL(String.format("amqp://" + + GUEST_USERNAME + + ":" + + GUEST_PASSWORD + + "@clientid/?brokerlist='localhost:%d'", port)); + Connection conn = getConnection(url); + assertNotNull(conn); + conn.close(); + } + } + /** + * Description: + * Test that providing an invalid broker logging configuration file does not + * cause the broker to enable DEBUG logging that will seriously impair + * performance + * Input: + * -l value that does not exist + *

+ * Output: + *

+ * No DEBUG output + *

+ * Validation Steps: + *

+ * 1. Start the broker and verify no DEBUG output exists + * + * @throws Exception caused by broker startup + */ + public void testInvalidLog4jConfigurationFile() throws Exception + { + // This logging startup code only occurs when you run a Java broker, + // that broker must be started via Main so not an InVM broker. + if (isJavaBroker() && isExternalBroker() && !isInternalBroker()) + { + //Remove test Log4j config from the commandline + setBrokerCommandLog4JFile(new File("invalid file")); + + // The broker has a built in default log4j configuration set up + // so if the the broker cannot load the -l value it will use default + // use this default. Test that this is correctly loaded, by + // including -Dlog4j.debug so we can validate. + setBrokerEnvironment("QPID_OPTS", "-Dlog4j.debug"); + + // Disable all client logging so we can test for broker DEBUG only. + setLoggerLevel(Logger.getRootLogger(), Level.WARN); + setLoggerLevel(Logger.getLogger("qpid.protocol"), Level.WARN); + setLoggerLevel(Logger.getLogger("org.apache.qpid"), Level.WARN); + + // Set the broker to use info level logging, which is the qpid-server + // default. Rather than debug which is the test default. + setBrokerOnlySystemProperty("amqj.server.logging.level", "info"); + // Set the logging defaults to info for this test. + setBrokerOnlySystemProperty("amqj.logging.level", "info"); + setBrokerOnlySystemProperty("root.logging.level", "info"); + + startBroker(); + + assertEquals("Log4j could not load desired configruation.", + 0, findMatches("log4j:ERROR Could not read configuration file from URL").size()); + + assertEquals("Logging did not error as expected", + 1, waitAndFindMatches("Logging configuration error: unable to read file ").size()); + + + // Perfom some action on the broker to ensure that we hit the DEBUG + // messages that we know are there. Though the current xml parsing + // will generate a LOT of DEBUG on startup. + Connection connection = getConnection(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Queue queue = session.createQueue(getTestQueueName()); + session.createConsumer(queue).close(); + + int COUNT = 10; + sendMessage(session, queue, COUNT); + + assertEquals(COUNT,drainQueue(queue)); + + List results = waitAndFindMatches("DEBUG"); + try + { + // Validation + + assertEquals("DEBUG messages should not be logged", 0, results.size()); + } + catch (AssertionFailedError afe) + { + System.err.println("Log Dump:"); + for (String log : results) + { + System.err.println(log); + } + + if (results.size() == 0) + { + System.err.println("Monitored file contents:"); + System.err.println(_monitor.readFile()); + } + + throw afe; + } + } + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/SupportedProtocolVersionsTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/SupportedProtocolVersionsTest.java new file mode 100644 index 0000000000..42f3854d32 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/SupportedProtocolVersionsTest.java @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.framing.ProtocolVersion; +import org.apache.qpid.server.configuration.BrokerProperties; +import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.model.adapter.PortFactoryTest; +import org.apache.qpid.server.plugin.AMQPProtocolVersionWrapper; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +/** + * Tests to validate it is possible to disable support for particular protocol + * versions entirely, rather than selectively excluding them on particular ports, + * and it is possible to configure the reply to an unsupported protocol initiation. + *

+ * Protocol exclusion/inclusion are unit tested as part of {@link PortFactoryTest} + */ +public class SupportedProtocolVersionsTest extends QpidBrokerTestCase +{ + public void setUp() throws Exception + { + // No-op, we call super.setUp() from test methods after appropriate config overrides + } + + private void clearProtocolSupportManipulations() + { + //Remove the QBTC provided protocol manipulations, giving only the protocols which default to enabled + setSystemProperty(BrokerProperties.PROPERTY_BROKER_DEFAULT_AMQP_PROTOCOL_EXCLUDES, null); + setSystemProperty(BrokerProperties.PROPERTY_BROKER_DEFAULT_AMQP_PROTOCOL_INCLUDES, null); + } + + /** + * Test that 0-10, 0-9-1, 0-9, and 0-8 support is present when no + * attempt has yet been made to disable them, and forcing the client + * to negotiate from a particular protocol version returns a connection + * using the expected protocol version. + */ + public void testDefaultProtocolSupport() throws Exception + { + clearProtocolSupportManipulations(); + + super.setUp(); + + //Verify requesting a 0-10 connection works + setTestClientSystemProperty(ClientProperties.AMQP_VERSION, "0-10"); + AMQConnection connection = (AMQConnection) getConnection(); + assertEquals("Unexpected protocol version in use", ProtocolVersion.v0_10, connection.getProtocolVersion()); + connection.close(); + + //Verify requesting a 0-91 connection works + setTestClientSystemProperty(ClientProperties.AMQP_VERSION, "0-9-1"); + connection = (AMQConnection) getConnection(); + assertEquals("Unexpected protocol version in use", ProtocolVersion.v0_91, connection.getProtocolVersion()); + connection.close(); + + //Verify requesting a 0-9 connection works + setTestClientSystemProperty(ClientProperties.AMQP_VERSION, "0-9"); + connection = (AMQConnection) getConnection(); + assertEquals("Unexpected protocol version in use", ProtocolVersion.v0_9, connection.getProtocolVersion()); + connection.close(); + + //Verify requesting a 0-8 connection works + setTestClientSystemProperty(ClientProperties.AMQP_VERSION, "0-8"); + connection = (AMQConnection) getConnection(); + assertEquals("Unexpected protocol version in use", ProtocolVersion.v8_0, connection.getProtocolVersion()); + connection.close(); + } + + public void testDisabling010and10() throws Exception + { + clearProtocolSupportManipulations(); + + //disable 0-10 and 1-0 support + setSystemProperty(BrokerProperties.PROPERTY_BROKER_DEFAULT_AMQP_PROTOCOL_EXCLUDES, + Protocol.AMQP_1_0 + "," + Protocol.AMQP_0_10); + + super.setUp(); + + //Verify initially requesting a 0-10 connection now negotiates a 0-91 + //connection as the broker should reply with its highest supported protocol + setTestClientSystemProperty(ClientProperties.AMQP_VERSION, "0-10"); + AMQConnection connection = (AMQConnection) getConnection(); + assertEquals("Unexpected protocol version in use", ProtocolVersion.v0_91, connection.getProtocolVersion()); + connection.close(); + } + + public void testConfiguringReplyingToUnsupported010ProtocolInitiationWith09insteadOf091() throws Exception + { + clearProtocolSupportManipulations(); + + //disable 0-10 support, and set the default unsupported protocol initiation reply to 0-9 + setSystemProperty(BrokerProperties.PROPERTY_BROKER_DEFAULT_AMQP_PROTOCOL_EXCLUDES, + Protocol.AMQP_1_0 + "," + Protocol.AMQP_0_10); + setSystemProperty(BrokerProperties.PROPERTY_DEFAULT_SUPPORTED_PROTOCOL_REPLY, "v0_9"); + + super.setUp(); + + //Verify initially requesting a 0-10 connection now negotiates a 0-9 connection as the + //broker should reply with its 'default unsupported protocol initiation reply' as opposed + //to the previous behaviour of the highest supported protocol version. + setTestClientSystemProperty(ClientProperties.AMQP_VERSION, "0-10"); + AMQConnection connection = (AMQConnection) getConnection(); + assertEquals("Unexpected protocol version in use", ProtocolVersion.v0_9, connection.getProtocolVersion()); + connection.close(); + + //Verify requesting a 0-91 connection directly still works, as its support is still enabled + setTestClientSystemProperty(ClientProperties.AMQP_VERSION, "0-9-1"); + connection = (AMQConnection) getConnection(); + assertEquals("Unexpected protocol version in use", ProtocolVersion.v0_91, connection.getProtocolVersion()); + connection.close(); + } + + public void testProtocolIsExpectedBasedOnTestProfile() throws Exception + { + super.setUp(); + final AMQConnection connection = (AMQConnection) getConnection(); + final Protocol expectedBrokerProtocol = getBrokerProtocol(); + final AMQPProtocolVersionWrapper amqpProtocolVersionWrapper = new AMQPProtocolVersionWrapper(expectedBrokerProtocol); + final ProtocolVersion protocolVersion = connection.getProtocolVersion(); + assertTrue("Connection AMQP protocol " + expectedBrokerProtocol + "is not the same as the test specified protocol " + protocolVersion, + areEquivalent(amqpProtocolVersionWrapper, protocolVersion)); + connection.close(); + } + + private boolean areEquivalent(AMQPProtocolVersionWrapper amqpProtocolVersionWrapper, ProtocolVersion protocolVersion) + { + byte byteMajor = (byte)amqpProtocolVersionWrapper.getMajor(); + byte byteMinor; + if (amqpProtocolVersionWrapper.getPatch() == 0) + { + byteMinor = (byte)amqpProtocolVersionWrapper.getMinor(); + } + else + { + final StringBuilder sb = new StringBuilder(); + sb.append(amqpProtocolVersionWrapper.getMinor()); + sb.append(amqpProtocolVersionWrapper.getPatch()); + byteMinor = Byte.valueOf(sb.toString()).byteValue(); + } + return (protocolVersion.getMajorVersion() == byteMajor && protocolVersion.getMinorVersion() == byteMinor); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/exchange/ReturnUnroutableMandatoryMessageTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/exchange/ReturnUnroutableMandatoryMessageTest.java new file mode 100644 index 0000000000..9f145cd62c --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/exchange/ReturnUnroutableMandatoryMessageTest.java @@ -0,0 +1,306 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.exchange; + +import org.apache.log4j.Logger; + +import org.apache.qpid.client.AMQHeadersExchange; +import org.apache.qpid.client.AMQNoRouteException; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.url.AMQBindingURL; +import org.apache.qpid.url.BindingURL; + +import javax.jms.Connection; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ReturnUnroutableMandatoryMessageTest extends QpidBrokerTestCase implements ExceptionListener +{ + private static final Logger _logger = Logger.getLogger(ReturnUnroutableMandatoryMessageTest.class); + + private final List _bouncedMessageList = Collections.synchronizedList(new ArrayList()); + + static + { + String workdir = System.getProperty("QPID_WORK"); + if (workdir == null || workdir.equals("")) + { + String tempdir = System.getProperty("java.io.tmpdir"); + _logger.info("QPID_WORK not set using tmp directory: " + tempdir); + System.setProperty("QPID_WORK", tempdir); + } + } + + /** + * Tests that mandatory message which are not routable are returned to the producer + * + * @throws Exception + */ + public void testReturnUnroutableMandatoryMessage_HEADERS() throws Exception + { + _bouncedMessageList.clear(); + MessageConsumer consumer = null; + AMQSession producerSession = null; + AMQHeadersExchange queue = null; + Connection con=null, con2 = null; + try + { + con = getConnection(); + + AMQSession consumerSession = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + queue = new AMQHeadersExchange(new AMQBindingURL(ExchangeDefaults.HEADERS_EXCHANGE_CLASS + "://" + ExchangeDefaults.HEADERS_EXCHANGE_NAME + "/test/queue1?" + BindingURL.OPTION_ROUTING_KEY + "='F0000=1'")); + + FieldTable ft = new FieldTable(); + ft.setString("F1000", "1"); + consumerSession.declareAndBind(queue, ft); + + consumer = consumerSession.createConsumer(queue); + + //force synch to ensure the consumer has resulted in a bound queue + //((AMQSession) consumerSession).declareExchangeSynch(ExchangeDefaults.HEADERS_EXCHANGE_NAME, ExchangeDefaults.HEADERS_EXCHANGE_CLASS); + // This is the default now + + con2 = getConnection(); + + con2.setExceptionListener(this); + producerSession = (AMQSession) con2.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + // Need to start the "producer" connection in order to receive bounced messages + _logger.info("Starting producer connection"); + con2.start(); + } + catch (JMSException jmse) + { + fail(jmse.getMessage()); + } + + try + { + MessageProducer nonMandatoryProducer = producerSession.createProducer(queue, false, false); + MessageProducer mandatoryProducer = producerSession.createProducer(queue); + + // First test - should neither be bounced nor routed + _logger.info("Sending non-routable non-mandatory message"); + TextMessage msg1 = producerSession.createTextMessage("msg1"); + nonMandatoryProducer.send(msg1); + + // Second test - should be bounced + _logger.info("Sending non-routable mandatory message"); + TextMessage msg2 = producerSession.createTextMessage("msg2"); + mandatoryProducer.send(msg2); + + // Third test - should be routed + _logger.info("Sending routable message"); + TextMessage msg3 = producerSession.createTextMessage("msg3"); + msg3.setStringProperty("F1000", "1"); + mandatoryProducer.send(msg3); + + _logger.info("Starting consumer connection"); + con.start(); + TextMessage tm = (TextMessage) consumer.receive(1000L); + + assertTrue("No message routed to receiver", tm != null); + assertTrue("Wrong message routed to receiver: " + tm.getText(), "msg3".equals(tm.getText())); + + try + { + Thread.sleep(1000L); + } + catch (InterruptedException e) + { + ; + } + + assertTrue("Wrong number of messages bounced (expect 1): " + _bouncedMessageList.size(), _bouncedMessageList.size() == 1); + Message m = _bouncedMessageList.get(0); + assertTrue("Wrong message bounced: " + m.toString(), m.toString().contains("msg2")); + } + catch (JMSException jmse) + { + + } + con.close(); + con2.close(); + + } + + public void testReturnUnroutableMandatoryMessage_QUEUE() throws Exception + { + _bouncedMessageList.clear(); + Connection con = getConnection(); + + AMQSession consumerSession = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + AMQQueue valid_queue = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, "testReturnUnroutableMandatoryMessage_QUEUE"); + AMQQueue invalid_queue = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, "testReturnUnroutableMandatoryMessage_QUEUE_INVALID"); + MessageConsumer consumer = consumerSession.createConsumer(valid_queue); + + //force synch to ensure the consumer has resulted in a bound queue + //((AMQSession) consumerSession).declareExchangeSynch(ExchangeDefaults.HEADERS_EXCHANGE_NAME, ExchangeDefaults.HEADERS_EXCHANGE_CLASS); + // This is the default now + + Connection con2 = getConnection(); + + con2.setExceptionListener(this); + AMQSession producerSession = (AMQSession) con2.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + // Need to start the "producer" connection in order to receive bounced messages + _logger.info("Starting producer connection"); + con2.start(); + + MessageProducer nonMandatoryProducer = producerSession.createProducer(valid_queue, false, false); + MessageProducer mandatoryProducer = producerSession.createProducer(invalid_queue); + + // First test - should be routed + _logger.info("Sending non-mandatory message"); + TextMessage msg1 = producerSession.createTextMessage("msg1"); + nonMandatoryProducer.send(msg1); + + // Second test - should be bounced + _logger.info("Sending non-routable mandatory message"); + TextMessage msg2 = producerSession.createTextMessage("msg2"); + mandatoryProducer.send(msg2); + + _logger.info("Starting consumer connection"); + con.start(); + TextMessage tm = (TextMessage) consumer.receive(1000L); + + assertTrue("No message routed to receiver", tm != null); + assertTrue("Wrong message routed to receiver: " + tm.getText(), "msg1".equals(tm.getText())); + + try + { + Thread.sleep(1000L); + } + catch (InterruptedException e) + { + ; + } + + assertTrue("Wrong number of messages bounced (expect 1): " + _bouncedMessageList.size(), _bouncedMessageList.size() == 1); + Message m = _bouncedMessageList.get(0); + assertTrue("Wrong message bounced: " + m.toString(), m.toString().contains("msg2")); + + con.close(); + con2.close(); + } + + public void testReturnUnroutableMandatoryMessage_TOPIC() throws Exception + { + _bouncedMessageList.clear(); + Connection con = getConnection(); + + AMQSession consumerSession = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + AMQTopic valid_topic = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_CLASS, "test.Return.Unroutable.Mandatory.Message.TOPIC"); + AMQTopic invalid_topic = new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_CLASS, "test.Return.Unroutable.Mandatory.Message.TOPIC.invalid"); + MessageConsumer consumer = consumerSession.createConsumer(valid_topic); + + //force synch to ensure the consumer has resulted in a bound queue + //((AMQSession) consumerSession).declareExchangeSynch(ExchangeDefaults.HEADERS_EXCHANGE_NAME, ExchangeDefaults.HEADERS_EXCHANGE_CLASS); + // This is the default now + + Connection con2 = getConnection(); + + con2.setExceptionListener(this); + AMQSession producerSession = (AMQSession) con2.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + // Need to start the "producer" connection in order to receive bounced messages + _logger.info("Starting producer connection"); + con2.start(); + + MessageProducer nonMandatoryProducer = producerSession.createProducer(valid_topic, false, false); + MessageProducer mandatoryProducer = producerSession.createProducer(invalid_topic, false, true); + + // First test - should be routed + _logger.info("Sending non-mandatory message"); + TextMessage msg1 = producerSession.createTextMessage("msg1"); + nonMandatoryProducer.send(msg1); + + // Second test - should be bounced + _logger.info("Sending non-routable mandatory message"); + TextMessage msg2 = producerSession.createTextMessage("msg2"); + mandatoryProducer.send(msg2); + + _logger.info("Starting consumer connection"); + con.start(); + TextMessage tm = (TextMessage) consumer.receive(1000L); + + assertTrue("No message routed to receiver", tm != null); + assertTrue("Wrong message routed to receiver: " + tm.getText(), "msg1".equals(tm.getText())); + + try + { + Thread.sleep(1000L); + } + catch (InterruptedException e) + { + ; + } + + assertEquals("Wrong number of messages bounced: ", 1, _bouncedMessageList.size()); + Message m = _bouncedMessageList.get(0); + assertTrue("Wrong message bounced: " + m.toString(), m.toString().contains("msg2")); + + con.close(); + con2.close(); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(ReturnUnroutableMandatoryMessageTest.class); + } + + public void onException(JMSException jmsException) + { + + Exception linkedException = null; + linkedException = jmsException.getLinkedException(); + if (linkedException instanceof AMQNoRouteException) + { + AMQNoRouteException noRoute = (AMQNoRouteException) linkedException; + Message bounced = (Message) noRoute.getUndeliveredMessage(); + _bouncedMessageList.add(bounced); + _logger.info("Caught expected NoRouteException"); + } + else + { + _logger.warn("Caught exception on producer: ", jmsException); + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/failover/FailoverMethodTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/failover/FailoverMethodTest.java new file mode 100644 index 0000000000..9e2bd28c43 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/failover/FailoverMethodTest.java @@ -0,0 +1,269 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.failover; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.AMQConnectionClosedException; +import org.apache.qpid.AMQDisconnectedException; +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQConnectionURL; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.util.SystemUtils; + +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class FailoverMethodTest extends QpidBrokerTestCase implements ExceptionListener +{ + private static final Logger LOGGER = LoggerFactory.getLogger(FailoverMethodTest.class); + private CountDownLatch _failoverComplete = new CountDownLatch(1); + private final int _freePortWithNoBroker = findFreePort(); + + /** + * Test that the round robin method has the correct delays. + * The first connection will work but the localhost connection should fail but the duration it takes + * to report the failure is what is being tested. + * + */ + public void testFailoverRoundRobinDelay() throws Exception + { + if (SystemUtils.isWindows()) + { + //TODO Test requires redevelopment - timings/behaviour on windows mean it fails + return; + } + + //note: The first broker has no connect delay and the default 1 retry + // while the tcp:localhost broker has 3 retries with a 2s connect delay + String connectionString = "amqp://guest:guest@/test?brokerlist=" + + "'tcp://localhost:" + getPort() + + ";tcp://localhost:" + _freePortWithNoBroker + "?connectdelay='2000',retries='3''"; + + AMQConnectionURL url = new AMQConnectionURL(connectionString); + + try + { + long start = System.currentTimeMillis(); + AMQConnection connection = new AMQConnection(url); + + connection.setExceptionListener(this); + + LOGGER.debug("Stopping broker"); + stopBroker(); + LOGGER.debug("Stopped broker"); + + _failoverComplete.await(30, TimeUnit.SECONDS); + assertEquals("failoverLatch was not decremented in given timeframe", + 0, _failoverComplete.getCount()); + + long end = System.currentTimeMillis(); + + long duration = (end - start); + + //Failover should take more that 6 seconds. + // 3 Retries + // so VM Broker NoDelay 0 (Connect) NoDelay 0 + // then TCP NoDelay 0 Delay 1 Delay 2 Delay 3 + // so 3 delays of 2s in total for connection + // as this is a tcp connection it will take 1second per connection to fail + // so max time is 6seconds of delay plus 4 seconds of TCP Delay + 1 second of runtime. == 11 seconds + + // Ensure we actually had the delay + assertTrue("Failover took less than 6 seconds", duration > 6000); + + // Ensure we don't have delays before initial connection and reconnection. + // We allow 1 second for initial connection and failover logic on top of 6s of sleep. + assertTrue("Failover took more than 11 seconds:(" + duration + ")", duration < 11000); + } + catch (AMQException e) + { + fail(e.getMessage()); + } + } + + public void testFailoverSingleDelay() throws Exception + { + if (SystemUtils.isWindows()) + { + //TODO Test requires redevelopment - timings/behaviour on windows mean it fails + return; + } + + String connectionString = "amqp://guest:guest@/test?brokerlist='tcp://localhost:" + getPort() + "?connectdelay='2000',retries='3''"; + + AMQConnectionURL url = new AMQConnectionURL(connectionString); + + try + { + long start = System.currentTimeMillis(); + AMQConnection connection = new AMQConnection(url); + + connection.setExceptionListener(this); + + LOGGER.debug("Stopping broker"); + stopBroker(); + LOGGER.debug("Stopped broker"); + + _failoverComplete.await(30, TimeUnit.SECONDS); + assertEquals("failoverLatch was not decremented in given timeframe", + 0, _failoverComplete.getCount()); + + long end = System.currentTimeMillis(); + + long duration = (end - start); + + //Failover should take more that 6 seconds. + // 3 Retries + // so NoDelay 0 (Connect) NoDelay 0 Delay 1 Delay 2 Delay 3 + // so 3 delays of 2s in total for connection + // so max time is 6 seconds of delay + 1 second of runtime. == 7 seconds + + // Ensure we actually had the delay + assertTrue("Failover took less than 6 seconds", duration > 6000); + + // Ensure we don't have delays before initial connection and reconnection. + // We allow 3 second for initial connection and failover logic on top of 6s of sleep. + assertTrue("Failover took more than 9 seconds:(" + duration + ")", duration < 9000); + } + catch (AMQException e) + { + fail(e.getMessage()); + } + } + + + /** + * Test that setting 'nofailover' as the failover policy does not result in + * delays or connection attempts when the initial connection is lost. + * + * Test validates that there is a connection delay as required on initial + * connection. + */ + public void testNoFailover() throws Exception + { + if (SystemUtils.isWindows()) + { + //TODO Test requires redevelopment - timings/behaviour on windows mean it fails + return; + } + + int CONNECT_DELAY = 2000; + String connectionString = "amqp://guest:guest@/test?brokerlist='tcp://localhost:" + getPort() + "?connectdelay='" + CONNECT_DELAY + "'," + + "retries='3'',failover='nofailover'"; + + + AMQConnectionURL url = new AMQConnectionURL(connectionString); + + Thread brokerStart = null; + try + { + //Kill initial broker + stopBroker(); + + //Create a thread to start the broker asynchronously + brokerStart = new Thread(new Runnable() + { + public void run() + { + try + { + //Wait before starting broker + // The wait should allow at least 1 retries to fail before broker is ready + Thread.sleep(750); + startBroker(); + } + catch (Exception e) + { + LOGGER.error("Exception whilst starting broker", e); + } + } + }); + + brokerStart.start(); + long start = System.currentTimeMillis(); + //Start the connection so it will use the retries + AMQConnection connection = new AMQConnection(url); + + long end = System.currentTimeMillis(); + long duration = (end - start); + + // Check that we actually had a delay in connection + assertTrue("Initial connection should be longer than 1 delay : " + CONNECT_DELAY + " <:(" + duration + ")", duration > CONNECT_DELAY); + + + connection.setExceptionListener(this); + + //Ensure we collect the brokerStart thread + brokerStart.join(); + brokerStart = null; + + start = System.currentTimeMillis(); + + //Kill connection + stopBroker(); + + _failoverComplete.await(30, TimeUnit.SECONDS); + assertEquals("failoverLatch was not decremented in given timeframe", 0, _failoverComplete.getCount()); + + end = System.currentTimeMillis(); + + duration = (end - start); + + // Notification of the connection failure should be very quick as we are denying the ability to failover. + // It may not be as quick for Java profile tests so lets just make sure it is less than the connectiondelay + // Occasionally it takes 1s so we have to set CONNECT_DELAY to be higher to take that in to account. + assertTrue("Notification of the connection failure took was : " + CONNECT_DELAY + " >:(" + duration + ")", duration < CONNECT_DELAY); + } + catch (AMQException e) + { + fail(e.getMessage()); + } + finally + { + // Guard against the case where the broker took too long to start + // and the initial connection failed to be formed. + if (brokerStart != null) + { + brokerStart.join(); + } + } + } + + @Override + public void onException(JMSException e) + { + if (e.getLinkedException() instanceof AMQDisconnectedException || e.getLinkedException() instanceof AMQConnectionClosedException) + { + LOGGER.debug("Received AMQDisconnectedException"); + _failoverComplete.countDown(); + } + else + { + LOGGER.error("Unexpected underlying exception", e.getLinkedException()); + } + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/AbstractTestLogging.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/AbstractTestLogging.java new file mode 100644 index 0000000000..8555d9c751 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/AbstractTestLogging.java @@ -0,0 +1,413 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging; + +import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.util.LogMonitor; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.text.NumberFormat; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; + +/** + * Abstract superclass for logging test set up and utility methods. + * + * So named to prevent it being selected itself as a test to run by the test suite. + */ +public class AbstractTestLogging extends QpidBrokerTestCase +{ + public static final long DEFAULT_LOG_WAIT = 2000; + public static final String TEST_LOG_PREFIX = "MESSAGE"; + protected LogMonitor _monitor; + + @Override + public void setUp() throws Exception + { + setLogMessagePrefix(); + + super.setUp(); + _monitor = new LogMonitor(_outputFile); + } + + protected void setLogMessagePrefix() + { + //set the message prefix to facilitate scraping from the munged test output. + setSystemProperty("qpid.logging.prefix", TEST_LOG_PREFIX); + } + + @Override + public void tearDown() throws Exception + { + _monitor.close(); + super.tearDown(); + } + + /** + * assert that the requested log message has not occured + * + * @param log + * + * @throws IOException + */ + public void assertLoggingNotYetOccured(String log) throws IOException + { + // Ensure the alert has not occured yet + assertEquals("Message has already occured:" + log, 0, + findMatches(log).size()); + } + + protected void validateMessageID(String id, String log) + { + assertEquals("Incorrect message", id, getMessageID(log)); + } + + protected String getMessageID(String log) + { + String message = fromMessage(log); + + return message.substring(0, message.indexOf(" ")); + } + + /** + * Return the first channel id from the log string + * ' ch;X' if there is no channel id return -1. + * + * @param log the log string to search. + * + * @return channel id or -1 if no channel id exists. + */ + protected int getChannelID(String log) + { + int start = log.indexOf("ch:") + 3; + + // If we do a check for ] as the boundary we will get cases where log + // is presented with the bounding. If we don't match a ] then we can use + // the end of the string as the boundary. + int end = log.indexOf("]", start); + if (end == -1) + { + end = log.length(); + } + return parseInt(log, start, end); + } + + protected String fromMessage(String log) + {; + int startSubject = log.indexOf("]") + 1; + int start = log.indexOf("]", startSubject) + 1; + + // If we don't have a subject then the second indexOf will return 0 + // in which case we can use the end of the actor as the index. + if (start == 0) + { + start = startSubject; + } + + return log.substring(start).trim(); + } + + /** + * Extract the Subject from the Log Message. + * + * The subject is the second block inclosed in brackets '[ ]'. + * + * If there is no Subject or the second block of brackets '[ ]' cannot be + * identified then an empty String ("") is returned. + * + * The brackets '[ ]' are not included in the returned String. + * + * @param log The log message to process + * + * @return the Subject string or the empty string ("") if the subject can't be identified. + */ + protected String fromSubject(String log) + { + int start = log.indexOf("[") + 1; + // Take the second index + start = log.indexOf("[", start) + 1; + + // There may not be a subject so in that case return nothing. + if (start == 0) + { + return ""; + } + + int end = log.indexOf("]", start); + try + { + return log.substring(start, end); + } + catch (IndexOutOfBoundsException iobe) + { + return ""; + } + } + + /** + * Extract the actor segment from the log message. + * The Actor segment is the first section enclosed in '[ ]'. + * + * No analysis is performed to ensure that the first '[ ]' section of the + * given log is really an Actor segment. + * + * The brackets '[ ]' are not included in the returned String. + * + * @param log the Log Message + * + * @return the Actor segment or "" if unable to locate '[ ]' section + */ + protected String fromActor(String log) + { + int start = log.indexOf("[") + 1; + int end = log.indexOf("]", start); + try + { + return log.substring(start, end).trim(); + } + catch (IndexOutOfBoundsException iobe) + { + return ""; + } + } + + /** + * Return the message String from the given message section + * + * @param log the Message Section + * + * @return the Message String. + */ + protected String getMessageString(String log) + { + // Remove the Log ID from the returned String + int start = log.indexOf(":") + 1; + + return log.substring(start).trim(); + } + + /** + * Given our log message extract the connection ID: + * + * The log string will contain the connectionID identified by 'con:' + * + * So extract the value shown here by X: + * + * 'con:X(' + * + * Extract the value between the ':' and '(' and process it as an Integer + * + * If we are unable to find the right index or process the substring as an + * Integer then return -1. + * + * @param log the log String to process + * + * @return the connection ID or -1. + */ + protected int getConnectionID(String log) + { + int conIDStart = log.indexOf("con:") + 4; + int conIDEnd = log.indexOf("(", conIDStart); + return parseInt(log, conIDStart, conIDEnd); + } + + /** + * Extract the log entry from the raw log line which will contain other + * log4j formatting. + * + * This formatting may impead our testing process so extract the log message + * as we know it to be formatted. + * + * This starts with the string MESSAGE + * + * @param rawLog the raw log + * + * @return the log we are expecting to be printed without the log4j prefixes + */ + protected String getLog(String rawLog) + { + int start = rawLog.indexOf(TEST_LOG_PREFIX); + return rawLog.substring(start); + } + + /** + * Extract the log entry from the result set. Positions are 0-based. + * + * @param results list of log message results to extract from + * @param position position in the list of the message to extract + * @return the message string + */ + protected String getLogMessage(List results, int position) + { + return getLog(results.get(position)); + } + + /** + * Extract the nth-from-last log entry from the result set. + * + * @param results list of log message results to extract from + * @param positionFromEnd position from end of the message list to extract (eg 0 for last) + * @return the message string + */ + protected String getLogMessageFromEnd(List results, int positionFromEnd) + { + int resultSize = results.size(); + return getLogMessage(results, resultSize - 1 - positionFromEnd); + } + + protected List findMatches(String toFind) throws IOException + { + return _monitor.findMatches(toFind); + } + + protected List waitAndFindMatches(String toFind) throws IOException + { + return waitAndFindMatches(toFind, DEFAULT_LOG_WAIT); + } + + protected List waitAndFindMatches(String toFind, long wait) throws IOException + { + return _monitor.waitAndFindMatches(toFind, wait); + } + + public boolean waitForMessage(String message) throws FileNotFoundException, IOException + { + return waitForMessage(message, DEFAULT_LOG_WAIT); + } + + public boolean waitForMessage(String message, long wait) throws FileNotFoundException, IOException + { + return _monitor.waitForMessage(message, wait); + } + + /** + * Given a list of messages that have been pulled out of a log file + * Process the results splitting the log statements in to lists based on the + * actor's connection ID. + * + * So for each log entry extract the Connecition ID from the Actor of the log + * + * Then use that as a key to a HashMap storing the list of log messages for + * that connection. + * + * @param logMessages The list of mixed connection log messages + * + * @return Map indexed by connection id to a list of log messages just for that connection. + */ + protected HashMap> splitResultsOnConnectionID(List logMessages) + { + HashMap> connectionSplitList = new HashMap>(); + + for (String log : logMessages) + { + // Get the connectionID from the Actor in the Message Log. + int cID = getConnectionID(fromActor(getLog(log))); + + List connectionData = connectionSplitList.get(cID); + + // Create the initial List if we don't have one already + if (connectionData == null) + { + connectionData = new LinkedList(); + connectionSplitList.put(cID, connectionData); + } + + // Store the log + connectionData.add(log); + } + + return connectionSplitList; + } + + /** + * Filter the give result set by the specficifed virtualhost. + * This is done using the getSlice to identify the virtualhost (vh) in the + * log message + * + * @param results full list of logs + * @param virtualHostName the virtualhostName to filter on + * + * @return the list of messages only for that virtualhost + */ + protected List filterResultsByVirtualHost(List results, String virtualHostName) + { + List filteredResults = new LinkedList(); + Iterator iterator = results.iterator(); + + while (iterator.hasNext()) + { + String log = iterator.next(); + + if (AbstractTestLogSubject.getSlice("vh", log).equals(virtualHostName)) + { + filteredResults.add(log); + } + } + + return filteredResults; + } + + /** + * Dump the log results. + */ + protected void dumpLogs(List results) throws IOException + { + dumpLogs(results, null); + } + + /** + * Dump the log results or if there are none, the contents of the + * monitored log file if the monitor is non-null. + */ + protected void dumpLogs(List results, LogMonitor monitor) throws IOException + { + System.err.println("Log Dump:"); + for (String log : results) + { + System.err.println(log); + } + + if (results.isEmpty() && monitor != null) + { + System.err.println("Monitored file contents:"); + System.err.println(monitor.readFile()); + } + } + + private int parseInt(final String logSubstring, final int start, final int end) + { + try + { + final NumberFormat format = NumberFormat.getInstance(Locale.getDefault()); + final Number number = format.parse(logSubstring.substring(start, end)); + return number.intValue(); + } + catch (Exception e) + { + return -1; + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/AccessControlLoggingTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/AccessControlLoggingTest.java new file mode 100644 index 0000000000..a0188626ee --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/AccessControlLoggingTest.java @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.logging; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.security.acl.AbstractACLTestCase; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Session; +import java.util.List; + +/** + * ACL version 2/3 file testing to verify that ACL actor logging works correctly. + * + * This suite of tests validate that the AccessControl messages occur correctly + * and according to the following format: + * + *

+ * ACL-1001 : Allowed Operation Object {PROPERTIES}
+ * ACL-1002 : Denied Operation Object {PROPERTIES}
+ * 
+ */ +public class AccessControlLoggingTest extends AbstractTestLogging +{ + private static final String ACL_LOG_PREFIX = "ACL-"; + private static final String USER = "client"; + private static final String PASS = "guest"; + + public void setUp() throws Exception + { + // Write out ACL for this test + AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW client ACCESS VIRTUALHOST", + "ACL ALLOW client CREATE QUEUE name='allow'", + "ACL ALLOW-LOG client CREATE QUEUE name='allow-log'", + "ACL DENY client CREATE QUEUE name='deny'", + "ACL DENY-LOG client CREATE QUEUE name='deny-log'"); + + super.setUp(); + + } + + @Override + public void tearDown() throws Exception + { + try + { + super.tearDown(); + } + catch (JMSException e) + { + //we're throwing this away as it can happen in this test as the state manager remembers exceptions + //that we provoked with authentication failures, where the test passes - we can ignore on con close + } + } + + /** + * Test that {@code allow} ACL entries do not log anything. + */ + public void testAllow() throws Exception + { + Connection conn = getConnection(USER, PASS); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + ((AMQSession) sess).createQueue(new AMQShortString("allow"), false, false, false); + + List matches = findMatches(ACL_LOG_PREFIX); + + assertTrue("Should be no ACL log messages", matches.isEmpty()); + } + + /** + * Test that {@code allow-log} ACL entries log correctly. + */ + public void testAllowLog() throws Exception + { + Connection conn = getConnection(USER, PASS); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + ((AMQSession) sess).createQueue(new AMQShortString("allow-log"), false, false, false); + + List matches = findMatches(ACL_LOG_PREFIX); + + assertEquals("Should only be one ACL log message", 1, matches.size()); + + String log = getLogMessage(matches, 0); + String actor = fromActor(log); + String subject = fromSubject(log); + String message = getMessageString(fromMessage(log)); + + validateMessageID(ACL_LOG_PREFIX + 1001, log); + + assertTrue("Actor " + actor + " should contain the user identity: " + USER, actor.contains(USER)); + assertTrue("Subject should be empty", subject.length() == 0); + assertTrue("Message should start with 'Allowed'", message.startsWith("Allowed")); + assertTrue("Message should contain 'Create Queue'", message.contains("Create Queue")); + assertTrue("Message should have contained the queue name", message.contains("allow-log")); + } + + /** + * Test that {@code deny-log} ACL entries log correctly. + */ + public void testDenyLog() throws Exception + { + Connection conn = getConnection(USER, PASS); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + try { + ((AMQSession) sess).createQueue(new AMQShortString("deny-log"), false, false, false); + fail("Should have denied queue creation"); + } + catch (AMQException amqe) + { + // Denied, so exception thrown + assertEquals("Expected ACCESS_REFUSED error code", AMQConstant.ACCESS_REFUSED, amqe.getErrorCode()); + } + + List matches = findMatches(ACL_LOG_PREFIX); + + assertEquals("Should only be one ACL log message", 1, matches.size()); + + String log = getLogMessage(matches, 0); + String actor = fromActor(log); + String subject = fromSubject(log); + String message = getMessageString(fromMessage(log)); + + validateMessageID(ACL_LOG_PREFIX + 1002, log); + + assertTrue("Actor " + actor + " should contain the user identity: " + USER, actor.contains(USER)); + assertTrue("Subject should be empty", subject.length() == 0); + assertTrue("Message should start with 'Denied'", message.startsWith("Denied")); + assertTrue("Message should contain 'Create Queue'", message.contains("Create Queue")); + assertTrue("Message should have contained the queue name", message.contains("deny-log")); + } + + /** + * Test that {@code deny} ACL entries do not log anything. + */ + public void testDeny() throws Exception + { + Connection conn = getConnection(USER, PASS); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + try { + ((AMQSession) sess).createQueue(new AMQShortString("deny"), false, false, false); + fail("Should have denied queue creation"); + } + catch (AMQException amqe) + { + // Denied, so exception thrown + assertEquals("Expected ACCESS_REFUSED error code", AMQConstant.ACCESS_REFUSED, amqe.getErrorCode()); + } + + List matches = findMatches(ACL_LOG_PREFIX); + + assertTrue("Should be no ACL log messages", matches.isEmpty()); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/AlertingTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/AlertingTest.java new file mode 100644 index 0000000000..336dedb422 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/AlertingTest.java @@ -0,0 +1,196 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.logging; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.server.management.plugin.HttpManagement; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager; +import org.apache.qpid.systest.rest.RestTestHelper; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class AlertingTest extends AbstractTestLogging +{ + + private Session _session; + private Connection _connection; + private Queue _destination; + private int _numMessages; + + private static final int ALERT_LOG_WAIT_PERIOD = 5000; + private static final String MESSAGE_COUNT_ALERT = "MESSAGE_COUNT_ALERT"; + + public void setUp() throws Exception + { + _numMessages = 50; + setTestSystemProperty("virtualhost.housekeepingCheckPeriod", String.valueOf(ALERT_LOG_WAIT_PERIOD)); + setTestSystemProperty("queue.alertThresholdQueueDepthMessages", String.valueOf(_numMessages)); + + // Then we do the normal setup stuff like starting the broker, getting a connection etc. + super.setUp(); + + setupConnection(); + } + + /** + * Create a new connection and ensure that our destination queue is created + * and bound. + * + * Note that the tests here that restart the broker rely on persistence. + * However, the queue creation here is transient. So the queue will not be + * rebound on restart. Hence the consumer creation here rather than just the + * once. + * + * The persistent messages will recreate the queue but not bind it (as it + * was not a durable queue) However, the consumer creation here will ensure + * that the queue is correctly bound and can receive new messages. + * + * @throws Exception + */ + private void setupConnection() + throws Exception + { + _connection = getConnection(); + _session = _connection.createSession(true, Session.SESSION_TRANSACTED); + _destination = _session.createQueue(getTestQueueName()); + + // Consumer is only used to actually create the destination + _session.createConsumer(_destination).close(); + } + + /** + * Checks the log file for MESSAGE_COUNT_ALERT, fails() the test if it's not found and + * places the entire contents in the message to help debug cruise control failures. + * + * @throws Exception + */ + private void wasAlertFired() throws Exception + { + if (!waitForMessage(MESSAGE_COUNT_ALERT, ALERT_LOG_WAIT_PERIOD)) + { + StringBuffer message = new StringBuffer("Could not find 'MESSAGE_COUNT_ALERT' in log file: " + _monitor.getMonitoredFile().getAbsolutePath()); + fail(message.toString()); + } + } + + public void testAlertingReallyWorks() throws Exception + { + // Send 5 messages, make sure that the alert was fired properly. + sendMessage(_session, _destination, _numMessages + 1); + _session.commit(); + wasAlertFired(); + } + + public void testAlertingReallyWorksWithRestart() throws Exception + { + sendMessage(_session, _destination, _numMessages + 1); + _session.commit(); + _connection.close(); + stopBroker(); + + // Rest the monitoring clearing the current output file. + _monitor.markDiscardPoint(); + startBroker(); + wasAlertFired(); + } + + /** + * Test that if the alert value is change from the previous value we can + * still get alerts. + * + * Test sends two messages to the broker then restarts the broker with new + * configuration. + * + * Validates that we only have two messages on the queue and then sends + * enough messages to trigger the alert. + * + * The alert is then validate. + * + * + * @throws Exception + */ + public void testAlertingReallyWorksWithChanges() throws Exception + { + // send some messages and nuke the logs + sendMessage(_session, _destination, 2); + _session.commit(); + // To prevent any failover/retry/connection dropped errors + _connection.close(); + + stopBroker(); + + _monitor.markDiscardPoint(); + + RestTestHelper restTestHelper = new RestTestHelper(findFreePort()); + TestBrokerConfiguration config = getBrokerConfiguration(); + config.addHttpManagementConfiguration(); + config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.PORT, restTestHelper.getHttpPort()); + config.removeObjectConfiguration(Port.class, TestBrokerConfiguration.ENTRY_NAME_JMX_PORT); + config.removeObjectConfiguration(Port.class, TestBrokerConfiguration.ENTRY_NAME_RMI_PORT); + + Map anonymousProviderAttributes = new HashMap(); + anonymousProviderAttributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); + anonymousProviderAttributes.put(AuthenticationProvider.NAME, "testAnonymous"); + config.addObjectConfiguration(AuthenticationProvider.class, anonymousProviderAttributes); + + // set password authentication provider on http port for the tests + config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER, + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); + config.setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); + config.setSaved(false); + restTestHelper.setUsernameAndPassword("webadmin", "webadmin"); + + startBroker(); + + setupConnection(); + + // Validate the queue depth is as expected + long messageCount = ((AMQSession) _session).getQueueDepth((AMQDestination) _destination); + assertEquals("Broker has invalid message count for test", 2, messageCount); + + // Ensure the alert has not occurred yet + assertLoggingNotYetOccured(MESSAGE_COUNT_ALERT); + + // Change max message count to 5, start broker and make sure that that's triggered at the right time + TestBrokerConfiguration brokerConfiguration = getBrokerConfiguration(); + setTestSystemProperty("queue.alertThresholdQueueDepthMessages","5"); + brokerConfiguration.setSaved(false); + + restTestHelper.submitRequest("queue/test/test/" + getTestQueueName(), "PUT", Collections.singletonMap(org.apache.qpid.server.model.Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, 5)); + // Trigger the new value + sendMessage(_session, _destination, 3); + _session.commit(); + + // Validate that the alert occurred. + wasAlertFired(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/BindingLoggingTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/BindingLoggingTest.java new file mode 100644 index 0000000000..646c17d1f2 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/BindingLoggingTest.java @@ -0,0 +1,227 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging; + +import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.Topic; +import java.io.IOException; +import java.util.List; + +/** + * Binding + * + * The Binding test suite validates that the follow log messages as specified in the Functional Specification. + * + * This suite of tests validate that the Binding messages occur correctly and according to the following format: + * + * BND-1001 : Create [: Arguments : ] + * BND-1002 : Deleted + */ +public class BindingLoggingTest extends AbstractTestLogging +{ + + static final String BND_PREFIX = "BND-"; + + private Connection _connection; + private Session _session; + private Queue _queue; + private Topic _topic; + + @Override + public void setUp() throws Exception + { + super.setUp(); + //Ignore broker startup messages + _monitor.markDiscardPoint(); + + _connection = getConnection(); + + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + _queue = _session.createQueue(getName()); + _topic = (Topic) getInitialContext().lookup(TOPIC); + } + + private void validateLogMessage(String log, String messageID, String message, String exchange, String rkey, String queueName) + { + validateMessageID(messageID, log); + + String subject = fromSubject(log); + + assertEquals("Queue not correct.", queueName, + AbstractTestLogSubject.getSlice("qu", subject)); + assertEquals("Routing Key not correct.", rkey, + AbstractTestLogSubject.getSlice("rk", subject)); + assertEquals("Virtualhost not correct.", "/test", + AbstractTestLogSubject.getSlice("vh", subject)); + assertEquals("Exchange not correct.", exchange, + AbstractTestLogSubject.getSlice("ex", subject)); + + assertEquals("Log Message not as expected", message, getMessageString(fromMessage(log))); + } + + /** + * testBindingCreate + * + * Description: + * The binding of a Queue and an Exchange is done via a Binding. When this Binding is created a BND-1001 Create message will be logged. + * Input: + * + * 1. Running Broker + * 2. New Client requests that a Queue is bound to a new exchange. + * Output: + * + * BND-1001 : Create : Arguments : {x-filter-jms-selector=} + * + * Validation Steps: + * 3. The BND ID is correct + * 4. This will be the first message for the given binding + */ + public void testBindingCreate() throws JMSException, IOException + { + _session.createConsumer(_queue).close(); + + List results = waitAndFindMatches(BND_PREFIX); + + assertEquals("Result set larger than expected.", 1, results.size()); + + String messageID = "BND-1001"; + String queueName = _queue.getQueueName(); + String exchange = "direct/amq.direct"; + String message = "Create"; + validateLogMessage(getLogMessage(results, 0), messageID, message, exchange, queueName, queueName); + } + + /** + * Description: + * A Binding can be made with a set of arguments. When this occurs we logged the key,value pairs as part of the Binding log message. When the subscriber with a JMS Selector consumes from an exclusive queue such as a topic. The binding is made with the JMS Selector as an argument. + * Input: + * + * 1. Running Broker + * 2. Java Client consumes from a topic with a JMS selector. + * Output: + * + * BND-1001 : Create : Arguments : {x-filter-jms-selector=} + * + * Validation Steps: + * 3. The BND ID is correct + * 4. The JMS Selector argument is present in the message + * 5. This will be the first message for the given binding + */ + public void testBindingCreateWithArguments() throws JMSException, IOException + { + final String SELECTOR = "Selector='True'"; + + _session.createDurableSubscriber(_topic, getName(), SELECTOR, false).close(); + + List results = waitAndFindMatches(BND_PREFIX); + + assertEquals("Result set larger than expected.", 1, results.size()); + + String messageID = "BND-1001"; + + // Perform full testing on the binding + String message = getMessageString(fromMessage(getLogMessage(results, 0))); + + validateLogMessage(getLogMessage(results, 0), messageID, message, + "topic/amq.topic", "topic", "clientid:" + getName()); + + assertTrue("JMSSelector not identified in binding:"+message, message.contains("jms-selector")); + assertTrue("Selector not part of binding.:"+message, message.contains(SELECTOR)); + + } + + /** + * Description: + * Bindings can be deleted so that a queue can be rebound with a different set of values. + * Input: + * + * 1. Running Broker + * 2. AMQP UnBind Request is made + * Output: + * + * BND-1002 : Deleted + * + * Validation Steps: + * 3. The BND ID is correct + * 4. There must have been a BND-1001 Create message first. + * 5. This will be the last message for the given binding + */ + public void testBindingDelete() throws JMSException, IOException + { + //Closing a consumer on a temporary queue will cause it to autodelete + // and so unbind. + _session.createConsumer(_session.createTemporaryQueue()).close(); + + if(isBroker010()) + { + //auto-delete is at session close for 0-10 + _session.close(); + } + + //wait for the deletion messages to be logged + waitForMessage("BND-1002"); + + //gather all the BND messages + List results = waitAndFindMatches(BND_PREFIX); + + // We will have two binds as we bind all queues to the default exchange + assertEquals("Result not as expected." + results, 2, results.size()); + + + String messageID = "BND-1001"; + String message = "Create"; + + String log = getLogMessage(results, 0); + validateMessageID(messageID, log); + assertEquals("Log Message not as expected", message, getMessageString(fromMessage(log))); + + String DIRECT = "direct/amq.direct"; + + messageID = "BND-1002"; + message = "Deleted"; + + log = getLogMessage(results, 1); + validateMessageID(messageID, log); + + String subject = fromSubject(log); + + validateBindingDeleteArguments(subject, "/test"); + + assertEquals("Log Message not as expected", message, getMessageString(fromMessage(log))); + + } + + private void validateBindingDeleteArguments(String subject, String vhostName) + { + String routingKey = AbstractTestLogSubject.getSlice("rk", subject); + + assertTrue("Routing Key does not start with TempQueue:"+routingKey, + routingKey.startsWith("TempQueue")); + assertEquals("Virtualhost not correct.", vhostName, + AbstractTestLogSubject.getSlice("vh", subject)); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/BrokerLoggingTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/BrokerLoggingTest.java new file mode 100644 index 0000000000..4952c4e10e --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/BrokerLoggingTest.java @@ -0,0 +1,1035 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.logging; + +import junit.framework.AssertionFailedError; + +import org.apache.qpid.server.BrokerOptions; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Transport; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.transport.ConnectionException; +import org.apache.qpid.util.LogMonitor; + +import java.io.IOException; +import java.net.Socket; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Broker Test Suite + * + * The Broker test suite validates that the follow log messages as specified in the Functional Specification. + * + * BRK-1001 : Startup : Version: Build: + * BRK-1002 : Starting : Listening on port + * BRK-1003 : Shutting down : port + * BRK-1004 : Ready + * BRK-1005 : Stopped + * BRK-1006 : Using configuration : + * BRK-1007 : Using logging configuration : + * + * These messages should only occur during startup. The tests need to verify the order of messages. In the case of the BRK-1002 and BRK-1003 the respective ports should only be available between the two log messages. + */ +public class BrokerLoggingTest extends AbstractTestLogging +{ + private static final String BROKER_MESSAGE_LOG_REG_EXP = ".*\\[\\w*\\] (BRK\\-\\d*) .*"; + private static final Pattern BROKER_MESSAGE_LOG_PATTERN = Pattern.compile(BROKER_MESSAGE_LOG_REG_EXP); + private static final String BRK_LOG_PREFIX = "BRK-"; + + public void setUp() throws Exception + { + setLogMessagePrefix(); + + // We either do this here or have a null check in tearDown. + // As when this test is run against profiles other than java it will NPE + _monitor = new LogMonitor(_outputFile); + //We explicitly do not call super.setUp as starting up the broker is + //part of the test case. + } + + /** + * Description: + * On startup the broker must report the active configuration file. The + * logging system must output this so that we can know what configuration + * is being used for this broker instance. + * + * Input: + * The value of -c specified on the command line. + * Output: + * MESSAGE BRK-1006 : Using configuration : + * Constraints: + * This MUST BE the first BRK log message. + * + * Validation Steps: + * 1. This is first BRK log message. + * 2. The BRK ID is correct + * 3. The config file is the full path to the file specified on + * the commandline. + * + * @throws Exception caused by broker startup + */ + public void testBrokerStartupConfiguration() throws Exception + { + String TESTID="BRK-1006"; + + if (isJavaBroker()) + { + startBroker(); + + // Now we can create the monitor as _outputFile will now be defined + _monitor = new LogMonitor(_outputFile); + + + String configFilePath = getConfigPath(); + + // Ensure we wait for TESTID to be logged + waitAndFindMatches(TESTID); + + List results = waitAndFindMatches(BRK_LOG_PREFIX); + try + { + // Validation + + assertTrue("BRKer message not logged", results.size() > 0); + + String log = getLogMessage(results, 0); + + //1 + validateMessageID(TESTID, log); + + //2 + results = findMatches(TESTID); + assertEquals("More than one configuration message found.", + 1, results.size()); + + //3 + assertTrue("Config file details not correctly logged, got " + + log + " but expected it to end with " + configFilePath, + log.endsWith(configFilePath)); + } + catch (AssertionFailedError afe) + { + dumpLogs(results, _monitor); + + throw afe; + } + } + } + + private String getConfigPath() + { + return getPathRelativeToWorkingDirectory(getTestConfigFile(DEFAULT_PORT)); + } + + /** + * Description: + * On startup the broker must report correctly report the log4j file in use. This is important as it can help diagnose why logging messages are not being reported. + * Input: + * No custom -l value should be provided on the command line so that the default value is correctly reported. + * Output: + * + * MESSAGE BRK-1007 : Using logging configuration : <$QPID_HOME>/etc/log4j.xml + * + * Validation Steps: + * + * 1. The BRK ID is correct + * 2. This occurs before the BRK-1001 startup message. + * 3. The log4j file is the full path to the file specified on the commandline. + * + * @throws Exception caused by broker startup + */ + public void testBrokerStartupDefaultLog4j() throws Exception + { + if (isJavaBroker() && isExternalBroker() && !isInternalBroker()) + { + String TESTID = "BRK-1007"; + + _brokerCommandHelper.removeBrokerCommandLog4JFile(); + + startBroker(); + + // Now we can create the monitor as _outputFile will now be defined + _monitor = new LogMonitor(_outputFile); + + // Ensure broker has fully started up. + getConnection(); + + // Ensure we wait for TESTID to be logged + waitAndFindMatches(TESTID); + + List results = waitAndFindMatches(BRK_LOG_PREFIX); + try + { + // Validation + + assertTrue("BRKer message not logged", results.size() > 0); + + boolean validation = false; + for (String rawLog : results) + { + // We don't care about messages after we have our log config + if (validation) + { + break; + } + + String log = getLog(rawLog); + + // Ensure we do not have a BRK-1001 message before + if (!getMessageID(log).equals(TESTID)) + { + assertFalse(getMessageID(log).equals("BRK-1001")); + continue; + } + + //1 + validateMessageID(TESTID, log); + + //2 + //There will be 1 copy of this startup message (via SystemOut) + assertEquals("Unexpected log4j configuration message count.", + 1, findMatches(TESTID).size()); + + //3 + String defaultLog4j = System.getProperty(QPID_HOME) + "/" + BrokerOptions.DEFAULT_LOG_CONFIG_FILE; + assertTrue("Log4j file(" + defaultLog4j + ") details not correctly logged:" + getMessageString(log), + getMessageString(log).endsWith(defaultLog4j)); + + validation = true; + } + + assertTrue("Validation not performed: " + TESTID + " not logged", validation); + } + catch (AssertionFailedError afe) + { + dumpLogs(results, _monitor); + + throw afe; + } + } + } + + /** + * Description: + * On startup the broker must report correctly report the log4j file in use. This is important as it can help diagnose why logging messages are not being reported. The broker must also be capable of correctly recognising the command line property to specify the custom logging configuration. + * Input: + * The value of -l specified on the command line. + * Output: + * + * MESSAGE BRK-1007 : Using logging configuration : + * + * Validation Steps: + * + * 1. The BRK ID is correct + * 2. This should occur before the BRK-1001 : Startup message + * 3. The log4j file is the full path to the file specified on the commandline. + * + * @throws Exception caused by broker startup + */ + public void testBrokerStartupCustomLog4j() throws Exception + { + // This logging startup code only occurs when you run a Java broker + if (isJavaBroker()) + { + String customLog4j = getBrokerCommandLog4JFile().getAbsolutePath(); + + String TESTID = "BRK-1007"; + + startBroker(); + + // Now we can create the monitor as _outputFile will now be defined + _monitor = new LogMonitor(_outputFile); + + + // Ensure broker has fully started up. + getConnection(); + + // Ensure we wait for TESTID to be logged + waitAndFindMatches(TESTID); + + List results = waitAndFindMatches(BRK_LOG_PREFIX); + try + { + // Validation + + assertTrue("BRKer message not logged", results.size() > 0); + + boolean validation = false; + for (String rawLog : results) + { + // We don't care about messages after we have our log config + if (validation) + { + break; + } + String log = getLog(rawLog); + + // Ensure we do not have a BRK-1001 message before + if (!getMessageID(log).equals(TESTID)) + { + assertFalse(getMessageID(log).equals("BRK-1001")); + continue; + } + + //1 + validateMessageID(TESTID, log); + + //2 + //There will be 1 copy of this startup message (via SystemOut) + assertEquals("Unexpected log4j configuration message count.", + 1, findMatches(TESTID).size()); + + //3 + String messageString = getMessageString(log); + assertTrue("Log4j file details not correctly logged. Message '" + + messageString + "' should contain '" +customLog4j + "'", + messageString.endsWith(customLog4j)); + + validation = true; + } + + assertTrue("Validation not performed: " + TESTID + " not logged", validation); + } + catch (AssertionFailedError afe) + { + dumpLogs(results, _monitor); + + throw afe; + } + } + } + + /** + * Description: On startup the broker reports the broker version number and svn build revision. This information is retrieved from the resource 'qpidversion.properties' which is located via the classloader. + * Input: The 'qpidversion.properties' file located on the classpath. + * Output: + * + * MESSAGE BRK-1001 : Startup : qpid Version: 0.6 Build: 767150 + * + * Validation Steps: + * + * 1. The BRK ID is correct + * 2. This occurs before any BRK-1002 listening messages are reported. + * + * @throws Exception caused by broker startup + */ + public void testBrokerStartupStartup() throws Exception + { + // This logging startup code only occurs when you run a Java broker, + // that broker must be started via Main so not an InVM broker. + if (isJavaBroker()) + { + String TESTID = "BRK-1001"; + + startBroker(); + + // Now we can create the monitor as _outputFile will now be defined + _monitor = new LogMonitor(_outputFile); + + // Ensure we wait for TESTID to be logged + waitAndFindMatches(TESTID); + + // Retrieve all BRK- log messages so we can check for an erroneous + // BRK-1002 message. + List results = findMatches(BRK_LOG_PREFIX); + + try + { + // Validation + + assertTrue("BRKer message not logged", results.size() > 0); + + boolean validation = false; + for (String rawLog : results) + { + if (validation) + { + //Stop checking once we have got to our startup test + break; + } + String log = getLog(rawLog); + + // Ensure we do not have a BRK-1002 message + if (!getMessageID(log).equals(TESTID)) + { + assertFalse(getMessageID(log).equals("BRK-1002")); + continue; + } + + //1 + validateMessageID(TESTID, log); + + //2 + //There will be 2 copies of the startup message (one via SystemOut, and one via Log4J) + assertEquals("Unexpected startup message count", + 2, findMatches(TESTID).size()); + + validation = true; + } + + assertTrue("Validation not performed: " + TESTID + " not logged", validation); + } + catch (AssertionFailedError afe) + { + dumpLogs(results, _monitor); + + throw afe; + } + } + } + + /** + * Description: + * On startup the broker may listen on a number of ports and protocols. Each of these must be reported as they are made available. + * Input: + * The default configuration with no SSL + * Output: + * + * MESSAGE BRK-1002 : Starting : Listening on TCP port 5672 + * + * Constraints: + * Additional broker configuration will occur between the Startup(BRK-1001) and Starting(BRK-1002) messages depending on what VirtualHosts are configured. + * Validation Steps: + * + * 1. The BRK ID is correct + * 2. This occurs after the BRK-1001 startup message + * 3. Using the default configuration a single BRK-1002 will be printed showing values TCP / 5672 + * + * @throws Exception caused by broker startup + */ + public void testBrokerStartupListeningTCPDefault() throws Exception + { + if (isJavaBroker()) + { + String TESTID = "BRK-1002"; + + startBroker(); + + // Now we can create the monitor as _outputFile will now be defined + _monitor = new LogMonitor(_outputFile); + + // Ensure broker has fully started up. + getConnection(); + + // Ensure we wait for TESTID to be logged + waitAndFindMatches(TESTID); + + // Retrieve all BRK- log messages so we can check for an erroneous + // BRK-1002 message. + List results = findMatches(BRK_LOG_PREFIX); + try + { + // Validation + + assertTrue("BRKer message not logged", results.size() > 0); + + boolean validation = false; + boolean foundBRK1001 = false; + for (String rawLog : results) + { + String log = getLog(rawLog); + + // using custom method to get id as getMessageId() fails to correctly identify id + // because of using brackets for protocols + String id = getBrokerLogId(log); + // Ensure we do not have a BRK-1002 message + if (!id.equals(TESTID)) + { + if (id.equals("BRK-1001")) + { + foundBRK1001 = true; + } + continue; + } + + assertTrue("BRK-1001 not logged before this message", foundBRK1001); + + //1 + assertEquals("Incorrect message", TESTID, id); + + //2 + //There will be 2 copies of the startup message (one via SystemOut, and one via Log4J) + assertEquals("Unexpected listen message count", + 2, findMatches(TESTID).size()); + + //3 + String message = getMessageString(log); + assertTrue("Expected Listen log not correct" + message, + message.endsWith("Listening on TCP port " + getPort())); + + validation = true; + } + + assertTrue("Validation not performed: " + TESTID + " not logged", validation); + } + catch (AssertionFailedError afe) + { + dumpLogs(results, _monitor); + + throw afe; + } + } + } + + private String getBrokerLogId(String log) + { + Matcher m = BROKER_MESSAGE_LOG_PATTERN.matcher(log); + if (m.matches()) + { + return m.group(1); + } + return getMessageID(log); + } + + /** + * Description: + * On startup the broker may listen on a number of ports and protocols. Each of these must be reported as they are made available. + * Input: + * The default configuration with SSL enabled + * Output: + * + * MESSAGE BRK-1002 : Starting : Listening on TCP port 5672 + * MESSAGE BRK-1002 : Starting : Listening on TCP/SSL port 8672 + * + * Constraints: + * Additional broker configuration will occur between the Startup(BRK-1001) and Starting(BRK-1002) messages depending on what VirtualHosts are configured. + * Validation Steps: + * + * 1. The BRK ID is correct + * 2. This occurs after the BRK-1001 startup message + * 3. With SSL enabled in the configuration two BRK-1002 will be printed (order is not specified) + * 1. One showing values [TCP] 5672 + * 2. One showing values [SSL] 5671 + * + * @throws Exception caused by broker startup + */ + public void testBrokerStartupListeningTCPSSL() throws Exception + { + if (isJavaBroker()) + { + String TESTID = "BRK-1002"; + + // Enable SSL on the connection + Map sslPortAttributes = new HashMap(); + sslPortAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); + sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT); + sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT); + sslPortAttributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); + sslPortAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); + getBrokerConfiguration().addObjectConfiguration(Port.class, sslPortAttributes); + + startBroker(); + + // Now we can create the monitor as _outputFile will now be defined + _monitor = new LogMonitor(_outputFile); + + // Ensure broker has fully started up. + getConnection(); + + // Ensure we wait for TESTID to be logged + waitAndFindMatches(TESTID); + + // Retrieve all BRK- log messages so we can check for an erroneous + // BRK-1002 message. + List results = findMatches(BRK_LOG_PREFIX); + try + { + // Validation + + assertTrue("BRKer message not logged", results.size() > 0); + + boolean validation = false; + boolean foundBRK1001 = false; + for (String rawLog : results) + { + String log = getLog(rawLog); + + String id = getBrokerLogId(log); + // Ensure we do not have a BRK-1002 message + if (!id.equals(TESTID)) + { + if (id.equals("BRK-1001")) + { + foundBRK1001 = true; + } + continue; + } + + assertTrue("BRK-1001 not logged before this message", foundBRK1001); + + //1 + assertEquals("Incorrect message", TESTID, id); + + //2 + //There will be 4 copies of the startup message (two via SystemOut, and two via Log4J) + List listenMessages = findMatches(TESTID); + assertEquals("Four listen messages should be found.", + 4, listenMessages .size()); + + int tcpStarted = 0; + int sslStarted = 0; + + for (String message : listenMessages) + { + if (message.endsWith("Listening on TCP port " + getPort())) + { + tcpStarted++; + } + if (message.endsWith("Listening on SSL port " + DEFAULT_SSL_PORT)) + { + sslStarted++; + } + } + + assertEquals("Unexpected number of logs 'Listening on TCP port'", 2, tcpStarted); + assertEquals("Unexpected number of logs 'Listening on SSL port'", 2, sslStarted); + + //4 Test ports open + testSocketOpen(getPort()); + testSocketOpen(DEFAULT_SSL_PORT); + + validation = true; + } + + assertTrue("Validation not performed: " + TESTID + " not logged", validation); + } + catch (AssertionFailedError afe) + { + dumpLogs(results, _monitor); + + throw afe; + } + } + } + + /** + * Description: + * The final message the broker will print when it has performed all initialisation and listener startups will be to log the BRK-1004 Ready message + * Input: + * No input, all successful broker startups will show BRK-1004 messages. + * Output: + * + * 2009-07-09 15:50:20 +0100 MESSAGE BRK-1004 : Qpid Broker Ready + * + * Validation Steps: + * + * 1. The BRK ID is correct + * 2. This occurs after the BRK-1001 startup message + * 3. This must be the last message the broker prints after startup. Currently, if there is no further interaction with the broker then there should be no more logging. + * + * @throws Exception caused by broker startup + */ + public void testBrokerStartupReady() throws Exception + { + if (isJavaBroker()) + { + String TESTID = "BRK-1004"; + + startBroker(); + + //Ensure the broker has fully started up. + getConnection(); + // Ensure we wait for TESTID to be logged + waitAndFindMatches(TESTID); + + // Retrieve all BRK- log messages so we can check for an erroneous + // BRK-1001 message. + List results = findMatches(BRK_LOG_PREFIX); + try + { + // Validation + + assertTrue("BRKer message not logged", results.size() > 0); + + boolean validationComplete = false; + boolean foundBRK1001 = false; + + for (int i=0; i < results.size(); i++) + { + String rawLog = results.get(i); + String log = getLog(rawLog); + + // Ensure we do not have a BRK-1001 message + if (!getMessageID(log).equals(TESTID)) + { + if (getMessageID(log).equals("BRK-1001")) + { + foundBRK1001 = true; + } + continue; + } + + assertTrue("BRK-1001 not logged before this message", foundBRK1001); + + //1 + validateMessageID(TESTID, log); + + //2 + assertEquals("Ready message not present", "Qpid Broker Ready", getMessageString(log)); + + //There will be 2 copies of the startup message (one via SystemOut, and one via Log4J) + assertEquals("Unexpected ready message count", + 2, findMatches(TESTID).size()); + assertEquals("The ready messages should have been the last 2 messages", results.size() - 2, i); + + validationComplete = true; + break; + } + + assertTrue("Validation not performed: " + TESTID + " not logged", validationComplete); + } + catch (AssertionFailedError afe) + { + dumpLogs(results, _monitor); + + throw afe; + } + } + } + + /** + * Description: + * On startup the broker may listen on a number of ports and protocols. Each of these must then report a shutting down message as they stop listening. + * Input: + * The default configuration with no SSL + * Output: + * + * MESSAGE BRK-1003 : Shutting down : TCP port 5672 + * + * Validation Steps: + * + * 1. The BRK ID is correct + * 2. Only TCP is reported with the default configuration with no SSL. + * 3. The default port is correct + * 4. The port is not accessible after this message + * + * @throws Exception caused by broker startup + */ + public void testBrokerShutdownListeningTCPDefault() throws Exception + { + if (isJavaBroker() && isInternalBroker()) + { + String TESTID = "BRK-1003"; + + startBroker(); + + // Now we can create the monitor as _outputFile will now be defined + _monitor = new LogMonitor(_outputFile); + + stopBroker(); + + //Give broker time to shutdown and flush log + checkSocketClosed(getPort()); + + List results = waitAndFindMatches(BRK_LOG_PREFIX); + try + { + // Validation + + assertTrue("BRKer message not logged", results.size() > 0); + + boolean validation = false; + boolean foundBRK1001 = false; + for (String rawLog : results) + { + String log = getLog(rawLog); + + // Ensure we do not have a BRK-1002 message + if (!getMessageID(log).equals(TESTID)) + { + if (getMessageID(log).equals("BRK-1001")) + { + foundBRK1001 = true; + } + continue; + } + + assertTrue("BRK-1001 not logged before this message", foundBRK1001); + + //1 + validateMessageID(TESTID, log); + + //2 + assertEquals("More than one listen message found.", + 1, findMatches(TESTID).size()); + + //3 + String message = getMessageString(log); + assertTrue("Expected shutdown log not correct" + message, + message.endsWith("TCP port " + getPort())); + + //4 + checkSocketClosed(getPort()); + + validation = true; + } + + assertTrue("Validation not performed: " + TESTID + " not logged", validation); + } + catch (AssertionFailedError afe) + { + dumpLogs(results, _monitor); + + throw afe; + } + } + } + + /** + * Description: + * On startup the broker may listen on a number of ports and protocols. Each of these must be reported as they are made available. + * Input: + * The default configuration with SSL enabled + * Output: + * + * MESSAGE BRK-1002 : Starting : Listening on TCP port 5672 + * MESSAGE BRK-1002 : Starting : Listening on TCP/SSL port 8672 + * + * Constraints: + * Additional broker configuration will occur between the Startup(BRK-1001) and Starting(BRK-1002) messages depending on what VirtualHosts are configured. + * Validation Steps: + * + * 1. The BRK ID is correct + * 2. This occurs after the BRK-1001 startup message + * 3. With SSL enabled in the configuration two BRK-1002 will be printed (order is not specified) + * 1. One showing values TCP / 5672 + * 2. One showing values TCP/SSL / 5672 + * + * @throws Exception caused by broker startup + */ + public void testBrokerShutdownListeningTCPSSL() throws Exception + { + if (isJavaBroker() && isInternalBroker()) + { + String TESTID = "BRK-1003"; + + // Enable SSL on the connection + Map sslPortAttributes = new HashMap(); + sslPortAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); + sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT); + sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT); + sslPortAttributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); + sslPortAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); + getBrokerConfiguration().addObjectConfiguration(Port.class, sslPortAttributes); + + startBroker(); + + // Now we can create the monitor as _outputFile will now be defined + _monitor = new LogMonitor(_outputFile); + + +// //Clear any startup messages as we don't need them for validation +// _monitor.reset(); + //Stop the broker to get the log messages for testing + stopBroker(); + + //Give broker time to shutdown and flush log + checkSocketClosed(getPort()); + + List results = waitAndFindMatches(TESTID); + try + { + // Validation + + assertTrue(TESTID + " messages not logged", results.size() > 0); + + String log = getLog(results.get(0)); + + //1 + validateMessageID(TESTID, log); + + //2 + List listenMessages = findMatches(TESTID); + assertEquals("Two shutdown messages should be found.", + 2, listenMessages.size()); + + int tcpShuttingDown = 0; + int sslShuttingDown = 0; + + for (String m : listenMessages) + { + if (m.endsWith("Shutting down : TCP port " + getPort())) + { + tcpShuttingDown++; + } + if (m.endsWith("Shutting down : SSL port " + DEFAULT_SSL_PORT)) + { + sslShuttingDown++; + } + } + + assertEquals("Unexpected number of logs 'Shutting down : TCP port'", 1, tcpShuttingDown); + assertEquals("Unexpected number of logs 'Shutting down : SSL port'", 1, sslShuttingDown); + + //4 + //Test Port closed + checkSocketClosed(getPort()); + //Test SSL Port closed + checkSocketClosed(DEFAULT_SSL_PORT); + } + catch (AssertionFailedError afe) + { + dumpLogs(results, _monitor); + + throw afe; + } + } + } + + /** + * Description: + * Input: + * No input, all clean broker shutdowns will show BRK-1005 messages. + * Output: + * + * MESSAGE BRK-1005 : Stopped + * + * Constraints: + * This is the LAST message the broker will log. + * Validation Steps: + * + * 1. The BRK ID is correct + * 2. This is the last message the broker will log. + * + * @throws Exception caused by broker startup + */ + public void testBrokerShutdownStopped() throws Exception + { + if (isJavaBroker() && isInternalBroker()) + { + String TESTID = "BRK-1005"; + + startBroker(); + + // Now we can create the monitor as _outputFile will now be defined + _monitor = new LogMonitor(_outputFile); + + getConnection().close(); + + stopBroker(); + + // Ensure the broker has shutdown before retreving results + checkSocketClosed(getPort()); + + waitAndFindMatches(TESTID); + + List results = waitAndFindMatches(BRK_LOG_PREFIX); + try + { + // Validation + + assertTrue("BRKer message not logged", results.size() > 0); + + boolean validation = false; + for (String rawLog : results) + { + assertFalse("More broker log statements present after ready message", validation); + String log = getLog(rawLog); + + // Ignore all logs until we get to the test id. + if (!getMessageID(log).equals(TESTID)) + { + continue; + } + + //1 + validateMessageID(TESTID, log); + + //2 + assertEquals("More than one ready message found.", + 1, findMatches(TESTID).size()); + + //3 + assertEquals("Stopped message not present", "Stopped", getMessageString(log)); + + validation = true; + } + + assertTrue("Validation not performed: " + TESTID + " not logged", validation); + } + catch (AssertionFailedError afe) + { + dumpLogs(results, _monitor); + + throw afe; + } + } + } + + /** + * Test that a socket on the given port is closed. + * + * Does this by attempting to connect to the port and expecting a + * ConnectionRefused IOException or a ConnectionException + * + * @param port the port number + */ + private void checkSocketClosed(int port) + { + try + { + Socket socket = new Socket((String) null, port); + fail("Socket not closed on port:" + port); + } + catch (ConnectionException e) + { + //normal path + } + catch (IOException e) + { + if (!e.getMessage().startsWith("Connection refused")) + { + fail("Socket not closed on port:" + port + ":" + e.getMessage()); + // Keep stack trace for diagnosis. + e.printStackTrace(System.err); + } + } + } + + /** + * Test that a socket on the given port is open. + * + * Does this by attempting to connect to the port and expecting a + * The connection to succeed. + * It then closes the socket and expects that to work cleanly. + * + * @param port the port number + */ + private void testSocketOpen(int port) + { + try + { + Socket socket = new Socket((String) null, port); + socket.close(); + } + catch (IOException e) + { + fail("Unable to open and close socket to port:" + port + + ". Due to:" + e.getMessage()); + } + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/ChannelLoggingTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/ChannelLoggingTest.java new file mode 100644 index 0000000000..047151684f --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/ChannelLoggingTest.java @@ -0,0 +1,417 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging; + +import org.apache.qpid.AMQChannelClosedException; +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; + +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.Queue; +import javax.jms.Session; +import java.util.List; +import java.util.regex.Pattern; + +public class ChannelLoggingTest extends AbstractTestLogging +{ + private static final String CHANNEL_CLOSE_FORCED_MESSAGE_PATTERN = "CHN-1003 : Close : \\d* - .*"; + private static final String CHANNEL_PREFIX = "CHN-"; + + // No explicit startup configuration is required for this test + // so no setUp() method + + /** + * Description: + * When a new Channel (JMS Session) is created this will be logged as a CHN-1001 Create message. The messages will contain the prefetch details about this new Channel. + * Input: + * + * 1. Running Broker + * 2. New JMS Session/Channel creation + * + * Output: + * CHN-1001 : Create + * CHN-1004 : Prefetch Size (bytes) {0,number} : Count {1,number} + * + * Validation Steps: + * 1. The CHN ID is correct + * 2. The prefetch value matches that defined by the requesting client. + * + * @throws Exception - if an error occurs + */ + public void testChannelCreate() throws Exception + { + assertLoggingNotYetOccured(CHANNEL_PREFIX); + + Connection connection = getConnection(); + + int PREFETCH = 12; + + // Test that calling session.close gives us the expected output + ((AMQConnection)connection).createSession(false, Session.AUTO_ACKNOWLEDGE,PREFETCH); + + // Wait to ensure that the CHN-1001 message is logged + waitForMessage("CHN-1001"); + + List results = findMatches("CHN-1001"); + + // Validation + assertEquals("CHN-1001 messages not logged", 1, results.size()); + + String log = getLogMessage(results, 0); + // MESSAGE [con:0(guest@anonymous(3273383)/test)/ch:1] CHN-1001 : Create + validateMessageID("CHN-1001", log); + final String fromActor = fromActor(log); + final int channelID = getChannelID(fromActor); + assertEquals("Incorrect Channel in actor:"+fromActor(log), isBroker010()? 0 : 1, channelID); + + if (!isBroker010()) + { + // Wait to ensure that the CHN-1004 message is logged + waitForMessage("CHN-1004"); + + results = findMatches("CHN-1004"); + + // Validation + assertEquals("CHN-1004 messages not logged", 1, results.size()); + log = getLogMessage(results, 0); + // MESSAGE [con:0(guest@anonymous(3273383)/test)/ch:1] CHN-1004 : Prefetch Size (bytes) {0,number} : Count {1,number} + validateMessageID("CHN-1004", log); + assertEquals("Incorrect Channel in actor:"+fromActor(log), 1, getChannelID(fromActor(log))); + assertTrue("Prefetch Count not correct",getMessageString(fromMessage(log)).endsWith("Count "+PREFETCH)); + } + + connection.close(); + } + + /** + * Description: + * The Java Broker implements consumer flow control for all ack modes except + * No-Ack. When a client connects the session's flow is initially set to + * Stopped. Verify this message appears + * + * Input: + * 1. Running broker + * 2. Create consumer + * Output: + * + * CHN-1002 : Flow Stopped + * + * Validation Steps: + * 4. The CHN ID is correct + * + * @throws Exception - if an error occurs + */ + + public void testChannelStartsFlowStopped() throws Exception + { + assertLoggingNotYetOccured(CHANNEL_PREFIX); + + Connection connection = getConnection(); + + // Create a session to fill up + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Queue queue = (Queue) getInitialContext().lookup(QUEUE); + MessageConsumer consumer = session.createConsumer(queue); + + connection.start(); + + // Wait to ensure that the CHN-1002 message is logged + waitForMessage("CHN-1002"); + + List results = findMatches(CHANNEL_PREFIX); + + assertTrue("No CHN messages logged", results.size() > 0); + + // The last channel message should be: + // + // INFO - MESSAGE [con:0(guest@anonymous(4205299)/test)/ch:1] [con:0(guest@anonymous(4205299)/test)/ch:1] CHN-1002 : Flow Stopped + + // Verify the last channel message is stopped + validateChannelStart(results, false); + } + + private void validateChannelStart(List results, boolean flowStarted) + { + String log = getLogMessageFromEnd(results, 0); + + String flow = flowStarted ? "Started" : "Stopped"; + validateMessageID("CHN-1002", log); + assertEquals("Message should be Flow " + flow, "Flow " + flow, getMessageString(fromMessage(log))); + } + + /** + * Description: + * The Java Broker implements consumer flow control for all ack modes except + * No-Ack. When the client first attempts to receive a message then the Flow + * status of the Session is set to Started. + * + * Input: + * 1. Running broker + * 2. Create a consumer + * 3. Attempt to receive a message + * Output: + * + * CHN-1002 : Flow Started + * + * Validation Steps: + * 4. The CHN ID is correct + * + * @throws Exception - if an error occurs + */ + + public void testChannelStartConsumerFlowStarted() throws Exception + { + assertLoggingNotYetOccured(CHANNEL_PREFIX); + + Connection connection = getConnection(); + + // Create a session to fill up + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Queue queue = (Queue) getInitialContext().lookup(QUEUE); + MessageConsumer consumer = session.createConsumer(queue); + + connection.start(); + + //Call receive to send the Flow On message + consumer.receiveNoWait(); + + //Wait for up to 2 seconds for message to appear + // ignore response as we will use the findMatches afterwards just + // incase it did take more than 2 seconds to log. + _monitor.waitForMessage(CHANNEL_PREFIX, 2000); + + // Wait to ensure that the CHN-1002 message is logged + waitForMessage("CHN-1002"); + + List results = findMatches(CHANNEL_PREFIX); + + assertTrue("No CHN messages logged", results.size() > 0); + + // The last two channel messages(before the close) should be: + // + // INFO [qpid.message] MESSAGE [con:1(guest@/127.0.0.1:49869/test)/ch:1] [con:1(guest@/127.0.0.1:49869/test)/ch:1] CHN-1002 : Flow Stopped + // INFO [qpid.message] MESSAGE [con:1(guest@/127.0.0.1:49869/test)/ch:1] [con:1(guest@/127.0.0.1:49869/test)/ch:1] CHN-1002 : Flow Started + + // Verify the last channel msg is Started. + validateChannelStart(results, true); + } + + /** + * Description: + * When the client gracefully closes the Connection then a CHN-1003 Close + * message will be issued. This must be the last message logged for this + * Channel. + * Input: + * 1. Running Broker + * 2. Connected Client + * 3. Client then requests that the Connection is closed + * Output: + * + * CHN-1003 : Close + * + * Validation Steps: + * 4. The MST ID is correct + * 5. This must be the last message logged for this Channel. + * + * @throws Exception - if an error occurs + */ + public void testChannelCloseViaConnectionClose() throws Exception + { + assertLoggingNotYetOccured(CHANNEL_PREFIX); + + Connection connection = getConnection(); + + // Create a session + connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // Close the connection to verify the created session closing is logged. + connection.close(); + + // Wait to ensure that the CHN-1003 message is logged + waitForMessage("CHN-1003"); + + List results = findMatches(CHANNEL_PREFIX); + + assertTrue("No CHN messages logged", results.size() > 0); + + // The last two channel messages should be: + // + // INFO - MESSAGE [con:0(guest@anonymous(4205299)/test)/ch:1] [con:0(guest@anonymous(4205299)/test)/ch:1] CHN-1002 : Flow On + + // Verify + validateChannelClose(results); + } + + /** + * Description: + * When the client gracefully closes the Connection then a CHN-1003 Close + * message will be issued. This must be the last message logged for this + * Channel. + * Input: + * 1. Running Broker + * 2. Connected Client + * 3. Client then requests that the Channel is closed + * Output: + * + * CHN-1003 : Close + * + * Validation Steps: + * 4. The MST ID is correct + * 5. This must be the last message logged for this Channel. + * + * @throws Exception - if an error occurs + */ + public void testChannelCloseViaChannelClose() throws Exception + { + assertLoggingNotYetOccured(CHANNEL_PREFIX); + + Connection connection = getConnection(); + + // Create a session and then close it + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + waitForMessage("CHN-1001"); + + // Wait to ensure that the CHN-1003 message is logged + session.close(); + waitForMessage("CHN-1003"); + + List results = findMatches(CHANNEL_PREFIX); + + assertTrue("No CHN messages logged", results.size() > 0); + + // Verify + validateChannelClose(results); + } + + public void testChannelClosedOnQueueArgumentsMismatch() throws Exception + { + assertLoggingNotYetOccured(CHANNEL_PREFIX); + + Connection connection = getConnection(); + + // Create a session and then close it + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + waitForMessage("CHN-1001"); + + String testQueueName = getTestQueueName(); + + Queue nonDurableQueue = (Queue) session.createQueue("direct://amq.direct/" + testQueueName + "/" + testQueueName + + "?durable='false'"); + + ((AMQSession)session).declareAndBind((AMQDestination)nonDurableQueue); + + Queue durableQueue = (Queue) session.createQueue("direct://amq.direct/" + testQueueName + "/" + testQueueName + + "?durable='true'"); + try + { + ((AMQSession)session).declareAndBind((AMQDestination) durableQueue); + fail("Exception not thrown"); + } + catch (AMQChannelClosedException acce) + { + // pass + } + catch (Exception e) + { + fail("Wrong exception thrown " + e); + } + waitForMessage("CHN-1003"); + + List results = findMatches(CHANNEL_PREFIX); + assertTrue("No CHN messages logged", results.size() > 0); + + String closeLog = results.get(results.size() -1); + int closeMessageID = closeLog.indexOf("CHN-1003"); + assertFalse("CHN-1003 is not found", closeMessageID == -1); + + String closeMessage = closeLog.substring(closeMessageID); + assertTrue("Unexpected close channel message :" + closeMessage, Pattern.matches(CHANNEL_CLOSE_FORCED_MESSAGE_PATTERN, closeMessage)); + + session.close(); + connection.close(); + } + + public void testChannelClosedOnExclusiveQueueDeclaredOnDifferentSession() throws Exception + { + assertLoggingNotYetOccured(CHANNEL_PREFIX); + + Connection connection = getConnection(); + + // Create a session and then close it + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + waitForMessage("CHN-1001"); + + Session session2 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + waitForMessage("CHN-1001"); + + String testQueueName = getTestQueueName(); + + Queue queue = (Queue) session.createQueue("direct://amq.direct/" + testQueueName + "/" + testQueueName + + "?exclusive='true'"); + + ((AMQSession)session).declareAndBind((AMQDestination)queue); + + try + { + ((AMQSession)session2).declareAndBind((AMQDestination) queue); + fail("Exception not thrown"); + } + catch (AMQException acce) + { + // pass + } + catch (Exception e) + { + fail("Wrong exception thrown " + e); + } + waitForMessage("CHN-1003"); + + List results = findMatches(CHANNEL_PREFIX); + assertTrue("No CHN messages logged", results.size() > 0); + + String closeLog = results.get(results.size() -1); + int closeMessageID = closeLog.indexOf("CHN-1003"); + assertFalse("CHN-1003 is not found", closeMessageID == -1); + + String closeMessage = closeLog.substring(closeMessageID); + assertTrue("Unexpected close channel message :" + closeMessage, Pattern.matches(CHANNEL_CLOSE_FORCED_MESSAGE_PATTERN, closeMessage)); + + session.close(); + connection.close(); + } + private void validateChannelClose(List results) + { + String open = getLogMessage(results, 0); + String close = getLogMessageFromEnd(results, 0); + + validateMessageID("CHN-1001", open); + validateMessageID("CHN-1003", close); + assertEquals("Message should be Close", "Close", getMessageString(fromMessage(close))); + assertEquals("Incorrect Channel ID closed", isBroker010()? 0 : 1, getChannelID(fromSubject(close))); + assertEquals("Channel IDs should be the same", getChannelID(fromActor(open)), getChannelID(fromSubject(close))); + assertEquals("Connection IDs should be the same", getConnectionID(fromActor(open)), getConnectionID(fromSubject(close))); + } +} \ No newline at end of file diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/ConnectionLoggingTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/ConnectionLoggingTest.java new file mode 100644 index 0000000000..0be1f69948 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/ConnectionLoggingTest.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.server.logging; + +import javax.jms.Connection; + +import org.apache.qpid.common.QpidProperties; + +import java.util.HashMap; +import java.util.List; +import java.util.TreeSet; + +public class ConnectionLoggingTest extends AbstractTestLogging +{ + private static final String CONNECTION_PREFIX = "CON-"; + + // No explicit startup configuration is required for this test + // so no setUp() method + + /** + * Description: + * When a new connection is made to the broker this must be logged. + * + * Input: + * 1. Running Broker + * 2. Connecting client + * Output: + * CON-1001 : Open : Client ID {0}[ : Protocol Version : {1}] + * + * Validation Steps: + * 1. The CON ID is correct + * 2. This is the first CON message for that Connection + * + * @throws Exception - if an error occurs + */ + public void testConnectionOpen() throws Exception + { + assertLoggingNotYetOccured(CONNECTION_PREFIX); + + Connection connection = getConnection(); + String clientid = connection.getClientID(); + + // Wait until opened + waitForMessage("CON-1001"); + + // Close the connection + connection.close(); + + // Wait to ensure that the desired message is logged + waitForMessage("CON-1002"); + + List results = waitAndFindMatches("CON-1001"); + + // MESSAGE [con:1(/127.0.0.1:46927)] CON-1001 : Open + // MESSAGE [con:1(/127.0.0.1:46927)] CON-1001 : Open : Protocol Version : 0-9 + // MESSAGE [con:1(/127.0.0.1:46927)] CON-1001 : Open : Client ID : clientid : Protocol Version : 0-9 : Client Version : 1.2.3_4 + // MESSAGE [con:0(/127.0.0.1:46927)] CON-1002 : Close + + HashMap> connectionData = splitResultsOnConnectionID(results); + + // Get the last Integer from keySet of the ConnectionData + int connectionID = new TreeSet(connectionData.keySet()).last(); + + //Use just the data from the last connection for the test + results = connectionData.get(connectionID); + + assertEquals("Unexpected CON-1001 messages count", 3, results.size()); + + String log = getLogMessage(results, 0); + // MESSAGE [con:1(/127.0.0.1:52540)] CON-1001 : Open + //1 & 2 + validateMessageID("CON-1001",log); + + // validate the last three CON-1001 messages. + // MESSAGE [con:1(/127.0.0.1:52540)] CON-1001 : Open : Client ID : clientid : Protocol Version : 0-9 : Client Version : 1.2.3_4 : Client Product : product + validateConnectionOpen(results, 0, true, true, clientid, true, QpidProperties.getReleaseVersion(), true, QpidProperties.getProductName()); + + // MESSAGE [con:1(/127.0.0.1:52540)] CON-1001 : Open : Protocol Version : 0-9 + validateConnectionOpen(results, 1, true, false, null, false, null, false, null); + + // MESSAGE [con:1(/127.0.0.1:52540)] CON-1001 : Open + validateConnectionOpen(results, 2, false, false, null, false, null, false, null); + } + + private void validateConnectionOpen(List results, int positionFromEnd, + boolean protocolVersionPresent, boolean clientIdOptionPresent, String clientIdValue, + boolean clientVersionPresent, String clientVersionValue, boolean clientProductPresent, String clientProductValue) + { + String log = getLogMessageFromEnd(results, positionFromEnd); + + validateMessageID("CON-1001",log); + + assertEquals("unexpected Client ID option state", clientIdOptionPresent, fromMessage(log).contains("Client ID :")); + + if(clientIdOptionPresent && clientIdValue != null) + { + assertTrue("Client ID value is not present: " + clientIdValue, fromMessage(log).contains(clientIdValue)); + } + + assertEquals("unexpected Protocol Version option state", + protocolVersionPresent, fromMessage(log).contains("Protocol Version :")); + //fixme there is no way currently to find out the negotiated protocol version + // The delegate is the versioned class ((AMQConnection)connection)._delegate + + assertEquals("unexpected Client Version option state", clientVersionPresent, fromMessage(log).contains("Client Version :")); + + if(clientVersionPresent && clientVersionValue != null) + { + assertTrue("Client version value is not present: " + clientVersionValue, fromMessage(log).contains(clientVersionValue)); + } + + assertEquals("unexpected Client Product option state", clientVersionPresent, fromMessage(log).contains("Client Product :")); + + if(clientProductPresent && clientProductValue != null) + { + assertTrue("Client product value is not present: " + clientProductValue, fromMessage(log).contains(clientProductValue)); + } + } + + /** + * Description: + * When a connected client closes the connection this will be logged as a CON-1002 message. + * Input: + * + * 1. Running Broker + * 2. Connected Client + * Output: + * + * CON-1002 : Close + * + * Validation Steps: + * 3. The CON ID is correct + * 4. This must be the last CON message for the Connection + * 5. It must be preceded by a CON-1001 for this Connection + */ + public void testConnectionClose() throws Exception + { + assertLoggingNotYetOccured(CONNECTION_PREFIX); + + Connection connection = getConnection(); + + // Wait until opened + waitForMessage("CON-1001"); + + // Close the conneciton + connection.close(); + + // Wait to ensure that the desired message is logged + waitForMessage("CON-1002"); + + List results = findMatches(CONNECTION_PREFIX); + + // Validation + + // We should have at least four messages + assertTrue("CON messages not logged:" + results.size(), results.size() >= 4); + + // Validate Close message occurs + String log = getLogMessageFromEnd(results, 0); + validateMessageID("CON-1002",log); + assertTrue("Message does not end with close:" + log, log.endsWith("Close")); + + // Extract connection ID to validate there is a CON-1001 messasge for it + final String logSubject = fromSubject(log); + int closeConnectionID = getConnectionID(logSubject); + assertTrue("Could not get the connection id from CLOSE message: " + logSubject, closeConnectionID != -1); + + //Previous log message should be the open + log = getLogMessageFromEnd(results, 1); + // MESSAGE [con:1(/127.0.0.1:52540)] CON-1001 : Open : Client ID : clientid : Protocol Version : 0-9 + validateMessageID("CON-1001",log); + + // Extract connection ID to validate it matches the CON-1002 messasge + int openConnectionID = getConnectionID(fromActor(log)); + assertTrue("Could not find connection id in OPEN", openConnectionID != -1); + + // Check connection ids match + assertEquals("Connection IDs do not match", closeConnectionID, openConnectionID); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/ConsumerLoggingTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/ConsumerLoggingTest.java new file mode 100644 index 0000000000..f321b4e8e0 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/ConsumerLoggingTest.java @@ -0,0 +1,407 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging; + +import javax.jms.QueueBrowser; +import junit.framework.AssertionFailedError; + +import org.apache.qpid.client.AMQConnection; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.Topic; +import java.io.IOException; +import java.util.List; + +/** + * Subscription + * + * The Subscription test suite validates that the follow log messages as specified in the Functional Specification. + * + * This suite of tests validate that the Subscription messages occur correctly and according to the following format: + * + * SUB-1001 : Create : [Durable] [Arguments : ] + * SUB-1002 : Close + * SUB-1003 : State : + */ +public class ConsumerLoggingTest extends AbstractTestLogging +{ + static final String SUB_PREFIX = "SUB-"; + + private Connection _connection; + private Session _session; + private Queue _queue; + private Topic _topic; + + @Override + public void setUp() throws Exception + { + super.setUp(); + //Remove broker startup logging messages + _monitor.markDiscardPoint(); + + _connection = getConnection(); + + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + _queue = _session.createQueue(getTestQueueName() + "Queue"); + _topic = _session.createTopic(getTestQueueName() + "Topic"); + } + + /** + * Description: + * When a Subscription is created it will be logged. This test validates that Subscribing to a transient queue is correctly logged. + * Input: + * + * 1. Running Broker + * 2. Create a new Subscription to a transient queue/topic. + * Output: 6 + * + * SUB-1001 : Create + * + * Validation Steps: + * 3. The SUB ID is correct + * + * @throws java.io.IOException - if there is a problem getting the matches + * @throws javax.jms.JMSException - if there is a problem creating the consumer + */ + public void testSubscriptionCreate() throws JMSException, IOException + { + _session.createConsumer(_queue); + + //Validate + + //Ensure that we wait for the SUB log message + waitAndFindMatches("SUB-1001"); + + List results = findMatches(SUB_PREFIX); + + assertEquals("Result set larger than expected.", 1, results.size()); + + String log = getLogMessage(results, 0); + + validateMessageID("SUB-1001", log); + + assertEquals("Log Message not as expected", "Create", getMessageString(fromMessage(log))); + } + + /** + * Description: + * The creation of a Durable Subscription, such as a JMS DurableTopicSubscriber will result in an extra Durable tag being included in the Create log message + * Input: + * + * 1. Running Broker + * 2. Creation of a JMS DurableTopicSubiber + * Output: + * + * SUB-1001 : Create : Durable + * + * Validation Steps: + * 3. The SUB ID is correct + * 4. The Durable tag is present in the message + * NOTE: A Subscription is not Durable, the queue it consumes from is. + * + * @throws java.io.IOException - if there is a problem getting the matches + * @throws javax.jms.JMSException - if there is a problem creating the consumer + */ + public void testSubscriptionCreateDurable() throws JMSException, IOException + { + _session.createDurableSubscriber(_topic, getName()); + + //Validate + //Ensure that we wait for the SUB log message + waitAndFindMatches("SUB-1001"); + + List results = findMatches(SUB_PREFIX); + + assertEquals("Result set not as expected.", 1, results.size()); + + String log = getLogMessage(results, 0); + + validateMessageID("SUB-1001", log); + + String message = getMessageString(fromMessage(log)); + assertTrue("Durable not on log message:" + message, message.contains("Durable")); + } + + /** + * Description: + * The creation of a Subscriber with a JMS Selector will result in the Argument field being populated. These argument key/value pairs are then shown in the log message. + * Input: + * + * 1. Running Broker + * 2. Subscriber created with a JMS Selector. + * Output: + * + * SUB-1001 : Create : Arguments : + * + * Validation Steps: + * 3. The SUB ID is correct + * 4. Argument tag is present in the message + * + * @throws java.io.IOException - if there is a problem getting the matches + * @throws javax.jms.JMSException - if there is a problem creating the consumer + */ + public void testSubscriptionCreateWithArguments() throws JMSException, IOException + { + final String SELECTOR = "Selector='True'"; + _session.createConsumer(_queue, SELECTOR); + + //Validate + + //Ensure that we wait for the SUB log message + waitAndFindMatches("SUB-1001"); + + List results = findMatches(SUB_PREFIX); + + assertEquals("Result set larger than expected.", 1, results.size()); + + String log = getLogMessage(results, 0); + + validateMessageID("SUB-1001", log); + + String message = getMessageString(fromMessage(log)); + assertTrue("Selector not on log message:" + message, message.contains(SELECTOR)); + } + + /** + * Description: + * The final combination of SUB-1001 Create messages involves the creation of a Durable Subscription that also contains a set of Arguments, such as those provided via a JMS Selector. + * Input: + * + * 1. Running Broker + * 2. Java Client creates a Durable Subscription with Selector + * Output: + * + * SUB-1001 : Create : Durable Arguments : + * + * Validation Steps: + * 3. The SUB ID is correct + * 4. The tag Durable is present in the message + * 5. The Arguments are present in the message + * + * @throws java.io.IOException - if there is a problem getting the matches + * @throws javax.jms.JMSException - if there is a problem creating the consumer + */ + public void testSubscriptionCreateDurableWithArguments() throws JMSException, IOException + { + final String SELECTOR = "Selector='True'"; + _session.createDurableSubscriber(_topic, getName(), SELECTOR, false); + + //Validate + + //Ensure that we wait for the SUB log message + waitAndFindMatches("SUB-1001"); + + List results = findMatches(SUB_PREFIX); + + assertEquals("Result set larger than expected.", 1, results.size()); + + String log = getLogMessage(results, 0); + + validateMessageID("SUB-1001", log); + + String message = getMessageString(fromMessage(log)); + assertTrue("Durable not on log message:" + message, message.contains("Durable")); + assertTrue("Selector not on log message:" + message, message.contains(SELECTOR)); + } + + /** + * Description: + * When a Subscription is closed it will log this so that it can be correlated with the Create. + * Input: + * + * 1. Running Broker + * 2. Client with a subscription. + * 3. The subscription is then closed. + * Output: + * + * SUB-1002 : Close + * + * Validation Steps: + * 1. The SUB ID is correct + * 2. There must be a SUB-1001 Create message preceding this message + * 3. This must be the last message from the given Subscription + * + * @throws java.io.IOException - if there is a problem getting the matches + * @throws javax.jms.JMSException - if there is a problem creating the consumer + */ + public void testSubscriptionClose() throws JMSException, IOException + { + _session.createConsumer(_queue).close(); + + //Validate + //Ensure that we wait for the SUB log message + waitAndFindMatches("SUB-1002"); + + List results = findMatches(SUB_PREFIX); + + //3 + assertEquals("Result set larger than expected.", 2, results.size()); + + // 2 + String log = getLogMessage(results, 0); + validateMessageID("SUB-1001", log); + // 1 + log = getLogMessage(results, 1); + validateMessageID("SUB-1002", log); + + String message = getMessageString(fromMessage(log)); + assertEquals("Log message is not close", "Close", message); + + } + + /** + * Description: + * When a Subscription fills its prefetch it will become suspended. This + * will be logged as a SUB-1003 message. + * Input: + * + * 1. Running broker + * 2. Message Producer to put more data on the queue than the client's prefetch + * 3. Client that ensures that its prefetch becomes full + * Output: + * + * SUB-1003 : State : + * + * Validation Steps: + * 1. The SUB ID is correct + * 2. The state is correct + * + * @throws java.io.IOException - if there is a problem getting the matches + * @throws javax.jms.JMSException - if there is a problem creating the consumer + */ + public void testSubscriptionSuspend() throws Exception, IOException + { + //Close session with large prefetch + _connection.createSession(false, Session.AUTO_ACKNOWLEDGE).close(); + + int PREFETCH = 15; + + //Create new session with small prefetch + _session = ((AMQConnection) _connection).createSession(true, Session.SESSION_TRANSACTED, PREFETCH); + + MessageConsumer consumer = _session.createConsumer(_queue); + + _connection.start(); + + //Start the dispatcher & Unflow the channel. + consumer.receiveNoWait(); + + //Fill the prefetch and two extra so that our receive bellow allows the + // subscription to become active + // Previously we set this to 17 so that it would return to a suspended + // state. However, testing has shown that the state change can occur + // sufficiently quickly that logging does not occur consistently enough + // for testing. + int SEND_COUNT = 16; + sendMessage(_session, _queue, SEND_COUNT); + _session.commit(); + // Retreive the first message, and start the flow of messages + Message msg = consumer.receive(1000); + assertNotNull("First message not retreived", msg); + _session.commit(); + + // Drain the queue to ensure there is time for the ACTIVE log message + // Check that we can received all the messages + int receivedCount = 0; + while (msg != null) + { + receivedCount++; + msg = consumer.receive(1000); + _session.commit(); + } + + //Validate we received all the messages + assertEquals("Not all sent messages received.", SEND_COUNT, receivedCount); + + // Fill the queue again to suspend the consumer + sendMessage(_session, _queue, SEND_COUNT); + _session.commit(); + + //Validate + List results = waitAndFindMatches("SUB-1003"); + + try + { + // Validation expects three messages. + // The Actor can be any one of the following depending on the exactly what is going on on the broker. + // Ideally we would test that we can get all of them but setting up + // the timing to do this in a consistent way is not benefitial. + // Ensuring the State is as expected is sufficient. +// INFO - MESSAGE [vh(/test)/qu(example.queue)] [sub:6(qu(example.queue))] SUB-1003 : State : +// INFO - MESSAGE [con:6(guest@anonymous(26562441)/test)/ch:3] [sub:6(qu(example.queue))] SUB-1003 : State : +// INFO - MESSAGE [sub:6(vh(test)/qu(example.queue))] [sub:6(qu(example.queue))] SUB-1003 : State : + + assertEquals("Result set not expected size:", 3, results.size()); + + // Validate Initial Suspension + String expectedState = "SUSPENDED"; + String log = getLogMessage(results, 0); + validateSubscriptionState(log, expectedState); + + // After being suspended the subscription should become active. + expectedState = "ACTIVE"; + log = getLogMessage(results, 1); + validateSubscriptionState(log, expectedState); + + // Validate that it was re-suspended + expectedState = "SUSPENDED"; + log = getLogMessage(results, 2); + validateSubscriptionState(log, expectedState); + // We only need validate the state. + } + catch (AssertionFailedError afe) + { + System.err.println("Log Dump:"); + for (String log : results) + { + System.err.println(log); + } + throw afe; + } + _connection.close(); + } + + /** + * Validate that the given log statement is a well formatted SUB-1003 + * message. That means the ID and expected state are correct. + * + * @param log the log to test + * @param expectedState the state that should be logged. + */ + private void validateSubscriptionState(String log, String expectedState) + { + validateMessageID("SUB-1003", log); + String logMessage = getMessageString(fromMessage(log)); + assertTrue("Log Message does not start with 'State'" + logMessage, + logMessage.startsWith("State")); + + assertTrue("Log Message does not have expected State of '" + + expectedState + "'" + logMessage, + logMessage.endsWith(expectedState)); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/DurableQueueLoggingTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/DurableQueueLoggingTest.java new file mode 100644 index 0000000000..dcc1837c5b --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/DurableQueueLoggingTest.java @@ -0,0 +1,311 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.AMQShortString; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Queue; +import javax.jms.Session; +import javax.naming.NamingException; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * The Queue test suite validates that the follow log messages as specified in + * the Functional Specification. + * + * This suite of tests validate that the Queue messages occur correctly and + * according to the following format: + * + * QUE-1001 : Create : [AutoDelete] [Durable|Transient] [Priority:] [Owner:] + */ +public class DurableQueueLoggingTest extends AbstractTestLogging +{ + protected String DURABLE = "Durable"; + protected String TRANSIENT = "Transient"; + protected boolean _durable; + + protected Connection _connection; + protected Session _session; + private static final String QUEUE_PREFIX = "QUE-"; + private static int PRIORITIES = 6; + + public void setUp() throws Exception + { + super.setUp(); + //Ensure we only have logs from our test + _monitor.markDiscardPoint(); + + _connection = getConnection(); + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _durable = true; + } + + /** + * Description: + * When a simple transient queue is created then a QUE-1001 create message + * is expected to be logged. + * Input: + * 1. Running broker + * 2. Persistent Queue is created from a client + * Output: + * + * QUE-1001 : Create : Owner: '' Durable + * + * Validation Steps: + * 3. The QUE ID is correct + * 4. The Durable tag is present in the message + * 5. The Owner is as expected + * + * @throws javax.jms.JMSException + * @throws javax.naming.NamingException + * @throws java.io.IOException + */ + public void testQueueCreateDurableExclusive() throws NamingException, JMSException, IOException + { + String queueName= getTestQueueName(); + // To force a queue Creation Event we need to create a consumer. + Queue queue = (Queue) _session.createQueue("direct://amq.direct/" + queueName + "/" + queueName + "?durable='" + _durable + "'&exclusive='true'"); + + _session.createConsumer(queue); + + List results = waitForMesssage(); + + String clientID = _connection.getClientID(); + assertNotNull("clientID should not be null", clientID); + + // in 0-8/9/9-1 an exclusive queue will be deleted when the connection is closed, so auto-delete is true. + // in 0-10 an exclusive queue outlasts the creating connection and so is not auto-delete + // the queue only has owner as the client-id in 0-8/9/91 where exclusivity is taken to mean exclusive to the + // client-id in perpetuity. For 0-10 exclusive means exclusive to a session. + validateQueueProperties(results, false, !(isBroker010() || _durable), (_durable && !isBroker010()) ? clientID : null); + } + + /** + * Description: + * When a simple transient queue is created then a QUE-1001 create message + * is expected to be logged. + * Input: + * 1. Running broker + * 2. Persistent Queue is created from a client + * Output: + * + * QUE-1001 : Create : Owner: '' Durable + * + * Validation Steps: + * 3. The QUE ID is correct + * 4. The Durable tag is present in the message + * 5. The Owner is as expected + * + * @throws javax.jms.JMSException + * @throws javax.naming.NamingException + * @throws java.io.IOException + */ + public void testQueueCreateDurable() throws NamingException, JMSException, IOException + { + String queueName = getTestQueueName(); + + // To force a queue Creation Event we need to create a consumer. + Queue queue = (Queue) _session.createQueue("direct://amq.direct/" + queueName + "/" + queueName + "?durable='" + _durable + "'"); + + _session.createConsumer(queue); + + List results = waitForMesssage(); + + validateQueueProperties(results, false, false, null); + } + + /** + * Description: + * When a simple transient queue is created then a QUE-1001 create message + * is expected to be logged. + * Input: + * 1. Running broker + * 2. AutoDelete Persistent Queue is created from a client + * Output: + * + * QUE-1001 : Create : Owner: '' AutoDelete Durable + * + * Validation Steps: + * 3. The QUE ID is correct + * 4. The Durable tag is present in the message + * 5. The Owner is as expected + * 6. The AutoDelete tag is present in the message + * + * @throws javax.jms.JMSException + * @throws javax.naming.NamingException + * @throws java.io.IOException + */ + public void testQueueCreatePersistentAutoDelete() throws NamingException, JMSException, IOException + { + String queueName = getTestQueueName(); + // To force a queue Creation Event we need to create a consumer. + Queue queue = (Queue) _session.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='"+_durable+"'&autodelete='true'"); + + _session.createConsumer(queue); + + List results = waitForMesssage(); + + validateQueueProperties(results, false, true, null); + } + + /** + * Description: + * When a simple transient queue is created then a QUE-1001 create message + * is expected to be logged. + * Input: + * 1. Running broker + * 2. Persistent Queue is created from a client + * Output: + * + * QUE-1001 : Create : Owner: '' Durable Priority: + * + * Validation Steps: + * 3. The QUE ID is correct + * 4. The Durable tag is present in the message + * 5. The Owner is as expected + * 6. The Priority level is correctly set + * + * @throws javax.jms.JMSException + * @throws javax.naming.NamingException + * @throws java.io.IOException + */ + public void testCreateQueuePersistentPriority() throws NamingException, JMSException, IOException, AMQException + { + // To Create a Priority queue we need to use AMQSession specific code + final Map arguments = new HashMap(); + arguments.put("x-qpid-priorities", PRIORITIES); + // Need to create a queue that does not exist so use test name + final String queueName = getTestQueueName(); + ((AMQSession) _session).createQueue(new AMQShortString(queueName), false, _durable, false, arguments); + + Queue queue = (Queue) _session.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='"+_durable+"'&autodelete='false'"); + + + //Need to create a Consumer to ensure that the log has had time to write + // as the above Create is Asynchronous + _session.createConsumer(queue); + + List results = waitForMesssage(); + + // Only 1 Queue message should hav been logged + assertEquals("Result set size not as expected", 1, results.size()); + + validateQueueProperties(results, true, false, null); + } + + /** + * Description: + * When a simple transient queue is created then a QUE-1001 create message + * is expected to be logged. + * Input: + * 1. Running broker + * 2. AutoDelete Persistent Queue is created from a client + * Output: + * + * QUE-1001 : Create : Owner: '' Durable Priority: + * + * Validation Steps: + * 3. The QUE ID is correct + * 4. The Durable tag is present in the message + * 5. The Owner is as expected + * 6. The AutoDelete tag is present in the message + * 7. The Priority level is correctly set + * + * @throws javax.jms.JMSException + * @throws javax.naming.NamingException + * @throws java.io.IOException + */ + public void testCreateQueuePersistentAutoDeletePriority() throws NamingException, JMSException, IOException, AMQException + { + // To Create a Priority queue we need to use AMQSession specific code + final Map arguments = new HashMap(); + arguments.put("x-qpid-priorities", PRIORITIES); + // Need to create a queue that does not exist so use test name + final String queueName = getTestQueueName() + "-autoDeletePriority"; + ((AMQSession) _session).createQueue(new AMQShortString(queueName), true, _durable, false, arguments); + + Queue queue = (Queue) _session.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='"+_durable+"'&autodelete='true'"); + + + //Need to create a Consumer to ensure that the log has had time to write + // as the above Create is Asynchronous + _session.createConsumer(queue); + + List results = waitForMesssage(); + + validateQueueProperties(results, true, true, null); + } + + private List waitForMesssage() throws IOException + { + // Validation + // Ensure we have received the QUE log msg. + waitForMessage("QUE-1001"); + + List results = findMatches(QUEUE_PREFIX); + + // Only 1 Queue message should hav been logged + assertEquals("Result set size not as expected", 1, results.size()); + + return results; + } + + public void validateQueueProperties(List results, boolean hasPriority, boolean hasAutodelete, String clientID) + { + String log = getLogMessage(results, 0); + + // Message Should be a QUE-1001 + validateMessageID("QUE-1001", log); + + // Queue is Durable + assertEquals(DURABLE + " keyword not correct in log entry", + _durable, fromMessage(log).contains(DURABLE)); + + assertEquals(TRANSIENT + " keyword not correct in log entry.", + !_durable, fromMessage(log).contains(TRANSIENT)); + + // Queue is Priority + assertEquals("Unexpected priority status:" + fromMessage(log), hasPriority, + fromMessage(log).contains("Priority: " + PRIORITIES)); + + // Queue is AutoDelete + assertEquals("Unexpected AutoDelete status:" + fromMessage(log), hasAutodelete, + fromMessage(log).contains("AutoDelete")); + + if(clientID != null) + { + assertTrue("Queue does not have correct owner value:" + fromMessage(log), + fromMessage(log).contains("Owner: " + clientID)); + } + else + { + assertFalse("Queue should not contain Owner tag:" + fromMessage(log), + fromMessage(log).contains("Owner")); + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/ExchangeLoggingTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/ExchangeLoggingTest.java new file mode 100644 index 0000000000..edffa7c0c0 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/ExchangeLoggingTest.java @@ -0,0 +1,254 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.logging; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQSession_0_10; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ExchangeDeleteBody; +import org.apache.qpid.framing.ExchangeDeleteOkBody; +import org.apache.qpid.framing.amqp_8_0.MethodRegistry_8_0; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import java.io.IOException; +import java.util.List; + +/** + * Exchange + * + * The Exchange test suite validates that the follow log messages as specified in the Functional Specification. + * + * This suite of tests validate that the Exchange messages occur correctly and according to the following format: + * + * EXH-1001 : Create : [Durable] Type: Name: + * EXH-1002 : Deleted + */ +public class ExchangeLoggingTest extends AbstractTestLogging +{ + + static final String EXH_PREFIX = "EXH-"; + + private Connection _connection; + private Session _session; + private Queue _queue; + private String _name; + private String _type; + + @Override + public void setUp() throws Exception + { + super.setUp(); + + _connection = getConnection(); + + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + _type = "direct"; + _name = getTestQueueName()+ "-exchange"; + + _queue = _session.createQueue(_type + "://" + _name + "/queue/queue"); + + } + + /** + * Description: + * When a durable exchange is created an EXH-1001 message is logged with the Durable tag. This will be the first message from this exchange. + * Input: + * + * 1. Running broker + * 2. Client requests a durable exchange be created. + * Output: + * + * EXH-1001 : Create : Durable Type: Name: + * + * Validation Steps: + * 3. The EXH ID is correct + * 4. The Durable tag is present in the message + */ + + public void testExchangeCreateDurable() throws JMSException, IOException + { + // The client cannot create durable exchanges lets just look at the + // ones the broker creates at startup. + + // They should all be durable + + // Ensure we have received the EXH log msg. + waitForMessage("EXH-1001"); + + List results = findMatches(EXH_PREFIX); + + assertTrue("No Results found for Exchange.", results.size()>0); + + validateExchangeCreate(results, true, false); + } + + /** + * Description: + * When an exchange is created an EXH-1001 message is logged. This will be the first message from this exchange. + * Input: + * + * 1. Running broker + * 2. Client requests an exchange be created. + * Output: + * + * EXH-1001 : Create : Type: Name: + * + * Validation Steps: + * 3. The EXH ID is correct + */ + public void testExchangeCreate() throws JMSException, IOException + { + //Ignore broker startup messages + _monitor.markDiscardPoint(); + + _session.createConsumer(_queue); + // Ensure we have received the EXH log msg. + waitForMessage("EXH-1001"); + + List results = findMatches(EXH_PREFIX); + + assertEquals("Result set larger than expected.", 1, results.size()); + + validateExchangeCreate(results, false, true); + } + + private void validateExchangeCreate(List results, boolean durable, boolean checkNameAndType) + { + String log = getLogMessage(results, 0); + String message = getMessageString(fromMessage(log)); + + validateMessageID("EXH-1001", log); + + assertTrue("Log Message does not start with create:" + message, + message.startsWith("Create")); + + assertEquals("Unexpected Durable state:" + message, durable, + message.contains("Durable")); + + if(checkNameAndType) + { + assertTrue("Log Message does not contain Type:" + message, + message.contains("Type: " + _type)); + assertTrue("Log Message does not contain Name:" + message, + message.contains("Name: " + _name)); + } + } + + /** + * Description: + * An Exchange can be deleted through an AMQP ExchangeDelete method. When this is successful an EXH-1002 Delete message will be logged. This will be the last message from this exchange. + * Input: + * + * 1. Running broker + * 2. A new Exchange has been created + * 3. Client requests that the new exchange be deleted. + * Output: + * + * EXH-1002 : Deleted + * + * Validation Steps: + * 4. The EXH ID is correct + * 5. There is a corresponding EXH-1001 Create message logged. + */ + public void testExchangeDelete() throws Exception, IOException + { + //Ignore broker startup messages + _monitor.markDiscardPoint(); + + //create the exchange by creating a consumer + _session.createConsumer(_queue); + + //now delete the exchange + if(isBroker010()) + { + ((AMQSession_0_10) _session).sendExchangeDelete(_name, false); + } + else + { + MethodRegistry_8_0 registry = new MethodRegistry_8_0(); + + ExchangeDeleteBody body = registry.createExchangeDeleteBody(0, new AMQShortString(_name), false, true); + + AMQFrame exchangeDeclare = body.generateFrame(((AMQSession)_session).getChannelId()); + + ((AMQConnection) _connection).getProtocolHandler().syncWrite(exchangeDeclare, ExchangeDeleteOkBody.class); + } + + //Wait and ensure we get our last EXH-1002 msg + waitForMessage("EXH-1002"); + + List results = findMatches(EXH_PREFIX); + + assertEquals("Result set larger than expected.", 2, results.size()); + + validateExchangeCreate(results, false, false); + + String log = getLogMessage(results, 1); + validateMessageID("EXH-1002", log); + + String message = getMessageString(fromMessage(log)); + assertEquals("Log Message not as expected", "Deleted", message); + + } + + public void testDiscardedMessage() throws Exception + { + //Ignore broker startup messages + _monitor.markDiscardPoint(); + + if (!isBroker010()) + { + // Default 0-8..-0-9-1 behaviour is for messages to be rejected (returned to client). + setTestClientSystemProperty("qpid.default_mandatory", "false"); + } + + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // Do not create consumer so queue is not created and message will be discarded. + final MessageProducer producer = _session.createProducer(_queue); + + // Sending message + final TextMessage msg = _session.createTextMessage("msg"); + producer.send(msg); + + final String expectedMessageBody = "Discarded Message : Name: " + _name + " Routing Key: " + _queue.getQueueName(); + + // Ensure we have received the EXH log msg. + waitForMessage("EXH-1003"); + + List results = findMatches(EXH_PREFIX); + assertEquals("Result set larger than expected.", 2, results.size()); + + final String log = getLogMessage(results, 1); + validateMessageID("EXH-1003", log); + + final String message = getMessageString(fromMessage(log)); + assertEquals("Log Message not as expected", expectedMessageBody, message); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/QueueLoggingTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/QueueLoggingTest.java new file mode 100644 index 0000000000..1c7b4c6be8 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/QueueLoggingTest.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.server.logging; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.failover.FailoverException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Queue; +import javax.jms.Session; +import javax.naming.NamingException; +import java.io.IOException; +import java.util.List; + +/** + * The Queue test suite validates that the follow log messages as specified in + * the Functional Specification. + * + * This suite of tests validate that the Queue messages occur correctly and + * according to the following format: + * + * QUE-1002 : Deleted + */ +public class QueueLoggingTest extends AbstractTestLogging +{ + protected Connection _connection; + protected Session _session; + private static final String QUEUE_PREFIX = "QUE-"; + + public void setUp() throws Exception + { + super.setUp(); + //Remove broker startup logging messages + _monitor.markDiscardPoint(); + + _connection = getConnection(); + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + /** + * Description: + * An explict QueueDelete request must result in a QUE-1002 Deleted message + * being logged. This can be done via an explict AMQP QueueDelete method. + * Input: + * + * 1. Running Broker + * 2. Queue created on the broker with no subscribers + * 3. Client requests the queue be deleted via a QueueDelete + * Output: + * + * QUE-1002 : Deleted + * + * Validation Steps: + * + * 4. The QUE ID is correct + * + * @throws java.io.IOException + * @throws javax.jms.JMSException + * @throws javax.naming.NamingException + */ + public void testQueueDelete() throws NamingException, JMSException, IOException, FailoverException, AMQException + { + // To force a queue Creation Event we need to create a consumer. + Queue queue = _session.createQueue(getTestQueueName()); + + _session.createConsumer(queue); + + // Delete Queue + ((AMQSession)_session).sendQueueDelete(new AMQShortString(queue.getQueueName())); + + //Perform a synchronous action to ensure that the above log will be on disk + _session.close(); + + // Validation + //Ensure that we wait for the QUE log message + waitAndFindMatches("QUE-1002"); + + List results = findMatches(QUEUE_PREFIX); + + // Only 1 Queue message should hav been logged + assertEquals("Result set size not as expected", 2, results.size()); + + String log = getLogMessage(results, 0); + + // Message Should be a QUE-1001 + validateMessageID("QUE-1001", log); + + String createdQueueName = AbstractTestLogSubject.getSlice("qu", fromSubject(log)); + + log = getLogMessage(results, 1); + // Message Should be a QUE-1002 + validateMessageID("QUE-1002", log); + + assertEquals("Log Message is incorrect ", "Deleted", getMessageString(fromMessage(log))); + + assertEquals("Queue Delete not for created queue:", createdQueueName, + AbstractTestLogSubject.getSlice("qu", fromSubject(log))); + } + + + /** + * Description: + * An explict QueueDelete request must result in a QUE-1002 Deleted message + * being logged. This can be done via an explict AMQP QueueDelete method. + * Input: + * + * 1. Running Broker + * 2. Queue created on the broker with no subscribers + * 3. Client creates a temporary queue then disconnects + * Output: + * + * QUE-1002 : Deleted + * + * Validation Steps: + * + * 4. The QUE ID is correct + * + * @throws java.io.IOException + * @throws javax.jms.JMSException + * @throws javax.naming.NamingException + */ + public void testQueueAutoDelete() throws NamingException, JMSException, IOException + { + // Create a temporary queue so that when we consume from it and + // then close the consumer it will be autoDeleted. + _session.createConsumer(_session.createTemporaryQueue()).close(); + + if(isBroker010()) + { + //auto-delete is at session close for 0-10 + _session.close(); + } + + // Validation + //Ensure that we wait for the QUE log message + waitAndFindMatches("QUE-1002"); + + List results = findMatches(QUEUE_PREFIX); + + // Only 1 Queue message should hav been logged + assertEquals("Result set size not as expected", 2, results.size()); + + String log = getLogMessage(results, 0); + + // Message Should be a QUE-1001 + validateMessageID("QUE-1001", log); + + String createdQueueName = AbstractTestLogSubject.getSlice("qu", fromSubject(log)); + + log = getLogMessage(results, 1); + // Message Should be a QUE-1002 + validateMessageID("QUE-1002", log); + + assertEquals("Log Message is incorrect ", "Deleted", getMessageString(fromMessage(log))); + + assertEquals("Queue Delete not for created queue:", createdQueueName, + AbstractTestLogSubject.getSlice("qu", fromSubject(log))); + + } + +} \ No newline at end of file diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/TransientQueueLoggingTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/TransientQueueLoggingTest.java new file mode 100644 index 0000000000..29f74c5818 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/TransientQueueLoggingTest.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.server.logging; + +public class TransientQueueLoggingTest extends DurableQueueLoggingTest +{ + public void setUp() throws Exception + { + super.setUp(); + _durable = false; + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java new file mode 100644 index 0000000000..25dd5fd2f8 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/logging/VirtualHostLoggingTest.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ + +package org.apache.qpid.server.logging; + +import junit.framework.AssertionFailedError; + + +import java.util.Arrays; +import java.util.List; + +/** + * Virtualhost Test Cases + * The virtualhost test suite validates that the follow log messages as specified in the Functional Specification. + *

+ * This suite of tests validate that the management console messages occur correctly and according to the following format: + *

+ * VHT-1001 : Created : + * VHT-1002 : Work directory : + * VHT-1003 : Closed + */ +public class VirtualHostLoggingTest extends AbstractTestLogging +{ + private static final String VHT_PREFIX = "VHT-"; + + /** + * Description: + * Testing can be performed using the default configuration. The goal is to validate that for each virtualhost defined in the configuration file a VHT-1001 Created message is provided. + * Input: + * The default configuration file + * Output: + *

+ * VHT-1001 : Created : + * Validation Steps: + *

+ * The VHT ID is correct + * A VHT-1001 is printed for each virtualhost defined in the configuration file. + * This must be the first message for the specified virtualhost. + * + * @throws Exception caused by broker startup + */ + public void testVirtualhostCreation() throws Exception + { + //Wait for the correct VHT message to arrive. + waitForMessage(VHT_PREFIX + "1001"); + + //Validate each vhost logs a creation + List results = findMatches(VHT_PREFIX + "1001"); + + try + { + List vhosts = Arrays.asList("test"); + + assertEquals("Each vhost did not create a store.", vhosts.size(), results.size()); + + for (int index = 0; index < results.size(); index++) + { + // Retrieve the vhostname from the log entry message 'Created : ' + String result = getLogMessage(results, index); + String vhostName = getMessageString(fromMessage(result)).split(" ")[2]; + + assertTrue("Virtualhost named in log not found in config file:" + vhostName + ":" + vhosts, vhosts.contains(vhostName)); + } + } + catch (AssertionFailedError afe) + { + dumpLogs(results, _monitor); + + throw afe; + } + } + + /** + * Description: + * Testing can be performed using the default configuration. During broker shutdown a VHT-1002 Closed message will be printed for each of the configured virtualhosts. For every virtualhost that was started a close must be logged. After the close message has been printed no further logging will be performed by this virtualhost. + * Input: + * The default configuration file + * Output: + *

+ * VHT-1002 : Closed + * Validation Steps: + *

+ * The VHT ID is correct + * This is the last VHT message for the given virtualhost. + * + * @throws Exception caused by broker startup + */ + public void testVirtualhostClosure() throws Exception + { + if (isJavaBroker() && isInternalBroker()) + { + stopBroker(); + + // Wait for the correct VHT message to arrive. + waitForMessage(VHT_PREFIX + "1002"); + + // Validate each vhost logs a closure + List results = findMatches(VHT_PREFIX + "1002"); + + try + { + assertEquals("Each vhost did not close their store.", 1, results.size()); + } + catch (AssertionFailedError afe) + { + dumpLogs(results, _monitor); + throw afe; + } + } + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/message/MessageProtocolConversionTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/message/MessageProtocolConversionTest.java new file mode 100644 index 0000000000..2a5f8b9b95 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/message/MessageProtocolConversionTest.java @@ -0,0 +1,322 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.message; + +import org.apache.qpid.AMQException; +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; + +public class MessageProtocolConversionTest extends QpidBrokerTestCase +{ + + private static final int TIMEOUT = 1500; + private Connection _connection_0_9_1; + private Connection _connection_0_10; + + private static final boolean BOOLEAN_TEST_VAL = true; + private static final byte BYTE_TEST_VAL = (byte) 4; + private static final byte[] BYTES_TEST_VAL = {5, 4, 3, 2, 1}; + private static final char CHAR_TEST_VAL = 'x'; + private static final double DOUBLE_TEST_VAL = Double.MAX_VALUE; + private static final float FLOAT_TEST_VAL = Float.MAX_VALUE; + private static final int INT_TEST_VAL = -73; + private static final long LONG_TEST_VAL = Long.MIN_VALUE / 2l; + private static final short SHORT_TEST_VAL = -586; + private static final String STRING_TEST_VAL = "This is a test text message"; + + @Override + public void setUp() throws Exception + { + super.setUp(); + setTestSystemProperty(ClientProperties.AMQP_VERSION, "0-10"); + _connection_0_10 = getConnection(); + setTestSystemProperty(ClientProperties.AMQP_VERSION, "0-9-1"); + _connection_0_9_1 = getConnection(); + } + + public void test0_9_1_to_0_10_conversion() throws JMSException, AMQException + { + doConversionTests(_connection_0_9_1, _connection_0_10); + } + + public void test_0_10_to_0_9_1_conversion() throws JMSException, AMQException + { + + doConversionTests(_connection_0_10, _connection_0_9_1); + } + + private void doConversionTests(Connection producerConn, Connection consumerConn) throws JMSException, AMQException + { + Session producerSession = producerConn.createSession(false, Session.AUTO_ACKNOWLEDGE); + Session consumerSession = consumerConn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Queue queue = getTestQueue(); + + MessageProducer producer = producerSession.createProducer(queue); + MessageConsumer consumer = consumerSession.createConsumer(queue); + + consumerConn.start(); + producerConn.start(); + + // Text Message + + Message m = producerSession.createTextMessage(STRING_TEST_VAL); + producer.send(m); + m = consumer.receive(TIMEOUT); + + assertNotNull("Expected text message did not arrive", m); + assertTrue("Received message not an instance of TextMessage (" + m.getClass().getName() + " instead)", m instanceof TextMessage); + assertEquals("Message text not as expected", STRING_TEST_VAL, ((TextMessage) m).getText()); + + // Map Message + + MapMessage mapMessage = producerSession.createMapMessage(); + mapMessage.setBoolean("boolean", BOOLEAN_TEST_VAL); + mapMessage.setByte("byte", BYTE_TEST_VAL); + mapMessage.setBytes("bytes", BYTES_TEST_VAL); + mapMessage.setChar("char", CHAR_TEST_VAL); + mapMessage.setDouble("double", DOUBLE_TEST_VAL); + mapMessage.setFloat("float", FLOAT_TEST_VAL); + mapMessage.setInt("int", INT_TEST_VAL); + mapMessage.setLong("long", LONG_TEST_VAL); + mapMessage.setShort("short", SHORT_TEST_VAL); + mapMessage.setString("string", STRING_TEST_VAL); + + producer.send(mapMessage); + + m = consumer.receive(TIMEOUT); + + assertNotNull("Expected map message message did not arrive", m); + assertTrue("Received message not an instance of MapMessage (" + m.getClass().getName() + " instead)", m instanceof MapMessage); + MapMessage receivedMapMessage = (MapMessage) m; + assertEquals("Map message boolean value not as expected", BOOLEAN_TEST_VAL, receivedMapMessage.getBoolean("boolean")); + assertEquals("Map message byte value not as expected", BYTE_TEST_VAL, receivedMapMessage.getByte("byte")); + assertTrue("Map message bytes value not as expected", Arrays.equals(BYTES_TEST_VAL, receivedMapMessage.getBytes("bytes"))); + assertEquals("Map message char value not as expected", CHAR_TEST_VAL, receivedMapMessage.getChar("char")); + assertEquals("Map message double value not as expected", DOUBLE_TEST_VAL, receivedMapMessage.getDouble("double")); + assertEquals("Map message float value not as expected", FLOAT_TEST_VAL, receivedMapMessage.getFloat("float")); + assertEquals("Map message int value not as expected", INT_TEST_VAL, receivedMapMessage.getInt("int")); + assertEquals("Map message long value not as expected", LONG_TEST_VAL, receivedMapMessage.getLong("long")); + assertEquals("Map message short value not as expected", SHORT_TEST_VAL, receivedMapMessage.getShort("short")); + assertEquals("Map message string value not as expected", STRING_TEST_VAL, receivedMapMessage.getString("string")); + ArrayList expectedNames = Collections.list(mapMessage.getMapNames()); + Collections.sort(expectedNames); + ArrayList actualNames = Collections.list(receivedMapMessage.getMapNames()); + Collections.sort(actualNames); + assertEquals("Map message keys not as expected", expectedNames, actualNames); + + // Stream Message + + StreamMessage streamMessage = producerSession.createStreamMessage(); + streamMessage.writeString(STRING_TEST_VAL); + streamMessage.writeShort(SHORT_TEST_VAL); + streamMessage.writeLong(LONG_TEST_VAL); + streamMessage.writeInt(INT_TEST_VAL); + streamMessage.writeFloat(FLOAT_TEST_VAL); + streamMessage.writeDouble(DOUBLE_TEST_VAL); + streamMessage.writeChar(CHAR_TEST_VAL); + streamMessage.writeBytes(BYTES_TEST_VAL); + streamMessage.writeByte(BYTE_TEST_VAL); + streamMessage.writeBoolean(BOOLEAN_TEST_VAL); + + producer.send(streamMessage); + + m = consumer.receive(TIMEOUT); + + assertNotNull("Expected stream message message did not arrive", m); + assertTrue("Received message not an instance of StreamMessage (" + m.getClass().getName() + " instead)", m instanceof StreamMessage); + StreamMessage receivedStreamMessage = (StreamMessage) m; + + assertEquals("Stream message read string not as expected", STRING_TEST_VAL, receivedStreamMessage.readString()); + assertEquals("Stream message read short not as expected", SHORT_TEST_VAL, receivedStreamMessage.readShort()); + assertEquals("Stream message read long not as expected", LONG_TEST_VAL, receivedStreamMessage.readLong()); + assertEquals("Stream message read int not as expected", INT_TEST_VAL, receivedStreamMessage.readInt()); + assertEquals("Stream message read float not as expected", FLOAT_TEST_VAL, receivedStreamMessage.readFloat()); + assertEquals("Stream message read double not as expected", DOUBLE_TEST_VAL, receivedStreamMessage.readDouble()); + assertEquals("Stream message read char not as expected", CHAR_TEST_VAL, receivedStreamMessage.readChar()); + byte[] bytesVal = new byte[BYTES_TEST_VAL.length]; + receivedStreamMessage.readBytes(bytesVal); + assertTrue("Stream message read bytes not as expected", Arrays.equals(BYTES_TEST_VAL, bytesVal)); + assertEquals("Stream message read byte not as expected", BYTE_TEST_VAL, receivedStreamMessage.readByte()); + assertEquals("Stream message read boolean not as expected", BOOLEAN_TEST_VAL, receivedStreamMessage.readBoolean()); + + try + { + receivedStreamMessage.readByte(); + fail("Unexpected remaining bytes in stream message"); + } + catch(MessageEOFException e) + { + // pass + } + + // Object Message + + ObjectMessage objectMessage = producerSession.createObjectMessage(); + objectMessage.setObject(STRING_TEST_VAL); + + producer.send(objectMessage); + + m = consumer.receive(TIMEOUT); + + assertNotNull("Expected object message message did not arrive", m); + assertTrue("Received message not an instance of ObjectMessage (" + m.getClass().getName() + " instead)", m instanceof ObjectMessage); + ObjectMessage receivedObjectMessage = (ObjectMessage) m; + assertEquals("Object message value not as expected", STRING_TEST_VAL, receivedObjectMessage.getObject()); + + + // Bytes Message + + BytesMessage bytesMessage = producerSession.createBytesMessage(); + bytesMessage.writeBytes(BYTES_TEST_VAL); + + producer.send(bytesMessage); + + m = consumer.receive(TIMEOUT); + + assertNotNull("Expected bytes message message did not arrive", m); + assertTrue("Received message not an instance of BytesMessage (" + m.getClass().getName() + " instead)", m instanceof BytesMessage); + BytesMessage receivedBytesMessage = (BytesMessage) m; + bytesVal = new byte[BYTES_TEST_VAL.length]; + receivedBytesMessage.readBytes(bytesVal); + assertTrue("Bytes message read bytes not as expected", Arrays.equals(BYTES_TEST_VAL, bytesVal)); + + try + { + receivedBytesMessage.readByte(); + fail("Unexpected remaining bytes in stream message"); + } + catch(MessageEOFException e) + { + // pass + } + + // Headers / properties tests + + Message msg = producerSession.createMessage(); + msg.setJMSCorrelationID("testCorrelationId"); + msg.setJMSDeliveryMode(DeliveryMode.NON_PERSISTENT); + msg.setJMSPriority(7); + msg.setJMSType("testType"); + + msg.setBooleanProperty("boolean", BOOLEAN_TEST_VAL); + msg.setByteProperty("byte", BYTE_TEST_VAL); + msg.setDoubleProperty("double", DOUBLE_TEST_VAL); + msg.setFloatProperty("float", FLOAT_TEST_VAL); + msg.setIntProperty("int", INT_TEST_VAL); + msg.setLongProperty("long", LONG_TEST_VAL); + msg.setShortProperty("short", SHORT_TEST_VAL); + msg.setStringProperty("string", STRING_TEST_VAL); + + producer.send(msg); + + m = consumer.receive(TIMEOUT); + assertNotNull("Expected message did not arrive", m); + assertEquals("JMSMessageID differs", msg.getJMSMessageID(), m.getJMSMessageID()); + assertEquals("JMSCorrelationID differs",msg.getJMSCorrelationID(),m.getJMSCorrelationID()); + assertEquals("JMSDeliveryMode differs",msg.getJMSDeliveryMode(),m.getJMSDeliveryMode()); + assertEquals("JMSPriority differs",msg.getJMSPriority(),m.getJMSPriority()); + assertEquals("JMSType differs",msg.getJMSType(),m.getJMSType()); + + assertEquals("Message boolean property not as expected", BOOLEAN_TEST_VAL, m.getBooleanProperty("boolean")); + assertEquals("Message byte property not as expected", BYTE_TEST_VAL, m.getByteProperty("byte")); + assertEquals("Message double property not as expected", DOUBLE_TEST_VAL, m.getDoubleProperty("double")); + assertEquals("Message float property not as expected", FLOAT_TEST_VAL, m.getFloatProperty("float")); + assertEquals("Message int property not as expected", INT_TEST_VAL, m.getIntProperty("int")); + assertEquals("Message long property not as expected", LONG_TEST_VAL, m.getLongProperty("long")); + assertEquals("Message short property not as expected", SHORT_TEST_VAL, m.getShortProperty("short")); + assertEquals("Message string property not as expected", STRING_TEST_VAL, m.getStringProperty("string")); + + ArrayList sentPropNames = Collections.list(msg.getPropertyNames()); + Collections.sort(sentPropNames); + ArrayList receivedPropNames = Collections.list(m.getPropertyNames()); + Collections.sort(receivedPropNames); + + // Shouldn't really need to do this, the client should be hiding these from us + removeSyntheticProperties(sentPropNames); + removeSyntheticProperties(receivedPropNames); + + assertEquals("Property names were not as expected", sentPropNames, receivedPropNames); + + // Test Reply To Queue + + Destination replyToDestination = producerSession.createTemporaryQueue(); + MessageConsumer replyToConsumer = producerSession.createConsumer(replyToDestination); + msg = producerSession.createMessage(); + msg.setJMSReplyTo(replyToDestination); + producer.send(msg); + + m = consumer.receive(TIMEOUT); + assertNotNull("Expected message did not arrive", m); + assertNotNull("Message does not have ReplyTo set", m.getJMSReplyTo()); + + MessageProducer responseProducer = consumerSession.createProducer(m.getJMSReplyTo()); + responseProducer.send(consumerSession.createMessage()); + + assertNotNull("Expected response message did not arrive", replyToConsumer.receive(TIMEOUT)); + + // Test Reply To Topic + + replyToDestination = producerSession.createTemporaryTopic(); + replyToConsumer = producerSession.createConsumer(replyToDestination); + msg = producerSession.createMessage(); + msg.setJMSReplyTo(replyToDestination); + producer.send(msg); + + m = consumer.receive(TIMEOUT); + assertNotNull("Expected message did not arrive", m); + assertNotNull("Message does not have ReplyTo set", m.getJMSReplyTo()); + + responseProducer = consumerSession.createProducer(m.getJMSReplyTo()); + responseProducer.send(consumerSession.createMessage()); + + assertNotNull("Expected response message did not arrive", replyToConsumer.receive(TIMEOUT)); + + + } + + private void removeSyntheticProperties(ArrayList propNames) + { + Iterator nameIter = propNames.iterator(); + while(nameIter.hasNext()) + { + String propName = nameIter.next(); + if(propName.startsWith("x-jms") || propName.startsWith("JMS_QPID")) + { + nameIter.remove(); + } + } + } + + @Override + public void tearDown() throws Exception + { + _connection_0_9_1.close(); + _connection_0_10.close(); + super.tearDown(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/persistent/NoLocalAfterRecoveryTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/persistent/NoLocalAfterRecoveryTest.java new file mode 100644 index 0000000000..82b421a531 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/persistent/NoLocalAfterRecoveryTest.java @@ -0,0 +1,185 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.persistent; + +import java.util.ArrayList; +import java.util.List; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicSubscriber; + +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +/** + * Verifies that after recovery, a new Connection with no-local in use is + * able to receive messages sent prior to the broker restart. + */ +public class NoLocalAfterRecoveryTest extends QpidBrokerTestCase +{ + protected final String MY_TOPIC_SUBSCRIPTION_NAME = getTestQueueName(); + protected static final int SEND_COUNT = 10; + + public void testNoLocalNotQueued() throws Exception + { + if(!isBrokerStorePersistent()) + { + fail("This test requires a broker with a persistent store"); + } + + Connection connection = getConnection(); + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Topic topic = session.createTopic(MY_TOPIC_SUBSCRIPTION_NAME); + + TopicSubscriber noLocalSubscriber = session. + createDurableSubscriber(topic, MY_TOPIC_SUBSCRIPTION_NAME + "-NoLocal", + null, true); + + TopicSubscriber normalSubscriber = session. + createDurableSubscriber(topic, MY_TOPIC_SUBSCRIPTION_NAME + "-Normal", + null, false); + + sendMessage(session, topic, SEND_COUNT); + + // Check messages can be received as expected. + connection.start(); + + //As the no-local subscriber was on the same connection the messages were + //published on, tit will receive no messages as they will be discarded on the broker + List received = receiveMessage(noLocalSubscriber, SEND_COUNT); + assertEquals("No Local Subscriber Received messages", 0, received.size()); + + received = receiveMessage(normalSubscriber, SEND_COUNT); + assertEquals("Normal Subscriber Received no messages", + SEND_COUNT, received.size()); + session.commit(); + + normalSubscriber.close(); + connection.close(); + + //Ensure the no-local subscribers messages were discarded by restarting the broker + //and reconnecting to the subscription to ensure they were not recovered. + restartBroker(); + + Connection connection2 = getConnection(); + connection2.start(); + + Session session2 = connection2.createSession(true, Session.SESSION_TRANSACTED); + Topic topic2 = session2.createTopic(MY_TOPIC_SUBSCRIPTION_NAME); + + TopicSubscriber noLocalSubscriber2 = session2. + createDurableSubscriber(topic2, MY_TOPIC_SUBSCRIPTION_NAME + "-NoLocal", + null, true); + + // The NO-local subscriber should not get any messages + received = receiveMessage(noLocalSubscriber2, SEND_COUNT); + session2.commit(); + assertEquals("No Local Subscriber Received messages", 0, received.size()); + + noLocalSubscriber2.close(); + + + } + + + public void testNonNoLocalQueued() throws Exception + { + if(!isBrokerStorePersistent()) + { + fail("This test requires a broker with a persistent store"); + } + + Connection connection = getConnection(); + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Topic topic = session.createTopic(MY_TOPIC_SUBSCRIPTION_NAME); + + TopicSubscriber noLocalSubscriber = + session.createDurableSubscriber(topic, MY_TOPIC_SUBSCRIPTION_NAME + "-NoLocal", null, true); + + + sendMessage(session, topic, SEND_COUNT); + + // Check messages can be received as expected. + connection.start(); + + List received = receiveMessage(noLocalSubscriber, SEND_COUNT); + assertEquals("No Local Subscriber Received messages", 0, received.size()); + + + + session.commit(); + + Connection connection3 = getConnection(); + Session session3 = connection3.createSession(true, Session.SESSION_TRANSACTED); + sendMessage(session3, topic, SEND_COUNT); + + + connection.close(); + + //We didn't receive the messages on the durable queue for the no-local subscriber + //so they are still on the broker. Restart the broker, prompting their recovery. + restartBroker(); + + Connection connection2 = getConnection(); + connection2.start(); + + Session session2 = connection2.createSession(true, Session.SESSION_TRANSACTED); + Topic topic2 = session2.createTopic(MY_TOPIC_SUBSCRIPTION_NAME); + + TopicSubscriber noLocalSubscriber2 = + session2.createDurableSubscriber(topic2, MY_TOPIC_SUBSCRIPTION_NAME + "-NoLocal",null, true); + + // The NO-local subscriber should receive messages sent from connection3 + received = receiveMessage(noLocalSubscriber2, SEND_COUNT); + session2.commit(); + assertEquals("No Local Subscriber did not receive expected messages", SEND_COUNT, received.size()); + + noLocalSubscriber2.close(); + + + } + + protected List receiveMessage(MessageConsumer messageConsumer, + int count) throws JMSException + { + + List receivedMessages = new ArrayList(count); + for (int i = 0; i < count; i++) + { + Message received = messageConsumer.receive(1000); + + if (received != null) + { + receivedMessages.add(received); + } + else + { + break; + } + } + + return receivedMessages; + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactoryTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactoryTest.java new file mode 100644 index 0000000000..c771e84f52 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngineFactoryTest.java @@ -0,0 +1,308 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.protocol; + +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.security.Principal; +import java.util.EnumSet; +import java.util.Iterator; +import java.util.Set; + +import org.apache.qpid.protocol.ServerProtocolEngine; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.util.BrokerTestHelper; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; +import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpid.transport.Sender; +import org.apache.qpid.transport.network.NetworkConnection; + +public class MultiVersionProtocolEngineFactoryTest extends QpidTestCase +{ + private VirtualHostImpl _virtualHost; + private Broker _broker; + + @Override + protected void setUp() throws Exception + { + super.setUp(); + BrokerTestHelper.setUp(); + _broker = BrokerTestHelper.createBrokerMock(); + when(_broker.getAttribute(Broker.DEFAULT_VIRTUAL_HOST)).thenReturn("default"); + when(_broker.getDefaultVirtualHost()).thenReturn("default"); + when(_broker.getContextValue(eq(Long.class), eq(Broker.BROKER_FRAME_SIZE))).thenReturn(0xffffl); + + } + + @Override + protected void tearDown() throws Exception + { + BrokerTestHelper.tearDown(); + super.tearDown(); + } + + private static final byte[] AMQP_0_8_HEADER = + new byte[] { (byte) 'A', + (byte) 'M', + (byte) 'Q', + (byte) 'P', + (byte) 1, + (byte) 1, + (byte) 8, + (byte) 0 + }; + + private static final byte[] AMQP_0_9_HEADER = + new byte[] { (byte) 'A', + (byte) 'M', + (byte) 'Q', + (byte) 'P', + (byte) 1, + (byte) 1, + (byte) 0, + (byte) 9 + }; + + private static final byte[] AMQP_0_9_1_HEADER = + new byte[] { (byte) 'A', + (byte) 'M', + (byte) 'Q', + (byte) 'P', + (byte) 0, + (byte) 0, + (byte) 9, + (byte) 1 + }; + + + private static final byte[] AMQP_0_10_HEADER = + new byte[] { (byte) 'A', + (byte) 'M', + (byte) 'Q', + (byte) 'P', + (byte) 1, + (byte) 1, + (byte) 0, + (byte) 10 + }; + + + private static final byte[] AMQP_1_0_0_HEADER = + new byte[] { + (byte)'A', + (byte)'M', + (byte)'Q', + (byte)'P', + (byte) 0, + (byte) 1, + (byte) 0, + (byte) 0 + }; + + + private byte[] getAmqpHeader(final Protocol version) + { + switch(version) + { + case AMQP_0_8: + return AMQP_0_8_HEADER; + case AMQP_0_9: + return AMQP_0_9_HEADER; + case AMQP_0_9_1: + return AMQP_0_9_1_HEADER; + case AMQP_0_10: + return AMQP_0_10_HEADER; + case AMQP_1_0: + return AMQP_1_0_0_HEADER; + default: + fail("unknown AMQP version, appropriate header must be added for new protocol version"); + return null; + } + } + + /** + * Test to verify that connections established using a MultiVersionProtocolEngine are assigned + * IDs from a common sequence, independent of the protocol version under use. + */ + public void testDifferentProtocolVersionsShareCommonIDNumberingSequence() + { + Set protocols = getAllAMQPProtocols(); + + Port port = mock(Port.class); + when(port.getContextValue(eq(Long.class),eq(Port.CONNECTION_MAXIMUM_AUTHENTICATION_DELAY))).thenReturn(10000l); + MultiVersionProtocolEngineFactory factory = + new MultiVersionProtocolEngineFactory(_broker, null, false, false, protocols, null, port, + org.apache.qpid.server.model.Transport.TCP); + + //create a dummy to retrieve the 'current' ID number + long previousId = factory.newProtocolEngine().getConnectionId(); + + //create a protocol engine and send the AMQP header for all supported AMQP verisons, + //ensuring the ID assigned increases as expected + for(Protocol protocol : protocols) + { + long expectedID = previousId + 1; + byte[] header = getAmqpHeader(protocol); + assertNotNull("protocol header should not be null", header); + + ServerProtocolEngine engine = factory.newProtocolEngine(); + TestNetworkConnection conn = new TestNetworkConnection(); + engine.setNetworkConnection(conn, conn.getSender()); + assertEquals("ID did not increment as expected", expectedID, engine.getConnectionId()); + + //actually feed in the AMQP header for this protocol version, and ensure the ID remains consistent + engine.received(ByteBuffer.wrap(header)); + assertEquals("ID was not as expected following receipt of the AMQP version header", expectedID, engine.getConnectionId()); + + previousId = expectedID; + engine.closed(); + } + } + + protected Set getAllAMQPProtocols() + { + Set protocols = EnumSet.allOf(Protocol.class); + Iterator protoIter = protocols.iterator(); + while(protoIter.hasNext()) + { + Protocol protocol = protoIter.next(); + if(protocol.getProtocolType() != Protocol.ProtocolType.AMQP) + { + protoIter.remove(); + } + } + return protocols; + } + + /** + * Test to verify that when requesting a ProtocolEngineFactory to produce engines having a default reply to unsupported + * version initiations, there is enforcement that the default reply is itself a supported protocol version. + */ + public void testUnsupportedDefaultReplyCausesIllegalArgumentException() + { + Set versions = getAllAMQPProtocols(); + versions.remove(Protocol.AMQP_0_9); + + try + { + new MultiVersionProtocolEngineFactory(_broker, null, false, false, versions, Protocol.AMQP_0_9, null, + org.apache.qpid.server.model.Transport.TCP); + fail("should not have been allowed to create the factory"); + } + catch(IllegalArgumentException iae) + { + //expected + } + } + + private static class TestNetworkConnection implements NetworkConnection + { + private String _remoteHost = "127.0.0.1"; + private String _localHost = "127.0.0.1"; + private int _port = 1; + private final Sender _sender; + + public TestNetworkConnection() + { + _sender = new Sender() + { + public void setIdleTimeout(int i) + { + } + + public void send(ByteBuffer msg) + { + } + + public void flush() + { + } + + public void close() + { + } + }; + } + + @Override + public SocketAddress getLocalAddress() + { + return new InetSocketAddress(_localHost, _port); + } + + @Override + public SocketAddress getRemoteAddress() + { + return new InetSocketAddress(_remoteHost, _port); + } + + @Override + public void setMaxReadIdle(int idleTime) + { + } + + @Override + public Principal getPeerPrincipal() + { + return null; + } + + @Override + public int getMaxReadIdle() + { + return 0; + } + + @Override + public int getMaxWriteIdle() + { + return 0; + } + + @Override + public void setMaxWriteIdle(int idleTime) + { + } + + @Override + public void close() + { + } + + @Override + public Sender getSender() + { + return _sender; + } + + @Override + public void start() + { + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/DeepQueueConsumeWithSelector.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/DeepQueueConsumeWithSelector.java new file mode 100644 index 0000000000..21e3bfa055 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/DeepQueueConsumeWithSelector.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.server.queue; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Queue; +import javax.jms.Session; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * Test DeapQueueConsumerWithSelector + * Summary: + * Prior to M4 the broker had a different queue model which pre-processed the + * messages on the queue for any connecting subscription that had a selector. + * + * If the queue had a lot of data then this may take a long time to process + * to such an extent that the subscription creation may time out. During this + * pre-process phase the virtualhost would be come unresposive. + * + * Our solution was to allow the timeout to be adjusted QPID-1119, which allowed + * the subscription to connect but did not address the unresponsiveness. + * + * The new queue model introduced in M4 resolved this. + * + * This test is to validate that the new queueing model does indeed remove the + * long pre-processing phase and allow immediate subscription so that there is + * no unresponsive period. + * + * Test Strategy: + * + * Add 100k messages to the queue with a numberic header property that will + * allow later subscribers to use as in a selector. + * + * Connect the subscriber and time how long it takes to connect. + * + * Finally consume all the messages from the queue to clean up. + */ +public class DeepQueueConsumeWithSelector extends QpidBrokerTestCase implements MessageListener +{ + + private static final int MESSAGE_COUNT = 10000; + private static final int BATCH_SIZE = MESSAGE_COUNT / 10; + + private CountDownLatch _receviedLatch = new CountDownLatch(MESSAGE_COUNT); + + protected long SYNC_WRITE_TIMEOUT = 120000L; + + + public void setUp() throws Exception + { + //Set the syncWrite timeout to be just larger than the delay on the commitTran. + setSystemProperty("amqj.default_syncwrite_timeout", String.valueOf(SYNC_WRITE_TIMEOUT)); + + super.setUp(); + } + + public void test() throws Exception + { + // Create Connection + Connection connection = getConnection(); + Session session = ((AMQConnection)connection).createSession(true, Session.SESSION_TRANSACTED, 100000); + + Queue queue = (Queue) getInitialContext().lookup("queue"); + + // Validate that the destination exists + session.createConsumer(queue).close(); + + // Send Messages + sendMessage(session, queue, MESSAGE_COUNT, BATCH_SIZE); + + session.close(); + + session = ((AMQConnection) connection).createSession(false, Session.AUTO_ACKNOWLEDGE);//, 100000); + + + // Setup Selector to perform a few calculations which will slow it down + String selector = "((\"" + INDEX + "\" % 1) = 0) AND ('" + INDEX + "' IS NOT NULL) AND ('" + INDEX + "' <> -1)"; + + // Setup timing + long start = System.nanoTime(); + + System.err.println("Create Consumer"); + // Connect Consumer + MessageConsumer consumer = session.createConsumer(queue, selector); + consumer.setMessageListener(this); + + // Validate timing details + long end = System.nanoTime(); + + System.err.println("Subscription time took:" + (end - start)); + + // Consume Messages + connection.start(); + + + + assertTrue("Messages took to long to be received :"+_receviedLatch.getCount(), + _receviedLatch.await(SYNC_WRITE_TIMEOUT, TimeUnit.MILLISECONDS )); + + } + + @Override + public Message createNextMessage(Session session, int msgCount) throws JMSException + { + Message message = super.createNextMessage(session,msgCount); + + if ((msgCount % BATCH_SIZE) == 0 ) + { + System.err.println("Sent:"+msgCount); + } + + return message; + } + + public void onMessage(Message message) + { + _receviedLatch.countDown(); + int msgCount = 0; + try + { + msgCount = message.getIntProperty(INDEX); + } + catch (JMSException e) + { + //ignore + } + if ((msgCount % BATCH_SIZE) == 0 ) + { + System.err.println("Received:"+msgCount); + } + + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/LastValueQueueTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/LastValueQueueTest.java new file mode 100644 index 0000000000..dc30c02951 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/LastValueQueueTest.java @@ -0,0 +1,574 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.url.AMQBindingURL; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class LastValueQueueTest extends QpidBrokerTestCase +{ + private static final Logger LOGGER = Logger.getLogger(LastValueQueueTest.class); + + private static final String MESSAGE_SEQUENCE_NUMBER_PROPERTY = "msg"; + private static final String KEY_PROPERTY = "key"; + + private static final int MSG_COUNT = 400; + + private String _queueName; + private Queue _queue; + private Connection _producerConnection; + private MessageProducer _producer; + private Session _producerSession; + private Connection _consumerConnection; + private Session _consumerSession; + private MessageConsumer _consumer; + + protected void setUp() throws Exception + { + super.setUp(); + + _queueName = getTestQueueName(); + _producerConnection = getConnection(); + _producerSession = _producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + public void testConflation() throws Exception + { + _consumerConnection = getConnection(); + _consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + createConflationQueue(_producerSession); + _producer = _producerSession.createProducer(_queue); + + for (int msg = 0; msg < MSG_COUNT; msg++) + { + _producer.send(nextMessage(msg, _producerSession)); + } + + _producer.close(); + _producerSession.close(); + _producerConnection.close(); + + _consumer = _consumerSession.createConsumer(_queue); + _consumerConnection.start(); + Message received; + + List messages = new ArrayList(); + while((received = _consumer.receive(1000))!=null) + { + messages.add(received); + } + + assertEquals("Unexpected number of messages received",10,messages.size()); + + for(int i = 0 ; i < 10; i++) + { + Message msg = messages.get(i); + assertEquals("Unexpected message number received", MSG_COUNT - 10 + i, msg.getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY)); + } + } + + public void testConflationWithRelease() throws Exception + { + _consumerConnection = getConnection(); + _consumerSession = _consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + + createConflationQueue(_producerSession); + _producer = _producerSession.createProducer(_queue); + + for (int msg = 0; msg < MSG_COUNT/2; msg++) + { + _producer.send(nextMessage(msg, _producerSession)); + + } + + // HACK to do something synchronous + ((AMQSession)_producerSession).sync(); + + _consumer = _consumerSession.createConsumer(_queue); + _consumerConnection.start(); + Message received; + List messages = new ArrayList(); + while((received = _consumer.receive(1000))!=null) + { + messages.add(received); + } + + assertEquals("Unexpected number of messages received",10,messages.size()); + + for(int i = 0 ; i < 10; i++) + { + Message msg = messages.get(i); + assertEquals("Unexpected message number received", MSG_COUNT/2 - 10 + i, msg.getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY)); + } + + _consumerSession.close(); + _consumerConnection.close(); + + + _consumerConnection = getConnection(); + _consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + + for (int msg = MSG_COUNT/2; msg < MSG_COUNT; msg++) + { + _producer.send(nextMessage(msg, _producerSession)); + } + + + // HACK to do something synchronous + ((AMQSession)_producerSession).sync(); + + _consumer = _consumerSession.createConsumer(_queue); + _consumerConnection.start(); + + messages = new ArrayList(); + while((received = _consumer.receive(1000))!=null) + { + messages.add(received); + } + + assertEquals("Unexpected number of messages received",10,messages.size()); + + for(int i = 0 ; i < 10; i++) + { + Message msg = messages.get(i); + assertEquals("Unexpected message number received", MSG_COUNT - 10 + i, msg.getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY)); + } + + } + + + public void testConflationWithReleaseAfterNewPublish() throws Exception + { + _consumerConnection = getConnection(); + _consumerSession = _consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + + createConflationQueue(_producerSession); + _producer = _producerSession.createProducer(_queue); + + for (int msg = 0; msg < MSG_COUNT/2; msg++) + { + _producer.send(nextMessage(msg, _producerSession)); + } + + // HACK to do something synchronous + ((AMQSession)_producerSession).sync(); + + _consumer = _consumerSession.createConsumer(_queue); + _consumerConnection.start(); + Message received; + List messages = new ArrayList(); + while((received = _consumer.receive(1000))!=null) + { + messages.add(received); + } + + assertEquals("Unexpected number of messages received",10,messages.size()); + + for(int i = 0 ; i < 10; i++) + { + Message msg = messages.get(i); + assertEquals("Unexpected message number received", MSG_COUNT/2 - 10 + i, msg.getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY)); + } + + _consumer.close(); + + for (int msg = MSG_COUNT/2; msg < MSG_COUNT; msg++) + { + _producer.send(nextMessage(msg, _producerSession)); + } + + // HACK to do something synchronous + ((AMQSession)_producerSession).sync(); + + + // this causes the "old" messages to be released + _consumerSession.close(); + _consumerConnection.close(); + + + _consumerConnection = getConnection(); + _consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + + + _consumer = _consumerSession.createConsumer(_queue); + _consumerConnection.start(); + + messages = new ArrayList(); + while((received = _consumer.receive(1000))!=null) + { + messages.add(received); + } + + assertEquals("Unexpected number of messages received",10,messages.size()); + + for(int i = 0 ; i < 10; i++) + { + Message msg = messages.get(i); + assertEquals("Unexpected message number received", MSG_COUNT - 10 + i, msg.getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY)); + } + + } + + public void testConflatedQueueDepth() throws Exception + { + _consumerConnection = getConnection(); + _consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + createConflationQueue(_producerSession); + _producer = _producerSession.createProducer(_queue); + + for (int msg = 0; msg < MSG_COUNT; msg++) + { + _producer.send(nextMessage(msg, _producerSession)); + } + + final long queueDepth = ((AMQSession)_producerSession).getQueueDepth((AMQDestination)_queue, true); + + assertEquals(10, queueDepth); + } + + public void testConflationBrowser() throws Exception + { + _consumerConnection = getConnection(); + _consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + + createConflationQueue(_producerSession); + _producer = _producerSession.createProducer(_queue); + + for (int msg = 0; msg < MSG_COUNT; msg++) + { + _producer.send(nextMessage(msg, _producerSession)); + + } + + ((AMQSession)_producerSession).sync(); + + AMQBindingURL url = new AMQBindingURL("direct://amq.direct//"+_queueName+"?browse='true'&durable='true'"); + AMQQueue browseQueue = new AMQQueue(url); + + _consumer = _consumerSession.createConsumer(browseQueue); + _consumerConnection.start(); + Message received; + List messages = new ArrayList(); + while((received = _consumer.receive(1000))!=null) + { + messages.add(received); + } + + assertEquals("Unexpected number of messages received",10,messages.size()); + + for(int i = 0 ; i < 10; i++) + { + Message msg = messages.get(i); + assertEquals("Unexpected message number received", MSG_COUNT - 10 + i, msg.getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY)); + } + + messages.clear(); + + _producer.send(nextMessage(MSG_COUNT, _producerSession)); + + ((AMQSession)_producerSession).sync(); + + while((received = _consumer.receive(1000))!=null) + { + messages.add(received); + } + assertEquals("Unexpected number of messages received",1,messages.size()); + assertEquals("Unexpected message number received", MSG_COUNT, messages.get(0).getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY)); + + + _producer.close(); + _producerSession.close(); + _producerConnection.close(); + } + + public void testConflation2Browsers() throws Exception + { + _consumerConnection = getConnection(); + _consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + + createConflationQueue(_producerSession); + _producer = _producerSession.createProducer(_queue); + + for (int msg = 0; msg < MSG_COUNT; msg++) + { + _producer.send(nextMessage(msg, _producerSession)); + } + + ((AMQSession)_producerSession).sync(); + + AMQBindingURL url = new AMQBindingURL("direct://amq.direct//"+_queueName+"?browse='true'&durable='true'"); + AMQQueue browseQueue = new AMQQueue(url); + + _consumer = _consumerSession.createConsumer(browseQueue); + MessageConsumer consumer2 = _consumerSession.createConsumer(browseQueue); + _consumerConnection.start(); + List messages = new ArrayList(); + List messages2 = new ArrayList(); + Message received = _consumer.receive(1000); + Message received2 = consumer2.receive(1000); + + while(received!=null || received2!=null) + { + if(received != null) + { + messages.add(received); + } + if(received2 != null) + { + messages2.add(received2); + } + + + received = _consumer.receive(1000); + received2 = consumer2.receive(1000); + + } + + assertEquals("Unexpected number of messages received on first browser",10,messages.size()); + assertEquals("Unexpected number of messages received on second browser",10,messages2.size()); + + for(int i = 0 ; i < 10; i++) + { + Message msg = messages.get(i); + assertEquals("Unexpected message number received on first browser", MSG_COUNT - 10 + i, msg.getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY)); + msg = messages2.get(i); + assertEquals("Unexpected message number received on second browser", MSG_COUNT - 10 + i, msg.getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY)); + } + + + _producer.close(); + _producerSession.close(); + _producerConnection.close(); + } + + public void testParallelProductionAndConsumption() throws Exception + { + createConflationQueue(_producerSession); + + // Start producing threads that send messages + BackgroundMessageProducer messageProducer1 = new BackgroundMessageProducer("Message sender1"); + messageProducer1.startSendingMessages(); + BackgroundMessageProducer messageProducer2 = new BackgroundMessageProducer("Message sender2"); + messageProducer2.startSendingMessages(); + + Map lastReceivedMessages = receiveMessages(messageProducer1); + + messageProducer1.join(); + messageProducer2.join(); + + final Map lastSentMessages1 = messageProducer1.getMessageSequenceNumbersByKey(); + assertEquals("Unexpected number of last sent messages sent by producer1", 2, lastSentMessages1.size()); + final Map lastSentMessages2 = messageProducer2.getMessageSequenceNumbersByKey(); + assertEquals(lastSentMessages1, lastSentMessages2); + + assertEquals("The last message sent for each key should match the last message received for that key", + lastSentMessages1, lastReceivedMessages); + + assertNull("Unexpected exception from background producer thread", messageProducer1.getException()); + } + + private Map receiveMessages(BackgroundMessageProducer producer) throws Exception + { + producer.waitUntilQuarterOfMessagesSentToEncourageConflation(); + + _consumerConnection = getConnection(); + int smallPrefetchToEncourageConflation = 1; + _consumerSession = ((AMQConnection)_consumerConnection).createSession(false, Session.AUTO_ACKNOWLEDGE, smallPrefetchToEncourageConflation); + + LOGGER.info("Starting to receive"); + + _consumer = _consumerSession.createConsumer(_queue); + _consumerConnection.start(); + + Map messageSequenceNumbersByKey = new HashMap(); + + Message message; + int numberOfShutdownsReceived = 0; + int numberOfMessagesReceived = 0; + while(numberOfShutdownsReceived < 2) + { + message = _consumer.receive(10000); + assertNotNull(message); + + if (message.propertyExists(BackgroundMessageProducer.SHUTDOWN)) + { + numberOfShutdownsReceived++; + } + else + { + numberOfMessagesReceived++; + putMessageInMap(message, messageSequenceNumbersByKey); + } + } + + LOGGER.info("Finished receiving. Received " + numberOfMessagesReceived + " message(s) in total"); + + return messageSequenceNumbersByKey; + } + + private void putMessageInMap(Message message, Map messageSequenceNumbersByKey) throws JMSException + { + String keyValue = message.getStringProperty(KEY_PROPERTY); + Integer messageSequenceNumber = message.getIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY); + messageSequenceNumbersByKey.put(keyValue, messageSequenceNumber); + } + + private class BackgroundMessageProducer + { + static final String SHUTDOWN = "SHUTDOWN"; + + private final String _threadName; + + private volatile Exception _exception; + + private Thread _thread; + private Map _messageSequenceNumbersByKey = new HashMap(); + private CountDownLatch _quarterOfMessagesSentLatch = new CountDownLatch(MSG_COUNT/4); + + public BackgroundMessageProducer(String threadName) + { + _threadName = threadName; + } + + public void waitUntilQuarterOfMessagesSentToEncourageConflation() throws InterruptedException + { + final long latchTimeout = 60000; + boolean success = _quarterOfMessagesSentLatch.await(latchTimeout, TimeUnit.MILLISECONDS); + assertTrue("Failed to be notified that 1/4 of the messages have been sent within " + latchTimeout + " ms.", success); + LOGGER.info("Quarter of messages sent"); + } + + public Exception getException() + { + return _exception; + } + + public Map getMessageSequenceNumbersByKey() + { + return Collections.unmodifiableMap(_messageSequenceNumbersByKey); + } + + public void startSendingMessages() + { + Runnable messageSender = new Runnable() + { + @Override + public void run() + { + try + { + LOGGER.info("Starting to send in background thread"); + Connection producerConnection = getConnection(); + Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer backgroundProducer = producerSession.createProducer(_queue); + for (int messageNumber = 0; messageNumber < MSG_COUNT; messageNumber++) + { + Message message = nextMessage(messageNumber, producerSession, 2); + backgroundProducer.send(message); + + putMessageInMap(message, _messageSequenceNumbersByKey); + _quarterOfMessagesSentLatch.countDown(); + } + + Message shutdownMessage = producerSession.createMessage(); + shutdownMessage.setBooleanProperty(SHUTDOWN, true); + backgroundProducer.send(shutdownMessage); + + LOGGER.info("Finished sending in background thread"); + } + catch (Exception e) + { + _exception = e; + throw new RuntimeException(e); + } + } + }; + + _thread = new Thread(messageSender); + _thread.setName(_threadName); + _thread.start(); + } + + public void join() throws InterruptedException + { + final int timeoutInMillis = 120000; + _thread.join(timeoutInMillis); + assertFalse("Expected producer thread to finish within " + timeoutInMillis + "ms", _thread.isAlive()); + } + } + + private void createConflationQueue(Session session) throws AMQException + { + final Map arguments = new HashMap(); + arguments.put("qpid.last_value_queue_key",KEY_PROPERTY); + ((AMQSession) session).createQueue(new AMQShortString(_queueName), false, true, false, arguments); + _queue = new AMQQueue("amq.direct", _queueName); + ((AMQSession) session).declareAndBind((AMQDestination)_queue); + } + + private Message nextMessage(int msg, Session producerSession) throws JMSException + { + return nextMessage(msg, producerSession, 10); + } + + private Message nextMessage(int msg, Session producerSession, int numberOfUniqueKeyValues) throws JMSException + { + Message send = producerSession.createTextMessage("Message: " + msg); + + send.setStringProperty(KEY_PROPERTY, String.valueOf(msg % numberOfUniqueKeyValues)); + send.setIntProperty(MESSAGE_SEQUENCE_NUMBER_PROPERTY, msg); + + return send; + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/MessageGroupQueueTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/MessageGroupQueueTest.java new file mode 100644 index 0000000000..cb8ced4ddb --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/MessageGroupQueueTest.java @@ -0,0 +1,604 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.queue; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +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 org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.jms.ConnectionURL; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class MessageGroupQueueTest extends QpidBrokerTestCase +{ + protected final String QUEUE = "MessageGroupQueue"; + + private Connection producerConnection; + private MessageProducer producer; + private Session producerSession; + private Queue queue; + private Connection consumerConnection; + + + protected void setUp() throws Exception + { + super.setUp(); + + producerConnection = getConnection(); + producerSession = producerConnection.createSession(true, Session.AUTO_ACKNOWLEDGE); + + producerConnection.start(); + + consumerConnection = getConnection(); + + } + + protected void tearDown() throws Exception + { + producerConnection.close(); + consumerConnection.close(); + super.tearDown(); + } + + + public void testSimpleGroupAssignment() throws Exception + { + simpleGroupAssignment(false); + } + + public void testSharedGroupSimpleGroupAssignment() throws Exception + { + simpleGroupAssignment(true); + } + + + /** + * Pre populate the queue with messages with groups as follows + * + * ONE + * TWO + * ONE + * TWO + * + * Create two consumers with prefetch of 1, the first consumer should then be assigned group ONE, the second + * consumer assigned group TWO if they are started in sequence. + * + * Thus doing + * + * c1 <--- (ONE) + * c2 <--- (TWO) + * c2 ack ---> + * + * c2 should now be able to receive a second message from group TWO (skipping over the message from group ONE) + * + * i.e. + * + * c2 <--- (TWO) + * c2 ack ---> + * c1 <--- (ONE) + * c1 ack ---> + * + */ + private void simpleGroupAssignment(boolean sharedGroups) throws AMQException, JMSException + { + final Map arguments = new HashMap(); + arguments.put(QueueArgumentsConverter.QPID_GROUP_HEADER_KEY,"group"); + if(sharedGroups) + { + arguments.put(QueueArgumentsConverter.QPID_SHARED_MSG_GROUP,"1"); + } + ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments); + queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'"); + + ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); + producer = producerSession.createProducer(queue); + + String[] groups = { "ONE", "TWO"}; + + for (int msg = 0; msg < 4; msg++) + { + producer.send(createMessage(msg, groups[msg % groups.length])); + } + producerSession.commit(); + producer.close(); + producerSession.close(); + producerConnection.close(); + + Session cs1 = ((AMQConnection)consumerConnection).createSession(false, Session.CLIENT_ACKNOWLEDGE,1); + Session cs2 = ((AMQConnection)consumerConnection).createSession(false, Session.CLIENT_ACKNOWLEDGE,1); + + + MessageConsumer consumer1 = cs1.createConsumer(queue); + MessageConsumer consumer2 = cs2.createConsumer(queue); + + consumerConnection.start(); + Message cs1Received = consumer1.receive(1000); + assertNotNull("Consumer 1 should have received first message", cs1Received); + + Message cs2Received = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received first message", cs2Received); + + cs2Received.acknowledge(); + + Message cs2Received2 = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received second message", cs2Received2); + assertEquals("Differing groups", cs2Received2.getStringProperty("group"), + cs2Received.getStringProperty("group")); + + cs1Received.acknowledge(); + Message cs1Received2 = consumer1.receive(1000); + + assertNotNull("Consumer 1 should have received second message", cs1Received2); + assertEquals("Differing groups", cs1Received2.getStringProperty("group"), + cs1Received.getStringProperty("group")); + + cs1Received2.acknowledge(); + cs2Received2.acknowledge(); + + assertNull(consumer1.receive(1000)); + assertNull(consumer2.receive(1000)); + } + + + public void testConsumerCloseGroupAssignment() throws Exception + { + consumerCloseGroupAssignment(false); + } + + public void testSharedGroupConsumerCloseGroupAssignment() throws Exception + { + consumerCloseGroupAssignment(true); + } + + /** + * + * Tests that upon closing a consumer, groups previously assigned to that consumer are reassigned to a different + * consumer. + * + * Pre-populate the queue as ONE, ONE, TWO, ONE + * + * create in sequence two consumers + * + * receive first from c1 then c2 (thus ONE is assigned to c1, TWO to c2) + * + * Then close c1 before acking. + * + * If we now attempt to receive from c2, then the remaining messages in group ONE should be available (which + * requires c2 to go "backwards" in the queue). + * + **/ + private void consumerCloseGroupAssignment(boolean sharedGroups) throws AMQException, JMSException + { + final Map arguments = new HashMap(); + arguments.put(QueueArgumentsConverter.QPID_GROUP_HEADER_KEY,"group"); + if(sharedGroups) + { + arguments.put(QueueArgumentsConverter.QPID_SHARED_MSG_GROUP,"1"); + } + ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments); + queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'"); + + ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); + producer = producerSession.createProducer(queue); + + producer.send(createMessage(1, "ONE")); + producer.send(createMessage(2, "ONE")); + producer.send(createMessage(3, "TWO")); + producer.send(createMessage(4, "ONE")); + + producerSession.commit(); + producer.close(); + producerSession.close(); + producerConnection.close(); + + Session cs1 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1); + Session cs2 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1); + + MessageConsumer consumer1 = cs1.createConsumer(queue); + + consumerConnection.start(); + MessageConsumer consumer2 = cs2.createConsumer(queue); + + Message cs1Received = consumer1.receive(1000); + assertNotNull("Consumer 1 should have received first message", cs1Received); + assertEquals("incorrect message received", 1, cs1Received.getIntProperty("msg")); + + Message cs2Received = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received first message", cs2Received); + assertEquals("incorrect message received", 3, cs2Received.getIntProperty("msg")); + cs2.commit(); + + Message cs2Received2 = consumer2.receive(1000); + + assertNull("Consumer 2 should not yet have received a second message", cs2Received2); + + consumer1.close(); + + cs1.commit(); + Message cs2Received3 = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received second message", cs2Received3); + assertEquals("Unexpected group", "ONE", cs2Received3.getStringProperty("group")); + assertEquals("incorrect message received", 2, cs2Received3.getIntProperty("msg")); + + cs2.commit(); + + + Message cs2Received4 = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received third message", cs2Received4); + assertEquals("Unexpected group", "ONE", cs2Received4.getStringProperty("group")); + assertEquals("incorrect message received", 4, cs2Received4.getIntProperty("msg")); + cs2.commit(); + + assertNull(consumer2.receive(1000)); + } + + + + + public void testConsumerCloseWithRelease() throws Exception + { + consumerCloseWithRelease(false); + } + + public void testSharedGroupConsumerCloseWithRelease() throws Exception + { + consumerCloseWithRelease(true); + } + + + /** + * + * Tests that upon closing a consumer and its session, groups previously assigned to that consumer are reassigned + * toa different consumer, including messages which were previously delivered but have now been released. + * + * Pre-populate the queue as ONE, ONE, TWO, ONE + * + * create in sequence two consumers + * + * receive first from c1 then c2 (thus ONE is assigned to c1, TWO to c2) + * + * Then close c1 and its session without acking. + * + * If we now attempt to receive from c2, then the all messages in group ONE should be available (which + * requires c2 to go "backwards" in the queue). The first such message should be marked as redelivered + * + */ + private void consumerCloseWithRelease(boolean sharedGroups) throws AMQException, JMSException + { + final Map arguments = new HashMap(); + arguments.put(QueueArgumentsConverter.QPID_GROUP_HEADER_KEY,"group"); + if(sharedGroups) + { + arguments.put(QueueArgumentsConverter.QPID_SHARED_MSG_GROUP,"1"); + } + + ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments); + queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'"); + + ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); + producer = producerSession.createProducer(queue); + + producer.send(createMessage(1, "ONE")); + producer.send(createMessage(2, "ONE")); + producer.send(createMessage(3, "TWO")); + producer.send(createMessage(4, "ONE")); + + producerSession.commit(); + producer.close(); + producerSession.close(); + producerConnection.close(); + + Session cs1 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1); + Session cs2 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1); + + + MessageConsumer consumer1 = cs1.createConsumer(queue); + + consumerConnection.start(); + + MessageConsumer consumer2 = cs2.createConsumer(queue); + + Message cs1Received = consumer1.receive(1000); + assertNotNull("Consumer 1 should have received its first message", cs1Received); + assertEquals("incorrect message received", 1, cs1Received.getIntProperty("msg")); + + Message received = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received its first message", received); + assertEquals("incorrect message received", 3, received.getIntProperty("msg")); + + received = consumer2.receive(1000); + + assertNull("Consumer 2 should not yet have received second message", received); + + consumer1.close(); + cs1.close(); + cs2.commit(); + received = consumer2.receive(1000); + + assertNotNull("Consumer 2 should now have received second message", received); + assertEquals("Unexpected group", "ONE", received.getStringProperty("group")); + assertEquals("incorrect message received", 1, received.getIntProperty("msg")); + assertTrue("Expected second message to be marked as redelivered " + received.getIntProperty("msg"), + received.getJMSRedelivered()); + + cs2.commit(); + + + received = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received a third message", received); + assertEquals("Unexpected group", "ONE", received.getStringProperty("group")); + assertEquals("incorrect message received", 2, received.getIntProperty("msg")); + + cs2.commit(); + + received = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received a fourth message", received); + assertEquals("Unexpected group", "ONE", received.getStringProperty("group")); + assertEquals("incorrect message received", 4, received.getIntProperty("msg")); + + cs2.commit(); + + + assertNull(consumer2.receive(1000)); + } + + public void testGroupAssignmentSurvivesEmpty() throws JMSException, AMQException + { + groupAssignmentOnEmpty(false); + } + + public void testSharedGroupAssignmentDoesNotSurviveEmpty() throws JMSException, AMQException + { + groupAssignmentOnEmpty(true); + } + + private void groupAssignmentOnEmpty(boolean sharedGroups) throws AMQException, JMSException + { + final Map arguments = new HashMap(); + arguments.put(QueueArgumentsConverter.QPID_GROUP_HEADER_KEY,"group"); + if(sharedGroups) + { + arguments.put(QueueArgumentsConverter.QPID_SHARED_MSG_GROUP,"1"); + } + + ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments); + queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'"); + + ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); + producer = producerSession.createProducer(queue); + + producer.send(createMessage(1, "ONE")); + producer.send(createMessage(2, "TWO")); + producer.send(createMessage(3, "THREE")); + producer.send(createMessage(4, "ONE")); + + producerSession.commit(); + producer.close(); + producerSession.close(); + producerConnection.close(); + + Session cs1 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1); + Session cs2 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1); + + + MessageConsumer consumer1 = cs1.createConsumer(queue); + + consumerConnection.start(); + + MessageConsumer consumer2 = cs2.createConsumer(queue); + + Message received = consumer1.receive(1000); + assertNotNull("Consumer 1 should have received its first message", received); + assertEquals("incorrect message received", 1, received.getIntProperty("msg")); + + received = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received its first message", received); + assertEquals("incorrect message received", 2, received.getIntProperty("msg")); + + cs1.commit(); + + received = consumer1.receive(1000); + assertNotNull("Consumer 1 should have received its second message", received); + assertEquals("incorrect message received", 3, received.getIntProperty("msg")); + + // We expect different behaviours from "shared groups": here the assignment of a subscription to a group + // is terminated when there are no outstanding delivered but unacknowledged messages. In contrast, with a + // standard message grouping queue the assignment will be retained until the subscription is no longer + // registered + if(sharedGroups) + { + cs2.commit(); + received = consumer2.receive(1000); + + assertNotNull("Consumer 2 should have received its second message", received); + assertEquals("incorrect message received", 4, received.getIntProperty("msg")); + + cs2.commit(); + } + else + { + cs2.commit(); + received = consumer2.receive(1000); + + assertNull("Consumer 2 should not have received a second message", received); + + cs1.commit(); + + received = consumer1.receive(1000); + assertNotNull("Consumer 1 should have received its third message", received); + assertEquals("incorrect message received", 4, received.getIntProperty("msg")); + + } + + } + + private Message createMessage(int msg, String group) throws JMSException + { + Message send = producerSession.createTextMessage("Message: " + msg); + send.setIntProperty("msg", msg); + send.setStringProperty("group", group); + + return send; + } + + /** + * Tests that when a number of new messages for a given groupid are arriving while the delivery group + * state is also in the process of being emptied (due to acking a message while using prefetch=1), that only + * 1 of a number of existing consumers is ever receiving messages for the shared group at a time. + */ + public void testSingleSharedGroupWithMultipleConsumers() throws Exception + { + final Map arguments = new HashMap(); + arguments.put(QueueArgumentsConverter.QPID_GROUP_HEADER_KEY,"group"); + arguments.put(QueueArgumentsConverter.QPID_SHARED_MSG_GROUP,"1"); + + ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments); + queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'"); + + ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); + producer = producerSession.createProducer(queue); + + + consumerConnection.close(); + Map options = new HashMap(); + options.put(ConnectionURL.OPTIONS_MAXPREFETCH, "1"); + consumerConnection = getConnectionWithOptions(options); + + int numMessages = 100; + SharedGroupTestMessageListener groupingTestMessageListener = new SharedGroupTestMessageListener(numMessages); + + Session cs1 = ((AMQConnection)consumerConnection).createSession(false, Session.AUTO_ACKNOWLEDGE); + Session cs2 = ((AMQConnection)consumerConnection).createSession(false, Session.AUTO_ACKNOWLEDGE); + Session cs3 = ((AMQConnection)consumerConnection).createSession(false, Session.AUTO_ACKNOWLEDGE); + Session cs4 = ((AMQConnection)consumerConnection).createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageConsumer consumer1 = cs1.createConsumer(queue); + consumer1.setMessageListener(groupingTestMessageListener); + MessageConsumer consumer2 = cs2.createConsumer(queue); + consumer2.setMessageListener(groupingTestMessageListener); + MessageConsumer consumer3 = cs3.createConsumer(queue); + consumer3.setMessageListener(groupingTestMessageListener); + MessageConsumer consumer4 = cs4.createConsumer(queue); + consumer4.setMessageListener(groupingTestMessageListener); + consumerConnection.start(); + + for(int i = 1; i <= numMessages; i++) + { + producer.send(createMessage(i, "GROUP")); + } + producerSession.commit(); + producer.close(); + producerSession.close(); + producerConnection.close(); + + assertTrue("Mesages not all recieved in the allowed timeframe", groupingTestMessageListener.waitForLatch(30)); + assertEquals("Unexpected concurrent processing of messages for the group", 0, groupingTestMessageListener.getConcurrentProcessingCases()); + assertNull("Unexpecte throwable in message listeners", groupingTestMessageListener.getThrowable()); + } + + public static class SharedGroupTestMessageListener implements MessageListener + { + private final CountDownLatch _count; + private final AtomicInteger _activeListeners = new AtomicInteger(); + private final AtomicInteger _concurrentProcessingCases = new AtomicInteger(); + private Throwable _throwable; + + public SharedGroupTestMessageListener(int numMessages) + { + _count = new CountDownLatch(numMessages); + } + + public void onMessage(Message message) + { + try + { + int currentActiveListeners = _activeListeners.incrementAndGet(); + + if (currentActiveListeners > 1) + { + _concurrentProcessingCases.incrementAndGet(); + + System.err.println("Concurrent processing when handling message: " + message.getIntProperty("msg")); + } + + try + { + Thread.sleep(25); + } + catch (InterruptedException e) + { + Thread.currentThread().interrupt(); + } + + _activeListeners.decrementAndGet(); + } + catch (Throwable t) + { + _throwable = t; + t.printStackTrace(); + } + finally + { + _count.countDown(); + } + } + + public boolean waitForLatch(int seconds) throws Exception + { + return _count.await(seconds, TimeUnit.SECONDS); + } + + public int getConcurrentProcessingCases() + { + return _concurrentProcessingCases.get(); + } + + public Throwable getThrowable() + { + return _throwable; + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/ModelTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/ModelTest.java new file mode 100644 index 0000000000..c6b2c9e95c --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/ModelTest.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.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.management.common.mbeans.ManagedBroker; +import org.apache.qpid.management.common.mbeans.ManagedQueue; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Session; +import javax.management.JMException; +import javax.management.MBeanException; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.UndeclaredThrowableException; + +/** + * This Test validates the Queue Model on the broker. + * Currently it has some basic queue creation / deletion tests. + * However, it should be expanded to include other tests that relate to the + * model. i.e. + * + * The Create and Delete tests should ensure that the requisite logging is + * performed. + * + * Additions to this suite would be to complete testing of creations, validating + * fields such as owner/exclusive, autodelete and priority are correctly set. + * + * Currently this test uses the JMX interface to validate that the queue has + * been declared as expected so these tests cannot run against a CPP broker. + * + * + * Tests should ensure that they clean up after themselves. + * e,g. Durable queue creation test should perform a queue delete. + */ +public class ModelTest extends QpidBrokerTestCase +{ + + private JMXTestUtils _jmxUtils; + private static final String VIRTUALHOST_NAME = "test"; + + @Override + public void setUp() throws Exception + { + getBrokerConfiguration().addJmxManagementConfiguration(); + + // Create a JMX Helper + _jmxUtils = new JMXTestUtils(this); + super.setUp(); + + // Open the JMX Connection + _jmxUtils.open(); + } + + @Override + public void tearDown() throws Exception + { + // Close the JMX Connection + _jmxUtils.close(); + super.tearDown(); + } + + /** + * Test that an exclusive transient queue can be created via AMQP. + * + * @throws Exception On unexpected error + */ + public void testExclusiveQueueCreationTransientViaAMQP() throws Exception + { + Connection connection = getConnection(); + + String queueName = getTestQueueName(); + boolean durable = false; + boolean autoDelete = false; + boolean exclusive = true; + + createViaAMQPandValidateViaJMX(connection, queueName, durable, + autoDelete, exclusive); + } + + + + /** + * Test that a transient queue can be created via AMQP. + * + * @throws Exception On unexpected error + */ + public void testQueueCreationTransientViaAMQP() throws Exception + { + Connection connection = getConnection(); + + String queueName = getTestQueueName(); + boolean durable = false; + boolean autoDelete = false; + boolean exclusive = true; + + createViaAMQPandValidateViaJMX(connection, queueName, durable, + autoDelete, exclusive); + } + + /** + * Test that a durable exclusive queue can be created via AMQP. + * + * @throws Exception On unexpected error + */ + + public void testExclusiveQueueCreationDurableViaAMQP() throws Exception + { + Connection connection = getConnection(); + + String queueName = getTestQueueName(); + boolean durable = true; + boolean autoDelete = false; + boolean exclusive = true; + + createViaAMQPandValidateViaJMX(connection, queueName, durable, + autoDelete, exclusive); + + // Clean up + ManagedBroker managedBroker = + _jmxUtils.getManagedBroker(VIRTUALHOST_NAME); + managedBroker.deleteQueue(queueName); + } + + /** + * Test that a durable queue can be created via AMQP. + * + * @throws Exception On unexpected error + */ + + public void testQueueCreationDurableViaAMQP() throws Exception + { + Connection connection = getConnection(); + + String queueName = getTestQueueName(); + boolean durable = true; + boolean autoDelete = false; + boolean exclusive = false; + + createViaAMQPandValidateViaJMX(connection, queueName, durable, + autoDelete, exclusive); + + // Clean up + ManagedBroker managedBroker = + _jmxUtils.getManagedBroker(VIRTUALHOST_NAME); + managedBroker.deleteQueue(queueName); + } + + + /** + * Test that a transient queue can be created via JMX. + * + * @throws IOException if there is a problem via the JMX connection + * @throws javax.management.JMException if there is a problem with the JMX command + */ + public void testCreationTransientViaJMX() throws IOException, JMException + { + String name = getName(); + String owner = null; + boolean durable = false; + + createViaJMXandValidateViaJMX(name, owner, durable); + } + + /** + * Test that a durable queue can be created via JMX. + * + * @throws IOException if there is a problem via the JMX connection + * @throws javax.management.JMException if there is a problem with the JMX command + */ + public void testCreationDurableViaJMX() throws IOException, JMException + { + String name = getName(); + String owner = null; + boolean durable = true; + + createViaJMXandValidateViaJMX(name, owner, durable); + + // Clean up + ManagedBroker managedBroker = + _jmxUtils.getManagedBroker(VIRTUALHOST_NAME); + managedBroker.deleteQueue(name); + } + + /** + * Test that a transient queue can be deleted via JMX. + * + * @throws IOException if there is a problem via the JMX connection + * @throws javax.management.JMException if there is a problem with the JMX command + */ + public void testDeletionTransientViaJMX() throws IOException, JMException + { + String name = getName(); + + _jmxUtils.createQueue(VIRTUALHOST_NAME, name, null, false); + + ManagedBroker managedBroker = _jmxUtils. + getManagedBroker(VIRTUALHOST_NAME); + + try + { + managedBroker.deleteQueue(name); + } + catch (UndeclaredThrowableException e) + { + fail(((MBeanException) ((InvocationTargetException) + e.getUndeclaredThrowable()).getTargetException()).getTargetException().getMessage()); + } + } + + /** + * Test that a durable queue can be created via JMX. + * + * @throws IOException if there is a problem via the JMX connection + * @throws javax.management.JMException if there is a problem with the JMX command + */ + public void testDeletionDurableViaJMX() throws IOException, JMException + { + String name = getName(); + + _jmxUtils.createQueue(VIRTUALHOST_NAME, name, null, true); + + ManagedBroker managedBroker = _jmxUtils. + getManagedBroker(VIRTUALHOST_NAME); + + try + { + managedBroker.deleteQueue(name); + } + catch (UndeclaredThrowableException e) + { + fail(((MBeanException) ((InvocationTargetException) + e.getUndeclaredThrowable()).getTargetException()).getTargetException().getMessage()); + } + } + + /* + * Helper Methods + */ + + /** + * Using the provided JMS Connection create a queue using the AMQP extension + * with the given properties and then validate it was created correctly via + * the JMX Connection + * + * @param connection Qpid JMS Connection + * @param queueName String the desired QueueName + * @param durable boolean if the queue should be durable + * @param autoDelete boolean if the queue is an autoDelete queue + * @param exclusive boolean if the queue is exclusive + * + * @throws AMQException if there is a problem with the createQueue call + * @throws JMException if there is a problem with the JMX validatation + * @throws IOException if there is a problem with the JMX connection + * @throws JMSException if there is a problem creating the JMS Session + */ + private void createViaAMQPandValidateViaJMX(Connection connection, + String queueName, + boolean durable, + boolean autoDelete, + boolean exclusive) + throws AMQException, JMException, IOException, JMSException + { + AMQSession session = (AMQSession) connection.createSession(false, + Session.AUTO_ACKNOWLEDGE); + + session.createQueue(new AMQShortString(queueName), + autoDelete, durable, exclusive); + + validateQueueViaJMX(queueName, (exclusive && durable &&!isBroker010()) ? connection.getClientID() : null, durable, autoDelete || (exclusive && !isBroker010() && !durable)); + } + + /** + * Use the JMX Helper to create a queue with the given properties and then + * validate it was created correctly via the JMX Connection + * + * @param queueName String the desired QueueName + * @param owner String the owner value that should be set + * @param durable boolean if the queue should be durable + * @param autoDelete boolean if the queue is an autoDelete queue + * + * @throws JMException if there is a problem with the JMX validatation + * @throws IOException if there is a problem with the JMX connection + */ + private void createViaJMXandValidateViaJMX(String queueName, String owner, + boolean durable) + throws JMException, IOException + { + _jmxUtils.createQueue(VIRTUALHOST_NAME, queueName, owner, durable); + + validateQueueViaJMX(queueName, owner, durable, false); + } + + /** + * Validate that a queue with the given properties exists on the broker + * + * @param queueName String the desired QueueName + * @param owner String the owner value that should be set + * @param durable boolean if the queue should be durable + * @param autoDelete boolean if the queue is an autoDelete queue + * + * @throws JMException if there is a problem with the JMX validatation + * @throws IOException if there is a problem with the JMX connection + */ + private void validateQueueViaJMX(String queueName, String owner, boolean durable, boolean autoDelete) + throws JMException, IOException + { + ManagedQueue managedQueue = _jmxUtils. + getManagedObject(ManagedQueue.class, + _jmxUtils.getQueueObjectName(VIRTUALHOST_NAME, + queueName)); + + assertEquals(queueName, managedQueue.getName()); + assertEquals(owner, managedQueue.getOwner()); + assertEquals(durable, managedQueue.isDurable()); + assertEquals(autoDelete, managedQueue.isAutoDelete()); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/MultipleTransactedBatchProducerTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/MultipleTransactedBatchProducerTest.java new file mode 100644 index 0000000000..cbf4e032db --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/MultipleTransactedBatchProducerTest.java @@ -0,0 +1,250 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; + +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Session; + +import java.util.Random; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class MultipleTransactedBatchProducerTest extends QpidBrokerTestCase +{ + private static final Logger _logger = Logger.getLogger(MultipleTransactedBatchProducerTest.class); + + private static final int MESSAGE_COUNT = 1000; + private static final int BATCH_SIZE = 50; + private static final int NUM_PRODUCERS = 2; + private static final int NUM_CONSUMERS = 3; + private static final Random RANDOM = new Random(); + + private CountDownLatch _receivedLatch; + private String _queueName; + + private volatile String _failMsg; + + public void setUp() throws Exception + { + //debug level logging often makes this test pass artificially, turn the level down to info. + setSystemProperty("amqj.server.logging.level", "INFO"); + _receivedLatch = new CountDownLatch(MESSAGE_COUNT * NUM_PRODUCERS); + + getBrokerConfiguration().addJmxManagementConfiguration(); + + super.setUp(); + _queueName = getTestQueueName(); + _failMsg = null; + } + + /** + * When there are multiple producers submitting batches of messages to a given + * queue using transacted sessions, it is highly probable that concurrent + * enqueue() activity will occur and attempt delivery of their message to the + * same subscription. In this scenario it is likely that one of the attempts + * will succeed and the other will result in use of the deliverAsync() method + * to start a queue Runner and ensure delivery of the message. + * + * A defect within the processQueue() method used by the Runner would mean that + * delivery of these messages may not occur, should the Runner stop before all + * messages have been processed. Such a defect was discovered and found to be + * most visible when Selectors are used such that one and only one subscription + * can/will accept any given message, but multiple subscriptions are present, + * and one of the earlier subscriptions receives more messages than the others. + * + * This test is to validate that the processQueue() method is able to correctly + * deliver all of the messages present for asynchronous delivery to subscriptions, + * by utilising multiple batch transacted producers to create the scenario and + * ensure all messages are received by a consumer. + */ + public void testMultipleBatchedProducersWithMultipleConsumersUsingSelectors() throws Exception + { + String selector1 = ("(\"" + _queueName +"\" % " + NUM_CONSUMERS + ") = 0"); + String selector2 = ("(\"" + _queueName +"\" % " + NUM_CONSUMERS + ") = 1"); + String selector3 = ("(\"" + _queueName +"\" % " + NUM_CONSUMERS + ") = 2"); + + //create consumers + Connection conn1 = getConnection(); + conn1.setExceptionListener(new ExceptionHandler("conn1")); + Session sess1 = conn1.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer cons1 = sess1.createConsumer(sess1.createQueue(_queueName), selector1); + cons1.setMessageListener(new Cons(sess1,"consumer1")); + + Connection conn2 = getConnection(); + conn2.setExceptionListener(new ExceptionHandler("conn2")); + Session sess2 = conn2.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer cons2 = sess2.createConsumer(sess2.createQueue(_queueName), selector2); + cons2.setMessageListener(new Cons(sess2,"consumer2")); + + Connection conn3 = getConnection(); + conn3.setExceptionListener(new ExceptionHandler("conn3")); + Session sess3 = conn3.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer cons3 = sess3.createConsumer(sess3.createQueue(_queueName), selector3); + cons3.setMessageListener(new Cons(sess3,"consumer3")); + + conn1.start(); + conn2.start(); + conn3.start(); + + //create producers + Connection connA = getConnection(); + connA.setExceptionListener(new ExceptionHandler("connA")); + Connection connB = getConnection(); + connB.setExceptionListener(new ExceptionHandler("connB")); + Thread producer1 = new Thread(new ProducerThread(connA, _queueName, "producer1")); + Thread producer2 = new Thread(new ProducerThread(connB, _queueName, "producer2")); + + producer1.start(); + Thread.sleep(10); + producer2.start(); + + //await delivery of the messages + int timeout = isBrokerStorePersistent() ? 300 : 75; + boolean result = _receivedLatch.await(timeout, TimeUnit.SECONDS); + + assertNull("Test failed because: " + String.valueOf(_failMsg), _failMsg); + assertTrue("Some of the messages were not all recieved in the given timeframe, remaining count was: "+_receivedLatch.getCount(), + result); + + } + + @Override + public Message createNextMessage(Session session, int msgCount) throws JMSException + { + Message message = super.createNextMessage(session,msgCount); + + //bias at least 50% of the messages to the first consumers selector because + //the issue presents itself primarily when an earlier subscription completes + //delivery after the later subscriptions + int val; + if (msgCount % 2 == 0) + { + val = 0; + } + else + { + val = RANDOM.nextInt(Integer.MAX_VALUE); + } + + message.setIntProperty(_queueName, val); + + return message; + } + + private class Cons implements MessageListener + { + private Session _sess; + private String _desc; + + public Cons(Session sess, String desc) + { + _sess = sess; + _desc = desc; + } + + public void onMessage(Message message) + { + _receivedLatch.countDown(); + int msgCount = 0; + int msgID = 0; + try + { + msgCount = message.getIntProperty(INDEX); + msgID = message.getIntProperty(_queueName); + } + catch (JMSException e) + { + _logger.error(_desc + " received exception: " + e.getMessage(), e); + failAsyncTest(e.getMessage()); + } + + _logger.info("Consumer received message:"+ msgCount + " with ID: " + msgID); + + try + { + _sess.commit(); + } + catch (JMSException e) + { + _logger.error(_desc + " received exception: " + e.getMessage(), e); + failAsyncTest(e.getMessage()); + } + } + } + + private class ProducerThread implements Runnable + { + private Connection _conn; + private String _dest; + private String _desc; + + public ProducerThread(Connection conn, String dest, String desc) + { + _conn = conn; + _dest = dest; + _desc = desc; + } + + public void run() + { + try + { + Session session = _conn.createSession(true, Session.SESSION_TRANSACTED); + sendMessage(session, session.createQueue(_dest), MESSAGE_COUNT, BATCH_SIZE); + } + catch (Exception e) + { + _logger.error(_desc + " received exception: " + e.getMessage(), e); + failAsyncTest(e.getMessage()); + } + } + } + + private class ExceptionHandler implements javax.jms.ExceptionListener + { + private String _desc; + + public ExceptionHandler(String description) + { + _desc = description; + } + + public void onException(JMSException e) + { + _logger.error(_desc + " received exception: " + e.getMessage(), e); + failAsyncTest(e.getMessage()); + } + } + + private void failAsyncTest(String msg) + { + _logger.error("Failing test because: " + msg); + _failMsg = msg; + } +} \ No newline at end of file diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/PriorityQueueTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/PriorityQueueTest.java new file mode 100644 index 0000000000..7b2dd3239d --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/PriorityQueueTest.java @@ -0,0 +1,303 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +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.naming.NamingException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class PriorityQueueTest extends QpidBrokerTestCase +{ + private static final int TIMEOUT = 1500; + + protected final String QUEUE = "PriorityQueue"; + + private static final int MSG_COUNT = 50; + + private Connection producerConnection; + private MessageProducer producer; + private Session producerSession; + private Queue queue; + private Connection consumerConnection; + private Session consumerSession; + + private MessageConsumer consumer; + + protected void setUp() throws Exception + { + super.setUp(); + + producerConnection = getConnection(); + producerSession = producerConnection.createSession(true, Session.AUTO_ACKNOWLEDGE); + + producerConnection.start(); + + consumerConnection = getConnection(); + consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + } + + protected void tearDown() throws Exception + { + producerConnection.close(); + consumerConnection.close(); + super.tearDown(); + } + + public void testPriority() throws JMSException, NamingException, AMQException + { + final Map arguments = new HashMap(); + arguments.put("x-qpid-priorities",10); + ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments); + queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'"); + + ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); + producer = producerSession.createProducer(queue); + + for (int msg = 0; msg < MSG_COUNT; msg++) + { + producer.setPriority(msg % 10); + producer.send(nextMessage(msg, false, producerSession, producer)); + } + producerSession.commit(); + producer.close(); + producerSession.close(); + producerConnection.close(); + + consumer = consumerSession.createConsumer(queue); + consumerConnection.start(); + Message received; + int receivedCount = 0; + Message previous = null; + int messageCount = 0; + while((received = consumer.receive(1000))!=null) + { + messageCount++; + if(previous != null) + { + assertTrue("Messages arrived in unexpected order " + messageCount + " " + previous.getIntProperty("msg") + " " + received.getIntProperty("msg") + " " + previous.getJMSPriority() + " " + received.getJMSPriority(), (previous.getJMSPriority() > received.getJMSPriority()) || ((previous.getJMSPriority() == received.getJMSPriority()) && previous.getIntProperty("msg") < received.getIntProperty("msg")) ); + } + + previous = received; + receivedCount++; + } + + assertEquals("Incorrect number of message received", 50, receivedCount); + } + + public void testOddOrdering() throws AMQException, JMSException + { + final Map arguments = new HashMap(); + arguments.put("x-qpid-priorities",3); + ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments); + queue = producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'"); + + ((AMQSession) producerSession).declareAndBind((AMQDestination)queue); + producer = producerSession.createProducer(queue); + + // In order ABC + producer.setPriority(9); + producer.send(nextMessage(1, false, producerSession, producer)); + producer.setPriority(4); + producer.send(nextMessage(2, false, producerSession, producer)); + producer.setPriority(1); + producer.send(nextMessage(3, false, producerSession, producer)); + + // Out of order BAC + producer.setPriority(4); + producer.send(nextMessage(4, false, producerSession, producer)); + producer.setPriority(9); + producer.send(nextMessage(5, false, producerSession, producer)); + producer.setPriority(1); + producer.send(nextMessage(6, false, producerSession, producer)); + + // Out of order BCA + producer.setPriority(4); + producer.send(nextMessage(7, false, producerSession, producer)); + producer.setPriority(1); + producer.send(nextMessage(8, false, producerSession, producer)); + producer.setPriority(9); + producer.send(nextMessage(9, false, producerSession, producer)); + + // Reverse order CBA + producer.setPriority(1); + producer.send(nextMessage(10, false, producerSession, producer)); + producer.setPriority(4); + producer.send(nextMessage(11, false, producerSession, producer)); + producer.setPriority(9); + producer.send(nextMessage(12, false, producerSession, producer)); + producerSession.commit(); + + consumer = consumerSession.createConsumer(queue); + consumerConnection.start(); + + Message msg = consumer.receive(TIMEOUT); + assertEquals(1, msg.getIntProperty("msg")); + msg = consumer.receive(TIMEOUT); + assertEquals(5, msg.getIntProperty("msg")); + msg = consumer.receive(TIMEOUT); + assertEquals(9, msg.getIntProperty("msg")); + msg = consumer.receive(TIMEOUT); + assertEquals(12, msg.getIntProperty("msg")); + + msg = consumer.receive(TIMEOUT); + assertEquals(2, msg.getIntProperty("msg")); + msg = consumer.receive(TIMEOUT); + assertEquals(4, msg.getIntProperty("msg")); + msg = consumer.receive(TIMEOUT); + assertEquals(7, msg.getIntProperty("msg")); + msg = consumer.receive(TIMEOUT); + assertEquals(11, msg.getIntProperty("msg")); + + msg = consumer.receive(TIMEOUT); + assertEquals(3, msg.getIntProperty("msg")); + msg = consumer.receive(TIMEOUT); + assertEquals(6, msg.getIntProperty("msg")); + msg = consumer.receive(TIMEOUT); + assertEquals(8, msg.getIntProperty("msg")); + msg = consumer.receive(TIMEOUT); + assertEquals(10, msg.getIntProperty("msg")); + } + + private Message nextMessage(int msg, boolean first, Session producerSession, MessageProducer producer) throws JMSException + { + Message send = producerSession.createTextMessage("Message: " + msg); + send.setIntProperty("msg", msg); + + return send; + } + + /** + * Test that after sending an initial message with priority 0, it is able to be repeatedly reflected back to the queue using + * default priority and then consumed again, with separate transacted sessions with prefetch 1 for producer and consumer. + * + * Highlighted defect with PriorityQueues resolved in QPID-3927. + */ + public void testMessageReflectionWithPriorityIncreaseOnTransactedSessionsWithPrefetch1() throws Exception + { + setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, "1"); + Connection conn = getConnection(); + conn.start(); + assertEquals("Prefetch not reset", 1, ((AMQConnection) conn).getMaxPrefetch()); + + final Session producerSess = conn.createSession(true, Session.SESSION_TRANSACTED); + final Session consumerSess = conn.createSession(true, Session.SESSION_TRANSACTED); + + //declare a priority queue with 10 priorities + final Map arguments = new HashMap(); + arguments.put("x-qpid-priorities",10); + ((AMQSession) producerSess).createQueue(new AMQShortString(getTestQueueName()), false, true, false, arguments); + + Queue queue = producerSess.createQueue(getTestQueueName()); + + //create the consumer, producer, add message listener + CountDownLatch latch = new CountDownLatch(5); + MessageConsumer cons = producerSess.createConsumer(queue); + MessageProducer producer = producerSess.createProducer(queue); + + ReflectingMessageListener listener = new ReflectingMessageListener(producerSess,producer,consumerSess,latch); + cons.setMessageListener(listener); + + //Send low priority 0 message to kick start the asynchronous reflection process + producer.setPriority(0); + producer.send(nextMessage(1, true, producerSess, producer)); + producerSess.commit(); + + //wait for the reflection process to complete + assertTrue("Test process failed to complete in allowed time", latch.await(10, TimeUnit.SECONDS)); + assertNull("Unexpected throwable encountered", listener.getThrown()); + } + + private static class ReflectingMessageListener implements MessageListener + { + private static final Logger _logger = Logger.getLogger(PriorityQueueTest.ReflectingMessageListener.class); + + private Session _prodSess; + private Session _consSess; + private CountDownLatch _latch; + private MessageProducer _prod; + private long _origCount; + private Throwable _lastThrown; + + public ReflectingMessageListener(final Session prodSess, final MessageProducer prod, + final Session consSess, final CountDownLatch latch) + { + _latch = latch; + _origCount = _latch.getCount(); + _prodSess = prodSess; + _consSess = consSess; + _prod = prod; + } + + @Override + public void onMessage(final Message message) + { + try + { + _latch.countDown(); + long msgNum = _origCount - _latch.getCount(); + _logger.info("Received message " + msgNum + " with ID: " + message.getIntProperty("msg")); + + if(_latch.getCount() > 0) + { + //reflect the message, updating its ID and using default priority + message.clearProperties(); + message.setIntProperty("msg", (int) msgNum + 1); + _prod.setPriority(Message.DEFAULT_PRIORITY); + _prod.send(message); + _prodSess.commit(); + } + + //commit the consumer session to consume the message + _consSess.commit(); + } + catch(Throwable t) + { + _logger.error(t.getMessage(), t); + _lastThrown = t; + } + } + + public Throwable getThrown() + { + return _lastThrown; + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java new file mode 100644 index 0000000000..427508954d --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java @@ -0,0 +1,494 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.server.queue; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.management.common.mbeans.ManagedQueue; +import org.apache.qpid.server.logging.AbstractTestLogging; +import org.apache.qpid.test.utils.JMXTestUtils; + +public class ProducerFlowControlTest extends AbstractTestLogging +{ + private static final Logger _logger = Logger.getLogger(ProducerFlowControlTest.class); + + private static final int TIMEOUT = 10000; + + private Connection producerConnection; + private Connection consumerConnection; + private Session producerSession; + private Session consumerSession; + private MessageProducer producer; + private MessageConsumer consumer; + private Queue queue; + + private final AtomicInteger _sentMessages = new AtomicInteger(0); + + private JMXTestUtils _jmxUtils; + private boolean _jmxUtilConnected; + + public void setUp() throws Exception + { + getBrokerConfiguration().addJmxManagementConfiguration(); + + _jmxUtils = new JMXTestUtils(this); + _jmxUtilConnected=false; + super.setUp(); + + _monitor.markDiscardPoint(); + + producerConnection = getConnection(); + producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + producerConnection.start(); + + consumerConnection = getConnection(); + consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + } + + public void tearDown() throws Exception + { + try + { + if(_jmxUtilConnected) + { + try + { + _jmxUtils.close(); + } + catch (IOException e) + { + _logger.error("Error closing jmxUtils", e); + } + } + producerConnection.close(); + consumerConnection.close(); + } + finally + { + super.tearDown(); + } + } + + public void testCapacityExceededCausesBlock() throws Exception + { + String queueName = getTestQueueName(); + + createAndBindQueueWithFlowControlEnabled(producerSession, queueName, 1000, 800); + producer = producerSession.createProducer(queue); + + // try to send 5 messages (should block after 4) + sendMessagesAsync(producer, producerSession, 5, 50L); + + Thread.sleep(5000); + + assertEquals("Incorrect number of message sent before blocking", 4, _sentMessages.get()); + + consumer = consumerSession.createConsumer(queue); + consumerConnection.start(); + + + consumer.receive(); + + Thread.sleep(1000); + + assertEquals("Message incorrectly sent after one message received", 4, _sentMessages.get()); + + + consumer.receive(); + + Thread.sleep(1000); + + assertEquals("Message not sent after two messages received", 5, _sentMessages.get()); + + } + + + public void testBrokerLogMessages() throws Exception + { + String queueName = getTestQueueName(); + + createAndBindQueueWithFlowControlEnabled(producerSession, queueName, 1000, 800); + producer = producerSession.createProducer(queue); + + // try to send 5 messages (should block after 4) + sendMessagesAsync(producer, producerSession, 5, 50L); + + List results = waitAndFindMatches("QUE-1003", 7000); + + assertEquals("Did not find correct number of QUE-1003 queue overfull messages", 1, results.size()); + + consumer = consumerSession.createConsumer(queue); + consumerConnection.start(); + + + while(consumer.receive(1000) != null) {}; + + results = waitAndFindMatches("QUE-1004"); + + assertEquals("Did not find correct number of UNDERFULL queue underfull messages", 1, results.size()); + } + + + public void testClientLogMessages() throws Exception + { + String queueName = getTestQueueName(); + + setTestClientSystemProperty("qpid.flow_control_wait_failure","3000"); + setTestClientSystemProperty("qpid.flow_control_wait_notify_period","1000"); + + Session session = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + createAndBindQueueWithFlowControlEnabled(session, queueName, 1000, 800); + producer = session.createProducer(queue); + + // try to send 5 messages (should block after 4) + MessageSender sender = sendMessagesAsync(producer, session, 5, 50L); + + List results = waitAndFindMatches("Message send delayed by", TIMEOUT); + assertTrue("No delay messages logged by client",results.size()!=0); + + List failedMessages = waitAndFindMatches("Message send failed due to timeout waiting on broker enforced" + + " flow control", TIMEOUT); + assertEquals("Incorrect number of send failure messages logged by client (got " + results.size() + " delay " + + "messages)",1,failedMessages.size()); + } + + + public void testFlowControlOnCapacityResumeEqual() throws Exception + { + String queueName = getTestQueueName(); + + createAndBindQueueWithFlowControlEnabled(producerSession, queueName, 1000, 1000); + producer = producerSession.createProducer(queue); + + + // try to send 5 messages (should block after 4) + sendMessagesAsync(producer, producerSession, 5, 50L); + + Thread.sleep(5000); + + assertEquals("Incorrect number of message sent before blocking", 4, _sentMessages.get()); + + consumer = consumerSession.createConsumer(queue); + consumerConnection.start(); + + consumer.receive(); + + Thread.sleep(1000); + + assertEquals("Message incorrectly sent after one message received", 5, _sentMessages.get()); + + + } + + + public void testFlowControlSoak() throws Exception + { + String queueName = getTestQueueName(); + + + final int numProducers = 10; + final int numMessages = 100; + + createAndBindQueueWithFlowControlEnabled(producerSession, queueName, 6000, 3000); + + consumerConnection.start(); + + Connection[] producers = new Connection[numProducers]; + for(int i = 0 ; i < numProducers; i ++) + { + + producers[i] = getConnection(); + producers[i].start(); + Session session = producers[i].createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer myproducer = session.createProducer(queue); + MessageSender sender = sendMessagesAsync(myproducer, session, numMessages, 50L); + } + + consumer = consumerSession.createConsumer(queue); + consumerConnection.start(); + + for(int j = 0; j < numProducers * numMessages; j++) + { + + Message msg = consumer.receive(5000); + Thread.sleep(50L); + assertNotNull("Message not received("+j+"), sent: "+_sentMessages.get(), msg); + + } + + + + Message msg = consumer.receive(500); + assertNull("extra message received", msg); + + + for(int i = 0; i < numProducers; i++) + { + producers[i].close(); + } + + } + + public void testSendTimeout() throws Exception + { + String queueName = getTestQueueName(); + final String expectedMsg = isBroker010() ? "Exception when sending message:timed out waiting for message credit" + : "Unable to send message for 3 seconds due to broker enforced flow control"; + + setTestClientSystemProperty("qpid.flow_control_wait_failure","3000"); + Session session = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + createAndBindQueueWithFlowControlEnabled(producerSession, queueName, 1000, 800); + producer = session.createProducer(queue); + + // try to send 5 messages (should block after 4) + MessageSender sender = sendMessagesAsync(producer, session, 5, 100L); + + Exception e = sender.awaitSenderException(10000); + + assertNotNull("No timeout exception on sending", e); + + + assertEquals("Unexpected exception reason", expectedMsg, e.getMessage()); + + } + + public void testFlowControlAttributeModificationViaJMX() throws Exception + { + _jmxUtils.open(); + _jmxUtilConnected = true; + + String queueName = getTestQueueName(); + + createAndBindQueueWithFlowControlEnabled(producerSession, queueName, 0, 0); + producer = producerSession.createProducer(queue); + + Thread.sleep(1000); + + //Create a JMX MBean proxy for the queue + ManagedQueue queueMBean = _jmxUtils.getManagedObject(ManagedQueue.class, _jmxUtils.getQueueObjectName("test", queueName)); + assertNotNull(queueMBean); + + //check current attribute values are 0 as expected + assertTrue("Capacity was not the expected value", queueMBean.getCapacity() == 0L); + assertTrue("FlowResumeCapacity was not the expected value", queueMBean.getFlowResumeCapacity() == 0L); + + //set new values that will cause flow control to be active, and the queue to become overfull after 1 message is sent + queueMBean.setCapacity(250L); + queueMBean.setFlowResumeCapacity(250L); + assertTrue("Capacity was not the expected value", queueMBean.getCapacity() == 250L); + assertTrue("FlowResumeCapacity was not the expected value", queueMBean.getFlowResumeCapacity() == 250L); + assertFalse("Queue should not be overfull", queueMBean.isFlowOverfull()); + + // try to send 2 messages (should block after 1) + + sendMessagesAsync(producer, producerSession, 2, 50L); + + Thread.sleep(2000); + + //check only 1 message was sent, and queue is overfull + assertEquals("Incorrect number of message sent before blocking", 1, _sentMessages.get()); + assertTrue("Queue should be overfull", queueMBean.isFlowOverfull()); + + //raise the attribute values, causing the queue to become underfull and allow the second message to be sent. + queueMBean.setCapacity(300L); + queueMBean.setFlowResumeCapacity(300L); + + Thread.sleep(2000); + + //check second message was sent, and caused the queue to become overfull again + assertEquals("Second message was not sent after lifting FlowResumeCapacity", 2, _sentMessages.get()); + assertTrue("Queue should be overfull", queueMBean.isFlowOverfull()); + + //raise capacity above queue depth, check queue remains overfull as FlowResumeCapacity still exceeded + queueMBean.setCapacity(700L); + assertTrue("Queue should be overfull", queueMBean.isFlowOverfull()); + + //receive a message, check queue becomes underfull + + consumer = consumerSession.createConsumer(queue); + consumerConnection.start(); + + consumer.receive(); + + //perform a synchronous op on the connection + ((AMQSession) consumerSession).sync(); + + assertFalse("Queue should not be overfull", queueMBean.isFlowOverfull()); + + consumer.receive(); + } + + public void testQueueDeleteWithBlockedFlow() throws Exception + { + String queueName = getTestQueueName(); + createAndBindQueueWithFlowControlEnabled(producerSession, queueName, 1000, 800, true, false); + + producer = producerSession.createProducer(queue); + + // try to send 5 messages (should block after 4) + sendMessagesAsync(producer, producerSession, 5, 50L); + + Thread.sleep(5000); + + assertEquals("Incorrect number of message sent before blocking", 4, _sentMessages.get()); + + // close blocked producer session and connection + producerConnection.close(); + + // delete queue with a consumer session + ((AMQSession) consumerSession).sendQueueDelete(new AMQShortString(queueName)); + + consumer = consumerSession.createConsumer(queue); + consumerConnection.start(); + + Message message = consumer.receive(1000l); + assertNull("Unexpected message", message); + } + + private void createAndBindQueueWithFlowControlEnabled(Session session, String queueName, int capacity, int resumeCapacity) throws Exception + { + createAndBindQueueWithFlowControlEnabled(session, queueName, capacity, resumeCapacity, false, true); + } + + private void createAndBindQueueWithFlowControlEnabled(Session session, String queueName, int capacity, int resumeCapacity, boolean durable, boolean autoDelete) throws Exception + { + final Map arguments = new HashMap(); + arguments.put("x-qpid-capacity",capacity); + arguments.put("x-qpid-flow-resume-capacity",resumeCapacity); + ((AMQSession) session).createQueue(new AMQShortString(queueName), autoDelete, durable, false, arguments); + queue = session.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='" + durable + "'&autodelete='" + autoDelete + "'"); + ((AMQSession) session).declareAndBind((AMQDestination)queue); + } + + private MessageSender sendMessagesAsync(final MessageProducer producer, + final Session producerSession, + final int numMessages, + long sleepPeriod) + { + MessageSender sender = new MessageSender(producer, producerSession, numMessages,sleepPeriod); + new Thread(sender).start(); + return sender; + } + + private void sendMessages(MessageProducer producer, Session producerSession, int numMessages, long sleepPeriod) + throws JMSException + { + + for (int msg = 0; msg < numMessages; msg++) + { + producer.send(nextMessage(msg, producerSession)); + _sentMessages.incrementAndGet(); + + + try + { + ((AMQSession)producerSession).sync(); + } + catch (AMQException e) + { + _logger.error("Error performing sync", e); + throw new RuntimeException(e); + } + + try + { + Thread.sleep(sleepPeriod); + } + catch (InterruptedException e) + { + throw new RuntimeException(e); + } + } + } + + private static final byte[] BYTE_300 = new byte[300]; + + private Message nextMessage(int msg, Session producerSession) throws JMSException + { + BytesMessage send = producerSession.createBytesMessage(); + send.writeBytes(BYTE_300); + send.setIntProperty("msg", msg); + + return send; + } + + private class MessageSender implements Runnable + { + private final MessageProducer _senderProducer; + private final Session _senderSession; + private final int _numMessages; + private volatile JMSException _exception; + private CountDownLatch _exceptionThrownLatch = new CountDownLatch(1); + private long _sleepPeriod; + + public MessageSender(MessageProducer producer, Session producerSession, int numMessages, long sleepPeriod) + { + _senderProducer = producer; + _senderSession = producerSession; + _numMessages = numMessages; + _sleepPeriod = sleepPeriod; + } + + public void run() + { + try + { + sendMessages(_senderProducer, _senderSession, _numMessages, _sleepPeriod); + } + catch (JMSException e) + { + _exception = e; + _exceptionThrownLatch.countDown(); + } + } + + public Exception awaitSenderException(long timeout) throws InterruptedException + { + _exceptionThrownLatch.await(timeout, TimeUnit.MILLISECONDS); + return _exception; + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/QueueBindTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/QueueBindTest.java new file mode 100644 index 0000000000..64ba0156e6 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/QueueBindTest.java @@ -0,0 +1,130 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Session; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.common.AMQPFilterTypes; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.url.AMQBindingURL; + +public class QueueBindTest extends QpidBrokerTestCase +{ + private Connection _connection; + private AMQSession _session; + + protected void setUp() throws Exception + { + super.setUp(); + + _connection = getConnection(); + _session = (AMQSession) _connection.createSession(true, Session.SESSION_TRANSACTED); + } + + public void testQueueCannotBeReboundOnNonTopicExchange() throws Exception + { + runTestForNonTopicExhange(new AMQQueue(new AMQBindingURL("direct://amq.direct//" + getTestQueueName()))); + runTestForNonTopicExhange(new AMQQueue(new AMQBindingURL("fanout://amq.fanout//" + getTestQueueName()) + "?routingkey='" + + getTestQueueName() + "'")); + } + + public void testQueueCanBeReboundOnTopicExchange() throws Exception + { + AMQQueue destination = new AMQQueue(new AMQBindingURL("topic://amq.topic//" + getTestQueueName() + "?routingkey='" + + getTestQueueName() + "'")); + setTestClientSystemProperty("qpid.default_mandatory", "false"); + runTestForTopicExchange(destination); + + } + + private void runTestForTopicExchange(AMQDestination destination) throws AMQException, JMSException, Exception + { + // binding queue with empty arguments + _session.declareAndBind(destination, FieldTable.convertToFieldTable(Collections. emptyMap())); + + // try to re-bind queue with a selector + Map bindArguments = new HashMap(); + bindArguments.put(AMQPFilterTypes.JMS_SELECTOR.getValue().toString(), INDEX + "=0"); + _session.bindQueue(destination.getAMQQueueName(), destination.getRoutingKey(), + FieldTable.convertToFieldTable(bindArguments), destination.getExchangeName(), destination); + + _connection.start(); + + // repeat send/receive twice to make sure that selector is working + for (int i = 0; i < 2; i++) + { + int numberOfMesssages = 2; + sendMessage(_session, destination, numberOfMesssages); + + MessageConsumer consumer = _session.createConsumer(destination); + Message m = consumer.receive(1000); + assertNotNull("Message not received", m); + assertEquals("Unexpected index", 0, m.getIntProperty(INDEX)); + _session.commit(); + + m = consumer.receive(1000); + assertNull("Message received", m); + + consumer.close(); + } + } + + private void runTestForNonTopicExhange(AMQQueue destination) throws AMQException, Exception, JMSException + { + // binding queue with empty arguments + _session.declareAndBind(destination, FieldTable.convertToFieldTable(Collections. emptyMap())); + + // try to re-bind queue with a selector + Map bindArguments = new HashMap(); + bindArguments.put(AMQPFilterTypes.JMS_SELECTOR.getValue().toString(), INDEX + "=0"); + _session.bindQueue(destination.getAMQQueueName(), destination.getRoutingKey(), + FieldTable.convertToFieldTable(bindArguments), destination.getExchangeName(), destination); + + // send and receive to prove that selector is not used + int numberOfMesssages = 2; + sendMessage(_session, destination, numberOfMesssages); + + MessageConsumer consumer = _session.createConsumer(destination); + _connection.start(); + + for (int i = 0; i < numberOfMesssages; i++) + { + Message m = consumer.receive(1000l); + assertNotNull("Message [" + i + "] not received with exchange " + destination.getExchangeName(), m); + assertEquals("Unexpected index", i, m.getIntProperty(INDEX)); + _session.commit(); + } + consumer.close(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java new file mode 100644 index 0000000000..dd57c1e3f7 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/QueueDepthWithSelectorTest.java @@ -0,0 +1,175 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.queue; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +/** + * Test Case to ensure that messages are correctly returned. + * This includes checking: + * - The message is returned. + * - The broker doesn't leak memory. + * - The broker's state is correct after test. + */ +public class QueueDepthWithSelectorTest extends QpidBrokerTestCase +{ + protected final String VHOST = "test"; + protected final String QUEUE = this.getClass().getName(); + + protected Connection _clientConnection; + protected Connection _producerConnection; + private Session _clientSession; + protected Session _producerSession; + protected MessageProducer _producer; + private MessageConsumer _consumer; + + protected static int MSG_COUNT = 50; + + protected Message[] _messages = new Message[MSG_COUNT]; + + protected Queue _queue; + + @Override + public void setUp() throws Exception + { + super.setUp(); + + _messages = new Message[MSG_COUNT]; + _queue = getTestQueue(); + + //Create Producer + _producerConnection = getConnection(); + _producerConnection.start(); + _producerSession = _producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _producer = _producerSession.createProducer(_queue); + + // Create consumer + _clientConnection = getConnection(); + _clientConnection.start(); + _clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _consumer = _clientSession.createConsumer(_queue, "key = 23"); + } + + public void test() throws Exception + { + //Send messages + _logger.info("Starting to send messages"); + for (int msg = 0; msg < MSG_COUNT; msg++) + { + _producer.send(nextMessage(msg)); + } + _logger.info("Closing connection"); + //Close the connection.. .giving the broker time to clean up its state. + _producerConnection.close(); + + //Verify we get all the messages. + _logger.info("Verifying messages"); + verifyAllMessagesRecevied(50); + verifyBrokerState(0); + + //Close the connection.. .giving the broker time to clean up its state. + _clientConnection.close(); + + //Verify Broker state + _logger.info("Verifying broker state"); + verifyBrokerState(0); + } + + protected void verifyBrokerState(int expectedDepth) + { + try + { + Connection connection = getConnection(); + AMQSession session = (AMQSession)connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + long queueDepth = session.getQueueDepth((AMQDestination) _queue); + assertEquals("Session reports Queue depth not as expected", expectedDepth, queueDepth); + + connection.close(); + } + catch (AMQException e) + { + fail(e.getMessage()); + } + catch (Exception e) + { + fail(e.getMessage()); + } + } + + protected void verifyAllMessagesRecevied(int expectedDepth) throws Exception + { + boolean[] msgIdRecevied = new boolean[MSG_COUNT]; + + for (int i = 0; i < expectedDepth; i++) + { + _messages[i] = _consumer.receive(1000); + assertNotNull("should have received a message but didn't", _messages[i]); + } + + //Check received messages + int msgId = 0; + for (Message msg : _messages) + { + assertNotNull("Message should not be null", msg); + assertEquals("msgId was wrong", msgId, msg.getIntProperty("ID")); + assertFalse("Already received msg id " + msgId, msgIdRecevied[msgId]); + msgIdRecevied[msgId] = true; + msgId++; + } + + //Check all received + for (msgId = 0; msgId < expectedDepth; msgId++) + { + assertTrue("Message " + msgId + " not received.", msgIdRecevied[msgId]); + } + + //do a synchronous op to ensure the acks are processed + //on the broker before proceeding + ((AMQSession)_clientSession).sync(); + } + + /** + * Get the next message putting the given count into the intProperties as ID. + * + * @param msgNo the message count to store as ID. + * @throws JMSException + */ + protected Message nextMessage(int msgNo) throws JMSException + { + Message send = _producerSession.createTextMessage("MessageReturnTest"); + send.setIntProperty("ID", msgNo); + send.setIntProperty("key", 23); + return send; + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/QueueMessageDurabilityTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/QueueMessageDurabilityTest.java new file mode 100644 index 0000000000..fe86e9d41f --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/QueueMessageDurabilityTest.java @@ -0,0 +1,216 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import java.util.HashMap; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.store.MessageDurability; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class QueueMessageDurabilityTest extends QpidBrokerTestCase +{ + + private static final String QPID_MESSAGE_DURABILITY = "qpid.message_durability"; + private static final String DURABLE_ALWAYS_PERSIST_NAME = "DURABLE_QUEUE_ALWAYS_PERSIST"; + private static final String DURABLE_NEVER_PERSIST_NAME = "DURABLE_QUEUE_NEVER_PERSIST"; + private static final String DURABLE_DEFAULT_PERSIST_NAME = "DURABLE_QUEUE_DEFAULT_PERSIST"; + private static final String NONDURABLE_ALWAYS_PERSIST_NAME = "NONDURABLE_QUEUE_ALWAYS_PERSIST"; + + @Override + public void setUp() throws Exception + { + super.setUp(); + Connection conn = getConnection(); + Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + AMQSession amqSession = (AMQSession) session; + + Map arguments = new HashMap<>(); + arguments.put(QPID_MESSAGE_DURABILITY, MessageDurability.ALWAYS.name()); + amqSession.createQueue(new AMQShortString(DURABLE_ALWAYS_PERSIST_NAME), false, true, false, arguments); + + arguments = new HashMap<>(); + arguments.put(QPID_MESSAGE_DURABILITY, MessageDurability.NEVER.name()); + amqSession.createQueue(new AMQShortString(DURABLE_NEVER_PERSIST_NAME), false, true, false, arguments); + + arguments = new HashMap<>(); + arguments.put(QPID_MESSAGE_DURABILITY, MessageDurability.DEFAULT.name()); + amqSession.createQueue(new AMQShortString(DURABLE_DEFAULT_PERSIST_NAME), false, true, false, arguments); + + arguments = new HashMap<>(); + arguments.put(QPID_MESSAGE_DURABILITY,MessageDurability.ALWAYS.name()); + amqSession.createQueue(new AMQShortString(NONDURABLE_ALWAYS_PERSIST_NAME), false, false, false, arguments); + + amqSession.bindQueue(AMQShortString.valueOf(DURABLE_ALWAYS_PERSIST_NAME), + AMQShortString.valueOf("Y.*.*.*"), + null, + AMQShortString.valueOf(ExchangeDefaults.TOPIC_EXCHANGE_NAME), + null); + + amqSession.bindQueue(AMQShortString.valueOf(DURABLE_NEVER_PERSIST_NAME), + AMQShortString.valueOf("*.Y.*.*"), + null, + AMQShortString.valueOf(ExchangeDefaults.TOPIC_EXCHANGE_NAME), + null); + + amqSession.bindQueue(AMQShortString.valueOf(DURABLE_DEFAULT_PERSIST_NAME), + AMQShortString.valueOf("*.*.Y.*"), + null, + AMQShortString.valueOf(ExchangeDefaults.TOPIC_EXCHANGE_NAME), + null); + + amqSession.bindQueue(AMQShortString.valueOf(NONDURABLE_ALWAYS_PERSIST_NAME), + AMQShortString.valueOf("*.*.*.Y"), + null, + AMQShortString.valueOf(ExchangeDefaults.TOPIC_EXCHANGE_NAME), + null); + } + + public void testSendPersistentMessageToAll() throws Exception + { + Connection conn = getConnection(); + Session session = conn.createSession(true, Session.SESSION_TRANSACTED); + MessageProducer producer = session.createProducer(null); + conn.start(); + producer.send(session.createTopic("Y.Y.Y.Y"), session.createTextMessage("test")); + session.commit(); + + AMQSession amqSession = (AMQSession) session; + assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_ALWAYS_PERSIST_NAME))); + assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_NEVER_PERSIST_NAME))); + assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_DEFAULT_PERSIST_NAME))); + assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(NONDURABLE_ALWAYS_PERSIST_NAME))); + + restartBroker(); + + conn = getConnection(); + session = conn.createSession(true, Session.SESSION_TRANSACTED); + amqSession = (AMQSession) session; + assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_ALWAYS_PERSIST_NAME))); + assertEquals(0,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_NEVER_PERSIST_NAME))); + assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_DEFAULT_PERSIST_NAME))); + + assertFalse(amqSession.isQueueBound((AMQDestination) session.createQueue(NONDURABLE_ALWAYS_PERSIST_NAME))); + + } + + + public void testSendNonPersistentMessageToAll() throws Exception + { + Connection conn = getConnection(); + Session session = conn.createSession(true, Session.SESSION_TRANSACTED); + MessageProducer producer = session.createProducer(null); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + conn.start(); + producer.send(session.createTopic("Y.Y.Y.Y"), session.createTextMessage("test")); + session.commit(); + + AMQSession amqSession = (AMQSession) session; + assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_ALWAYS_PERSIST_NAME))); + assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_NEVER_PERSIST_NAME))); + assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_DEFAULT_PERSIST_NAME))); + assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(NONDURABLE_ALWAYS_PERSIST_NAME))); + + restartBroker(); + + conn = getConnection(); + session = conn.createSession(true, Session.SESSION_TRANSACTED); + amqSession = (AMQSession) session; + assertEquals(1,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_ALWAYS_PERSIST_NAME))); + assertEquals(0,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_NEVER_PERSIST_NAME))); + assertEquals(0,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_DEFAULT_PERSIST_NAME))); + + assertFalse(amqSession.isQueueBound((AMQDestination)session.createQueue(NONDURABLE_ALWAYS_PERSIST_NAME))); + + } + + public void testNonPersistentContentRetained() throws Exception + { + Connection conn = getConnection(); + Session session = conn.createSession(true, Session.SESSION_TRANSACTED); + MessageProducer producer = session.createProducer(null); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + conn.start(); + producer.send(session.createTopic("N.N.Y.Y"), session.createTextMessage("test1")); + producer.send(session.createTopic("Y.N.Y.Y"), session.createTextMessage("test2")); + session.commit(); + MessageConsumer consumer = session.createConsumer(session.createQueue(DURABLE_ALWAYS_PERSIST_NAME)); + Message msg = consumer.receive(1000l); + assertNotNull(msg); + assertTrue(msg instanceof TextMessage); + assertEquals("test2", ((TextMessage) msg).getText()); + session.rollback(); + restartBroker(); + conn = getConnection(); + conn.start(); + session = conn.createSession(true, Session.SESSION_TRANSACTED); + AMQSession amqSession = (AMQSession) session; + assertEquals(1, amqSession.getQueueDepth((AMQDestination) session.createQueue(DURABLE_ALWAYS_PERSIST_NAME))); + assertEquals(0,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_NEVER_PERSIST_NAME))); + assertEquals(0,amqSession.getQueueDepth((AMQDestination)session.createQueue(DURABLE_DEFAULT_PERSIST_NAME))); + consumer = session.createConsumer(session.createQueue(DURABLE_ALWAYS_PERSIST_NAME)); + msg = consumer.receive(1000l); + assertNotNull(msg); + assertTrue(msg instanceof TextMessage); + assertEquals("test2", ((TextMessage)msg).getText()); + session.commit(); + } + + public void testPersistentContentRetainedOnTransientQueue() throws Exception + { + setTestClientSystemProperty(ClientProperties.QPID_DECLARE_QUEUES_PROP_NAME, "false"); + Connection conn = getConnection(); + Session session = conn.createSession(true, Session.SESSION_TRANSACTED); + MessageProducer producer = session.createProducer(null); + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + conn.start(); + producer.send(session.createTopic("N.N.Y.Y"), session.createTextMessage("test1")); + session.commit(); + MessageConsumer consumer = session.createConsumer(session.createQueue(DURABLE_DEFAULT_PERSIST_NAME)); + Message msg = consumer.receive(1000l); + assertNotNull(msg); + assertTrue(msg instanceof TextMessage); + assertEquals("test1", ((TextMessage)msg).getText()); + session.commit(); + System.gc(); + consumer = session.createConsumer(session.createQueue(NONDURABLE_ALWAYS_PERSIST_NAME)); + msg = consumer.receive(1000l); + assertNotNull(msg); + assertTrue(msg instanceof TextMessage); + assertEquals("test1", ((TextMessage)msg).getText()); + session.commit(); + } + + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/SortedQueueTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/SortedQueueTest.java new file mode 100644 index 0000000000..340ae4a1ae --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/SortedQueueTest.java @@ -0,0 +1,538 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.queue; + +import org.apache.log4j.Logger; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.naming.NamingException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.atomic.AtomicInteger; + +public class SortedQueueTest extends QpidBrokerTestCase +{ + private static final Logger LOGGER = Logger.getLogger(SortedQueueTest.class); + public static final String TEST_SORT_KEY = "testSortKey"; + private static final String[] VALUES = SortedQueueEntryListTest.keys.clone(); + private static final String[] VALUES_SORTED = SortedQueueEntryListTest.keys.clone(); + private final String[] SUBSET_KEYS = { "000", "100", "200", "300", "400", "500", "600", "700", "800", "900" }; + + private Connection _producerConnection; + private Session _producerSession; + private Connection _consumerConnection; + private long _receiveInterval; + + protected void setUp() throws Exception + { + super.setUp(); + setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, "1"); + // Sort value array to generated "expected" order of messages. + Arrays.sort(VALUES_SORTED); + _producerConnection = getConnection(); + _consumerConnection = getConnection(); + _producerSession = _producerConnection.createSession(true, Session.SESSION_TRANSACTED); + _receiveInterval = isBrokerStorePersistent() ? 3000l : 1500l; + } + + protected void tearDown() throws Exception + { + _producerSession.close(); + _producerConnection.close(); + _consumerConnection.close(); + super.tearDown(); + } + + public void testSortOrder() throws JMSException, NamingException, AMQException + { + final Queue queue = createQueue(); + final MessageProducer producer = _producerSession.createProducer(queue); + + for(String value : VALUES) + { + final Message msg = _producerSession.createTextMessage("Message Text:" + value); + msg.setStringProperty(TEST_SORT_KEY, value); + producer.send(msg); + } + + _producerSession.commit(); + producer.close(); + + final Session consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageConsumer consumer = consumerSession.createConsumer(queue); + _consumerConnection.start(); + TextMessage received; + int messageCount = 0; + while((received = (TextMessage) consumer.receive(_receiveInterval)) != null) + { + assertEquals("Received message with unexpected sorted key value", VALUES_SORTED[messageCount], + received.getStringProperty(TEST_SORT_KEY)); + assertEquals("Received message with unexpected message value", + "Message Text:" + VALUES_SORTED[messageCount], received.getText()); + messageCount++; + } + + assertEquals("Incorrect number of messages received", VALUES.length, messageCount); + } + + public void testAutoAckSortedQueue() throws JMSException, NamingException, AMQException + { + runThroughSortedQueueForSessionMode(Session.AUTO_ACKNOWLEDGE); + } + + public void testTransactedSortedQueue() throws JMSException, NamingException, AMQException + { + runThroughSortedQueueForSessionMode(Session.SESSION_TRANSACTED); + } + + public void testClientAckSortedQueue() throws JMSException, NamingException, AMQException + { + runThroughSortedQueueForSessionMode(Session.CLIENT_ACKNOWLEDGE); + } + + private void runThroughSortedQueueForSessionMode(final int sessionMode) throws JMSException, NamingException, + AMQException + { + final Queue queue = createQueue(); + final MessageProducer producer = _producerSession.createProducer(queue); + + final TestConsumerThread consumerThread = new TestConsumerThread(sessionMode, queue); + consumerThread.start(); + + for(String value : VALUES) + { + final Message msg = _producerSession.createMessage(); + msg.setStringProperty(TEST_SORT_KEY, value); + producer.send(msg); + _producerSession.commit(); + } + + try + { + consumerThread.join(getConsumerThreadJoinInterval()); + } + catch(InterruptedException e) + { + fail("Test failed waiting for consumer to complete"); + } + + assertTrue("Consumer timed out", consumerThread.isStopped()); + assertEquals("Incorrect number of messages received", VALUES.length, consumerThread.getConsumed()); + + producer.close(); + } + + public void testSortedQueueWithAscendingSortedKeys() throws JMSException, NamingException, AMQException + { + final Queue queue = createQueue(); + final MessageProducer producer = _producerSession.createProducer(queue); + + final TestConsumerThread consumerThread = new TestConsumerThread(Session.AUTO_ACKNOWLEDGE, queue); + consumerThread.start(); + + for(int i = 0; i < 200; i++) + { + final String ascendingKey = AscendingSortedKeys.getNextKey(); + final Message msg = _producerSession.createTextMessage("Message Text:" + ascendingKey); + msg.setStringProperty(TEST_SORT_KEY, ascendingKey); + producer.send(msg); + _producerSession.commit(); + } + + try + { + consumerThread.join(getConsumerThreadJoinInterval()); + } + catch(InterruptedException e) + { + fail("Test failed waiting for consumer to complete"); + } + + assertTrue("Consumer timed out", consumerThread.isStopped()); + assertEquals("Incorrect number of messages received", 200, consumerThread.getConsumed()); + + producer.close(); + } + + private long getConsumerThreadJoinInterval() + { + return isBrokerStorePersistent() ? 50000L: 5000L; + } + + public void testSortOrderWithNonUniqueKeys() throws JMSException, NamingException, AMQException + { + final Queue queue = createQueue(); + final MessageProducer producer = _producerSession.createProducer(queue); + + int count = 0; + while(count < 200) + { + final Message msg = _producerSession.createTextMessage("Message Text:" + count++); + msg.setStringProperty(TEST_SORT_KEY, "samesortkeyvalue"); + producer.send(msg); + } + + _producerSession.commit(); + producer.close(); + + final Session consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageConsumer consumer = consumerSession.createConsumer(queue); + _consumerConnection.start(); + TextMessage received = null; + int messageCount = 0; + + while((received = (TextMessage) consumer.receive(_receiveInterval)) != null) + { + assertEquals("Received message with unexpected sorted key value", "samesortkeyvalue", + received.getStringProperty(TEST_SORT_KEY)); + assertEquals("Received message with unexpected message value", "Message Text:" + messageCount, + received.getText()); + messageCount++; + } + + assertEquals("Incorrect number of messages received", 200, messageCount); + } + + public void testSortOrderWithUniqueKeySubset() throws JMSException, NamingException, AMQException + { + final Queue queue = createQueue(); + final MessageProducer producer = _producerSession.createProducer(queue); + + int count = 0; + while(count < 100) + { + int keyValueIndex = count % 10; + final Message msg = _producerSession.createTextMessage("Message Text:" + count); + msg.setStringProperty(TEST_SORT_KEY, SUBSET_KEYS[keyValueIndex]); + producer.send(msg); + count++; + } + + _producerSession.commit(); + producer.close(); + + final Session consumerSession = _consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final MessageConsumer consumer = consumerSession.createConsumer(queue); + _consumerConnection.start(); + TextMessage received; + int messageCount = 0; + + while((received = (TextMessage) consumer.receive(_receiveInterval)) != null) + { + assertEquals("Received message with unexpected sorted key value", SUBSET_KEYS[messageCount / 10], + received.getStringProperty(TEST_SORT_KEY)); + messageCount++; + } + + assertEquals("Incorrect number of messages received", 100, messageCount); + } + + public void testGetNextWithAck() throws JMSException, NamingException, AMQException + { + Queue _queue = createQueue(); + MessageProducer producer = _producerSession.createProducer(_queue); + Message received = null; + + //Send 3 out of order + sendAndCommitMessage(producer,"2"); + sendAndCommitMessage(producer,"3"); + sendAndCommitMessage(producer,"1"); + + final Session consumerSession = _consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + final MessageConsumer consumer = consumerSession.createConsumer(_queue); + _consumerConnection.start(); + + //Receive 3 in sorted order + received = assertReceiveAndValidateMessage(consumer, "1"); + received.acknowledge(); + received = assertReceiveAndValidateMessage(consumer, "2"); + received.acknowledge(); + received = assertReceiveAndValidateMessage(consumer, "3"); + received.acknowledge(); + + //Send 1 + sendAndCommitMessage(producer,"4"); + + //Receive 1 and recover + received = assertReceiveAndValidateMessage(consumer, "4"); + consumerSession.recover(); + + //Receive same 1 + received = assertReceiveAndValidateMessage(consumer, "4"); + received.acknowledge(); + + //Send 3 out of order + sendAndCommitMessage(producer,"7"); + sendAndCommitMessage(producer,"6"); + sendAndCommitMessage(producer,"5"); + + //Receive 1 of 3 (possibly out of order due to pre-fetch) + final Message messageBeforeRollback = assertReceiveMessage(consumer); + consumerSession.recover(); + + if (isBroker010()) + { + //Receive 3 in sorted order (not as per JMS recover) + received = assertReceiveAndValidateMessage(consumer, "5"); + received.acknowledge(); + received = assertReceiveAndValidateMessage(consumer, "6"); + received.acknowledge(); + received = assertReceiveAndValidateMessage(consumer, "7"); + received.acknowledge(); + } + else + { + //First message will be the one rolled-back (as per JMS spec). + final String messageKeyDeliveredBeforeRollback = messageBeforeRollback.getStringProperty(TEST_SORT_KEY); + received = assertReceiveAndValidateMessage(consumer, messageKeyDeliveredBeforeRollback); + received.acknowledge(); + + //Remaining two messages will be sorted + final SortedSet keys = new TreeSet(Arrays.asList("5", "6", "7")); + keys.remove(messageKeyDeliveredBeforeRollback); + + received = assertReceiveAndValidateMessage(consumer, keys.first()); + received.acknowledge(); + received = assertReceiveAndValidateMessage(consumer, keys.last()); + received.acknowledge(); + } + } + + private Queue createQueue() throws AMQException, JMSException + { + final Map arguments = new HashMap(); + arguments.put(QueueArgumentsConverter.QPID_QUEUE_SORT_KEY, TEST_SORT_KEY); + ((AMQSession) _producerSession).createQueue(new AMQShortString(getTestQueueName()), false, true, false, arguments); + final Queue queue = new AMQQueue("amq.direct", getTestQueueName()); + ((AMQSession) _producerSession).declareAndBind((AMQDestination) queue); + return queue; + } + + private Message getSortableTestMesssage(final String key) throws JMSException + { + final Message msg = _producerSession.createTextMessage("Message Text: Key Value" + key); + msg.setStringProperty(TEST_SORT_KEY, key); + return msg; + } + + private void sendAndCommitMessage(final MessageProducer producer, final String keyValue) throws JMSException + { + producer.send(getSortableTestMesssage(keyValue)); + _producerSession.commit(); + } + + private Message assertReceiveAndValidateMessage(final MessageConsumer consumer, final String expectedKey) throws JMSException + { + final Message received = assertReceiveMessage(consumer); + assertEquals("Received message with unexpected sorted key value", expectedKey, + received.getStringProperty(TEST_SORT_KEY)); + return received; + } + + private Message assertReceiveMessage(final MessageConsumer consumer) + throws JMSException + { + final Message received = (TextMessage) consumer.receive(_receiveInterval); + assertNotNull("Received message is unexpectedly null", received); + return received; + } + + private class TestConsumerThread extends Thread + { + private final AtomicInteger _consumed = new AtomicInteger(0); + private volatile boolean _stopped = false; + private int _count = 0; + private int _sessionType = Session.AUTO_ACKNOWLEDGE; + private Queue _queue; + + public TestConsumerThread(final int sessionType, final Queue queue) + { + _sessionType = sessionType; + _queue = queue; + } + + public void run() + { + try + { + Connection conn = null; + try + { + conn = getConnection(); + } + catch(Exception e) + { + throw new RuntimeException("Could not get connection"); + } + + final Session session = conn.createSession((_sessionType == Session.SESSION_TRANSACTED ? true : false), + _sessionType); + final MessageConsumer consumer = session.createConsumer(_queue); + + conn.start(); + + Message msg; + while((msg = consumer.receive(_receiveInterval)) != null) + { + if(_sessionType == Session.SESSION_TRANSACTED) + { + if (_count%10 == 0) + { + LOGGER.debug("transacted session rollback"); + session.rollback(); + } + else + { + LOGGER.debug("transacted session commit"); + session.commit(); + _consumed.incrementAndGet(); + } + } + else if(_sessionType == Session.CLIENT_ACKNOWLEDGE) + { + if (_count%10 == 0) + { + LOGGER.debug("client ack session recover"); + session.recover(); + } + else + { + LOGGER.debug("client ack session acknowledge"); + msg.acknowledge(); + _consumed.incrementAndGet(); + } + } + else + { + LOGGER.debug("auto ack session"); + _consumed.incrementAndGet(); + } + + _count++; + LOGGER.debug("Message consumed with key: " + msg.getStringProperty(TEST_SORT_KEY)); + LOGGER.debug("Message consumed with consumed index: " + _consumed.get()); + } + + _stopped = true; + session.close(); + conn.close(); + } + catch(JMSException e) + { + LOGGER.error("Exception in listener", e); + } + } + + public boolean isStopped() + { + return _stopped; + } + + public int getConsumed() + { + return _consumed.get(); + } + } + + private static class AscendingSortedKeys + { + public static final String[] KEYS = { "Ul4a1", "WaWsv", "2Yz7E", "ix74r", "okgRi", "HlUbF", "LewvM", "lweGy", + "TXQ0Z", "0Kyfs", "s7Mxk", "dmoS7", "8RCUA", "W3VFH", "aez9y", "uQIcz", "0h1b1", "cmXIX", + "4dEz6", "zHF1q", "D6rBy", "5drc6", "0BmCy", "BCxeC", "t59lR", "aL6AJ", "OHaBz", "WmadA", + "B3qem", "CxVEf", "AIYUu", "uJScX", "uoStw", "ogLgc", "AgJHQ", "hUTw7", "Rxrsm", "9GXkX", + "7hyVv", "y94nw", "Twano", "TCgPp", "pFrrl", "POUYS", "L7cGc", "0ao3l", "CNHmv", "MaJQs", + "OUqFM", "jeskS", "FPfSE", "v1Hln", "14FLR", "KZamH", "G1RhS", "FVMxo", "rKDLJ", "nnP8o", + "nFqik", "zmLYD", "1j5L8", "e6e4z", "WDVWJ", "aDGtS", "fcwDa", "nlaBy", "JJs5m", "vLsmS", + "No0Qb", "JXljW", "Waim6", "MezSW", "l83Ud", "SjskQ", "uPX7G", "5nmWv", "ZhwG1", "uTacx", + "t98iW", "JkzUn", "fmIK1", "i7WMQ", "bgJAz", "n1pmO", "jS1aj", "4W0Tl", "Yf2Ec", "sqVrf", + "MojnP", "qQxHP", "pWiOs", "yToGW", "kB5nP", "BpYhV", "Cfgr3", "zbIYY", "VLTy6", "he9IA", + "lm0pD", "WreyP", "8hJdt", "QnJ1S", "n8pJ9", "iqv4k", "OUYuF", "8cVD3", "sx5Gl", "cQOnv", + "wiHrZ", "oGu6x", "7fsYM", "gf8rI", "7fKYU", "pT8wu", "lCMxy", "prNT6", "5Drn0", "guMb8", + "OxWIH", "uZPqg", "SbRYy", "In3NS", "uvf7A", "FLsph", "pmeCd", "BbwgA", "ru4UG", "YOfrY", + "W7cTs", "K4GS8", "AOgEe", "618Di", "dpe1v", "3otm6", "oVQp6", "5Mg9r", "Y1mC0", "VIlwP", + "aFFss", "Mkgy8", "pv0i7", "S77LH", "XyPZN", "QYxC0", "vkCHH", "MGlTF", "24ARF", "v2eC3", + "ZUnqt", "HfyNQ", "FjHXR", "45cIH", "1LB1L", "zqH0W", "fLNg8", "oQ87r", "Cp3mZ", "Zv7z0", + "O3iyQ", "EOE1o", "5ZaEz", "tlILt", "MmsIo", "lXFOB", "gtCA5", "yEfy9", "7X3uy", "d7vjM", + "XflUq", "Fhtgl", "NOHsz", "GWqqX", "xciqp", "BFkb8", "P6bcg", "lViBv", "2TRI7", "2hEEU", + "9XyT9", "29QAz", "U3yw5", "FxX9q", "C2Irc", "8U2nU", "m4bxU", "5iGN5", "mX2GE", "cShY2", + "JRJQB", "yvOMI", "4QMc9", "NAFuw", "RmDcr", "faHir", "2ZHdk", "zY1GY", "a00b5", "ZuDtD", + "JIqXi", "K20wK", "gdQsS", "5Namm", "lkMUA", "IBe8k", "FcWrW", "FFDui", "tuDyS", "ZJTXH", + "AkKTk", "zQt6Q", "FNYIM", "RpBQm", "RsQUq", "Mm8si", "gjUTu", "zz4ZU", "jiVBP", "ReKEW", + "5VZjS", "YjB9t", "zFgtB", "8TxD7", "euZA5", "MK07Y", "CK5W7", "16lHc", "6q6L9", "Z4I1v", + "UlU3M", "SWfou", "0PktI", "55rfB", "jfREu", "580YD", "Uvlv4", "KASQ8", "AmdQd", "piJSk", + "hE1Ql", "LDk6f", "NcICA", "IKxdL", "iwzGk", "uN6r3", "lsQGo", "QClRL", "iKqhr", "FGzgp", + "RkQke", "b29RJ", "CIShG", "9eoRc", "F6PT2", "LbRTH", "M3zXL", "GXdoH", "IjTwP", "RBhp0", + "yluBx", "mz8gx", "MmKGJ", "Q6Lix", "uupzk", "RACuj", "d85a9", "qaofN", "kZANm", "jtn0X", + "lpF6W", "suY4x", "rz7Ut", "wDajX", "1v5hH", "Yw2oU", "ksJby", "WMiS3", "lj07Q", "EdBKc", + "6AFT0", "0YAGH", "ThjNn", "JKWYR", "9iGoT", "UmaEv", "3weIF", "CdyBV", "pAhR1", "djsrv", + "xReec", "8FmFH", "Dz1R3", "Ta8f6", "DG4sT", "VjCZq", "jSjS3", "Pb1pa", "VNCPd", "Kr8ys", + "AXpwE", "ZzJHW", "Nxx9V", "jzUqR", "dhSuH", "DQimp", "07n1c", "HP433", "RzaZA", "cL0aE", + "Ss0Zu", "FnPFB", "7lUXZ", "9rlg9", "lH1kt", "ni2v1", "48cHL", "soy9t", "WPmlx", "2Nslm", + "hSSvQ", "9y4lw", "ulk41", "ECMvU", "DLhzM", "GrDg7", "x3LDe", "QChxs", "xXTI4", "Gv3Fq", + "rhl0J", "QssNC", "brhlQ", "s93Ml", "tl72W", "pvgjS", "Qworu", "DcpWB", "X6Pin", "J2mQi", + "BGaQY", "CqqaD", "NhXdu", "dQ586", "Yh1hF", "HRxd8", "PYBf4", "64s8N", "tvdkD", "azIWp", + "tAOsr", "v8yFN", "h1zcH", "SmGzv", "bZLvS", "fFDrJ", "Oz8yZ", "0Wr5y", "fcJOy", "7ku1p", + "QbxXc", "VerEA", "QWxoT", "hYBCK", "o8Uyd", "FwEJz", "hi5X7", "uAWyp", "I7p2a", "M6qcG", + "gIYvE", "HzZT8", "iB08l", "StlDJ", "tjQxs", "k85Ae", "taOXK", "s4786", "2DREs", "atef2", + "Vprf2", "VBjhz", "EoToP", "blLA9", "qUJMd", "ydG8U", "8xEKz", "uLtKs", "GSQwj", "S2Dfu", + "ciuWz", "i3pyd", "7Ow5C", "IRh48", "vOqCE", "Q6hMC", "yofH3", "KsjRK", "5IhmG", "fqypy", + "0MR5X", "Chuy3" }; + + private static int _i = 0; + private static int _j = 0; + + static + { + Arrays.sort(KEYS); + } + + public static String getNextKey() + { + if(_j == KEYS.length) + { + _j = 0; + _i++; + if(_i == KEYS.length) + { + _i = 0; + } + } + return new StringBuffer().append(KEYS[_i]).append("-").append(KEYS[_j++]).toString(); + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/TimeToLiveTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/TimeToLiveTest.java new file mode 100644 index 0000000000..e606df3f7d --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/queue/TimeToLiveTest.java @@ -0,0 +1,397 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.queue; + +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TopicSubscriber; +import javax.naming.NamingException; + +import org.apache.log4j.Logger; +import org.junit.Assert; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class TimeToLiveTest extends QpidBrokerTestCase +{ + private static final Logger _logger = Logger.getLogger(TimeToLiveTest.class); + + protected final String QUEUE = "TimeToLiveQueue"; + + private final long TIME_TO_LIVE = 100L; + + private static final int MSG_COUNT = 50; + private static final long SERVER_TTL_TIMEOUT = 60000L; + + public void testPassiveTTLWithPrefetch() throws Exception + { + doTestPassiveTTL(true); + } + + public void testPassiveTTL() throws Exception + { + doTestPassiveTTL(false); + + } + + private void doTestPassiveTTL(boolean prefetchMessages) throws JMSException, NamingException + { + //Create Client 1 + Connection clientConnection = getConnection(); + + Session clientSession = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = clientSession.createQueue(QUEUE); + + // Create then close the consumer so the queue is actually created + // Closing it then reopening it ensures that the consumer shouldn't get messages + // which should have expired and allows a shorter sleep period. See QPID-1418 + + MessageConsumer consumer = clientSession.createConsumer(queue); + consumer.close(); + + //Create Producer + Connection producerConnection = getConnection(); + + producerConnection.start(); + + // Move to a Transacted session to ensure that all messages have been delivered to broker before + // we start waiting for TTL + Session producerSession = producerConnection.createSession(true, Session.SESSION_TRANSACTED); + + MessageProducer producer = producerSession.createProducer(queue); + + consumer = clientSession.createConsumer(queue); + if(prefetchMessages) + { + clientConnection.start(); + } + + //Set TTL + int msg = 0; + producer.send(nextMessage(String.valueOf(msg), true, producerSession, producer)); + + producer.setTimeToLive(TIME_TO_LIVE); + + for (; msg < MSG_COUNT - 2; msg++) + { + producer.send(nextMessage(String.valueOf(msg), false, producerSession, producer)); + } + + //Reset TTL + producer.setTimeToLive(0L); + producer.send(nextMessage(String.valueOf(msg), false, producerSession, producer)); + + producerSession.commit(); + + + // Ensure we sleep the required amount of time. + ReentrantLock waitLock = new ReentrantLock(); + Condition wait = waitLock.newCondition(); + final long MILLIS = 1000000L; + + long waitTime = TIME_TO_LIVE * MILLIS; + while (waitTime > 0) + { + try + { + waitLock.lock(); + + waitTime = wait.awaitNanos(waitTime); + } + catch (InterruptedException e) + { + //Stop if we are interrupted + fail(e.getMessage()); + } + finally + { + waitLock.unlock(); + } + + } + + if(prefetchMessages) + { + clientConnection.close(); + clientConnection = getConnection(); + + clientSession = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + queue = clientSession.createQueue(QUEUE); + consumer = clientSession.createConsumer(queue); + } + + clientConnection.start(); + + //Receive Message 0 + // Set 5s receive time for messages we expect to receive. + Message receivedFirst = consumer.receive(5000); + Message receivedSecond = consumer.receive(5000); + Message receivedThird = consumer.receive(1000); + + // Log the messages to help diagnosis incase of failure + _logger.info("First:"+receivedFirst); + _logger.info("Second:"+receivedSecond); + _logger.info("Third:"+receivedThird); + + // Only first and last messages sent should survive expiry + Assert.assertNull("More messages received", receivedThird); + + Assert.assertNotNull("First message not received", receivedFirst); + Assert.assertTrue("First message doesn't have first set.", receivedFirst.getBooleanProperty("first")); + Assert.assertEquals("First message has incorrect TTL.", 0L, receivedFirst.getLongProperty("TTL")); + + Assert.assertNotNull("Final message not received", receivedSecond); + Assert.assertFalse("Final message has first set.", receivedSecond.getBooleanProperty("first")); + Assert.assertEquals("Final message has incorrect TTL.", 0L, receivedSecond.getLongProperty("TTL")); + + clientConnection.close(); + + producerConnection.close(); + } + + private Message nextMessage(String msg, boolean first, Session producerSession, MessageProducer producer) throws JMSException + { + Message send = producerSession.createTextMessage("Message " + msg); + send.setBooleanProperty("first", first); + send.setStringProperty("testprop", "TimeToLiveTest"); + send.setLongProperty("TTL", producer.getTimeToLive()); + return send; + } + + + /** + * Tests the expired messages get actively deleted even on queues which have no consumers + * @throws Exception + */ + public void testActiveTTL() throws Exception + { + Connection producerConnection = getConnection(); + AMQSession producerSession = (AMQSession) producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = producerSession.createTemporaryQueue(); + producerSession.declareAndBind((AMQDestination) queue); + MessageProducer producer = producerSession.createProducer(queue); + producer.setTimeToLive(1000L); + + // send Messages + for(int i = 0; i < MSG_COUNT; i++) + { + producer.send(producerSession.createTextMessage("Message: "+i)); + } + long failureTime = System.currentTimeMillis() + 2 * SERVER_TTL_TIMEOUT; + + // check Queue depth for up to TIMEOUT seconds after the Queue Depth hasn't changed for 100ms. + long messageCount = MSG_COUNT; + long lastPass; + + do + { + lastPass = messageCount; + Thread.sleep(100); + messageCount = producerSession.getQueueDepth((AMQDestination) queue); + + // If we have received messages in the last loop then extend the timeout time. + // if we get messages stuck that are not expiring then the failureTime will occur + // failing the test. This will help with the scenario when the broker does not + // have enough CPU cycles to process the TTLs. + if (lastPass != messageCount) + { + failureTime = System.currentTimeMillis() + 2 * SERVER_TTL_TIMEOUT; + } + } + while(messageCount > 0L && System.currentTimeMillis() < failureTime); + + assertEquals("Messages not automatically expired: ", 0L, messageCount); + + producer.close(); + producerSession.close(); + producerConnection.close(); + } + + public void testPassiveTTLwithDurableSubscription() throws Exception + { + //Create Client 1 + Connection clientConnection = getConnection(); + + Session clientSession = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // Create and close the durable subscriber + AMQTopic topic = new AMQTopic((AMQConnection) clientConnection, getTestQueueName()); + TopicSubscriber durableSubscriber = clientSession.createDurableSubscriber(topic, getTestQueueName(),"testprop='TimeToLiveTest'", false); + durableSubscriber.close(); + + //Create Producer + Connection producerConnection = getConnection(); + + producerConnection.start(); + + // Move to a Transacted session to ensure that all messages have been delivered to broker before + // we start waiting for TTL + Session producerSession = producerConnection.createSession(true, Session.SESSION_TRANSACTED); + + MessageProducer producer = producerSession.createProducer(topic); + + //Set TTL + int msg = 0; + producer.send(nextMessage(String.valueOf(msg), true, producerSession, producer)); + + producer.setTimeToLive(TIME_TO_LIVE); + + for (; msg < MSG_COUNT - 2; msg++) + { + producer.send(nextMessage(String.valueOf(msg), false, producerSession, producer)); + } + + //Reset TTL + producer.setTimeToLive(0L); + producer.send(nextMessage(String.valueOf(msg), false, producerSession, producer)); + + producerSession.commit(); + + //resubscribe + durableSubscriber = clientSession.createDurableSubscriber(topic, getTestQueueName(),"testprop='TimeToLiveTest'", false); + + // Ensure we sleep the required amount of time. + ReentrantLock waitLock = new ReentrantLock(); + Condition wait = waitLock.newCondition(); + final long MILLIS = 1000000L; + + long waitTime = TIME_TO_LIVE * MILLIS; + while (waitTime > 0) + { + try + { + waitLock.lock(); + + waitTime = wait.awaitNanos(waitTime); + } + catch (InterruptedException e) + { + //Stop if we are interrupted + fail(e.getMessage()); + } + finally + { + waitLock.unlock(); + } + + } + + clientConnection.start(); + + //Receive Message 0 + // Set 5s receive time for messages we expect to receive. + Message receivedFirst = durableSubscriber.receive(5000); + Message receivedSecond = durableSubscriber.receive(5000); + Message receivedThird = durableSubscriber.receive(1000); + + // Log the messages to help diagnosis incase of failure + _logger.info("First:"+receivedFirst); + _logger.info("Second:"+receivedSecond); + _logger.info("Third:"+receivedThird); + + // Only first and last messages sent should survive expiry + Assert.assertNull("More messages received", receivedThird); + + Assert.assertNotNull("First message not received", receivedFirst); + Assert.assertTrue("First message doesn't have first set.", receivedFirst.getBooleanProperty("first")); + Assert.assertEquals("First message has incorrect TTL.", 0L, receivedFirst.getLongProperty("TTL")); + + Assert.assertNotNull("Final message not received", receivedSecond); + Assert.assertFalse("Final message has first set.", receivedSecond.getBooleanProperty("first")); + Assert.assertEquals("Final message has incorrect TTL.", 0L, receivedSecond.getLongProperty("TTL")); + + clientSession.unsubscribe(getTestQueueName()); + clientConnection.close(); + + producerConnection.close(); + } + + public void testActiveTTLwithDurableSubscription() throws Exception + { + //Create Client 1 + Connection clientConnection = getConnection(); + Session clientSession = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // Create and close the durable subscriber + AMQTopic topic = new AMQTopic((AMQConnection) clientConnection, getTestQueueName()); + TopicSubscriber durableSubscriber = clientSession.createDurableSubscriber(topic, "MyDurableTTLSubscription","testprop='TimeToLiveTest'", false); + durableSubscriber.close(); + + //Create Producer + Connection producerConnection = getConnection(); + AMQSession producerSession = (AMQSession) producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = producerSession.createProducer(topic); + producer.setTimeToLive(1000L); + + // send Messages + for(int i = 0; i < MSG_COUNT; i++) + { + producer.send(producerSession.createTextMessage("Message: "+i)); + } + long failureTime = System.currentTimeMillis() + 2 * SERVER_TTL_TIMEOUT; + + // check Queue depth for up to TIMEOUT seconds after the Queue Depth hasn't changed for 100ms. + long messageCount = MSG_COUNT; + long lastPass; + AMQQueue subcriptionQueue = new AMQQueue("amq.topic","clientid" + ":" + "MyDurableTTLSubscription"); + do + { + lastPass = messageCount; + Thread.sleep(100); + messageCount = producerSession.getQueueDepth((AMQDestination) subcriptionQueue); + + // If we have received messages in the last loop then extend the timeout time. + // if we get messages stuck that are not expiring then the failureTime will occur + // failing the test. This will help with the scenario when the broker does not + // have enough CPU cycles to process the TTLs. + if (lastPass != messageCount) + { + failureTime = System.currentTimeMillis() + 2 * SERVER_TTL_TIMEOUT; + } + } + while(messageCount > 0L && System.currentTimeMillis() < failureTime); + + assertEquals("Messages not automatically expired: ", 0L, messageCount); + + producer.close(); + producerSession.close(); + producerConnection.close(); + + clientSession.unsubscribe("MyDurableTTLSubscription"); + clientSession.close(); + clientConnection.close(); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java new file mode 100644 index 0000000000..789ad420d8 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.acl; + +import org.apache.commons.lang.StringUtils; +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQConnectionURL; +import org.apache.qpid.jms.ConnectionListener; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.url.URLSyntaxException; + +import javax.jms.Connection; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.naming.NamingException; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * Abstract test case for ACLs. + * + * This base class contains convenience methods to manage ACL files and implements a mechanism that allows each + * test method to run its own setup code before the broker starts. + * + * @see ExternalACLTest + * @see ExternalACLJMXTest + * @see ExhaustiveACLTest + */ +public abstract class AbstractACLTestCase extends QpidBrokerTestCase implements ConnectionListener +{ + /** Used to synchronise {@link #tearDown()} when exceptions are thrown */ + protected CountDownLatch _exceptionReceived; + + @Override + public void setUp() throws Exception + { + getBrokerConfiguration().addGroupFileConfiguration(System.getProperty(QPID_HOME) + "/etc/groups-systests"); + + // run test specific setup + String testSetup = StringUtils.replace(getName(), "test", "setUp"); + try + { + Method setup = getClass().getDeclaredMethod(testSetup); + setup.invoke(this); + } + catch (NoSuchMethodException e) + { + // Ignore + } + catch (InvocationTargetException e) + { + throw (Exception) e.getTargetException(); + } + + super.setUp(); + } + + @Override + public void tearDown() throws Exception + { + try + { + super.tearDown(); + } + catch (JMSException e) + { + //we're throwing this away as it can happen in this test as the state manager remembers exceptions + //that we provoked with authentication failures, where the test passes - we can ignore on con close + } + } + + public void writeACLFile(final String...rules) throws IOException + { + writeACLFileUtil(this, rules); + } + + public static void writeACLFileUtil(QpidBrokerTestCase testcase, String...rules) throws IOException + { + File aclFile = File.createTempFile(testcase.getClass().getSimpleName(), testcase.getName()); + aclFile.deleteOnExit(); + + testcase.getBrokerConfiguration().addAclFileConfiguration(aclFile.getAbsolutePath()); + + PrintWriter out = new PrintWriter(new FileWriter(aclFile)); + out.println(String.format("# %s", testcase.getName())); + for (String line : rules) + { + out.println(line); + } + out.close(); + } + + /** + * Creates a connection to the broker, and sets a connection listener to prevent failover and an exception listener + * with a {@link CountDownLatch} to synchronise in the {@link #check403Exception(Throwable)} method and allow the + * {@link #tearDown()} method to complete properly. + */ + public Connection getConnection(String vhost, String username, String password) throws NamingException, JMSException, URLSyntaxException + { + AMQConnection connection = (AMQConnection) getConnection(createConnectionURL(vhost, username, password)); + + //Prevent Failover + connection.setConnectionListener(this); + + //QPID-2081: use a latch to sync on exception causing connection close, to work + //around the connection close race during tearDown() causing sporadic failures + _exceptionReceived = new CountDownLatch(1); + + connection.setExceptionListener(new ExceptionListener() + { + public void onException(JMSException e) + { + _exceptionReceived.countDown(); + } + }); + + return (Connection) connection; + } + + // Connection Listener Interface - Used here to block failover + + public void bytesSent(long count) + { + } + + public void bytesReceived(long count) + { + } + + public boolean preFailover(boolean redirect) + { + //Prevent failover. + return false; + } + + public boolean preResubscribe() + { + return false; + } + + public void failoverComplete() + { + } + + /** + * Convenience method to build an {@link AMQConnectionURL} with the right parameters. + */ + public AMQConnectionURL createConnectionURL(String vhost, String username, String password) throws URLSyntaxException + { + String url = "amqp://" + username + ":" + password + "@clientid/" + vhost + "?brokerlist='" + getBroker() + "?retries='0''"; + return new AMQConnectionURL(url); + } + + /** + * Convenience method to validate a JMS exception with a linked {@link AMQConstant#ACCESS_REFUSED} 403 error code exception. + */ + public void check403Exception(Throwable t) throws Exception + { + assertNotNull("There was no linked exception", t); + assertTrue("Wrong linked exception type : " + t.getClass(), t instanceof AMQException); + assertEquals("Incorrect error code received", 403, ((AMQException) t).getErrorCode().getCode()); + + //use the latch to ensure the control thread waits long enough for the exception thread + //to have done enough to mark the connection closed before teardown commences + assertTrue("Timed out waiting for conneciton to report close", _exceptionReceived.await(2, TimeUnit.SECONDS)); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/security/acl/ExhaustiveACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/security/acl/ExhaustiveACLTest.java new file mode 100644 index 0000000000..505b3035d3 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/security/acl/ExhaustiveACLTest.java @@ -0,0 +1,216 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.acl; + +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.protocol.AMQConstant; + +/** + * ACL version 2/3 file testing to verify that ACL entries control queue creation with specific properties. + * + * Tests have their own ACL files that setup specific permissions, and then try to create queues with every possible combination + * of properties to show that rule matching works correctly. For example, a rule that specified {@code autodelete="true"} for + * queues with {@code name="temp.true.*"} as well should not affect queues that have names that do not match, or queues that + * are not autodelete, or both. Also checks that ACL entries only affect the specified users and virtual hosts. + */ +public class ExhaustiveACLTest extends AbstractACLTestCase +{ + + /** + * Creates a queue. + * + * Connects to the broker as a particular user and create the named queue on a virtual host, with the provided + * parameters. Uses a new {@link Connection} and {@link Session} and closes them afterwards. + */ + private void createQueue(String vhost, String user, String name, boolean autoDelete, boolean durable) throws Exception + { + Connection conn = getConnection(vhost, user, "guest"); + Session sess = conn.createSession(true, Session.SESSION_TRANSACTED); + conn.start(); + ((AMQSession) sess).createQueue(new AMQShortString(name), autoDelete, durable, false); + sess.commit(); + conn.close(); + } + + /** + * Calls {@link #createQueue(String, String, String, boolean, boolean)} with the provided parameters and checks that + * no exceptions were thrown. + */ + private void createQueueSuccess(String vhost, String user, String name, boolean autoDelete, boolean durable) throws Exception + { + try + { + createQueue(vhost, user, name, autoDelete, durable); + } + catch (AMQException e) + { + fail(String.format("Create queue should have worked for \"%s\" for user %s@%s, autoDelete=%s, durable=%s", + name, user, vhost, Boolean.toString(autoDelete), Boolean.toString(durable))); + } + } + + /** + * Calls {@link #createQueue(String, String, String, boolean, boolean)} with the provided parameters and checks that + * the exception thrown was an {@link AMQConstant#ACCESS_REFUSED} or 403 error code. + */ + private void createQueueFailure(String vhost, String user, String name, boolean autoDelete, boolean durable) throws Exception + { + try + { + createQueue(vhost, user, name, autoDelete, durable); + fail(String.format("Create queue should have failed for \"%s\" for user %s@%s, autoDelete=%s, durable=%s", + name, user, vhost, Boolean.toString(autoDelete), Boolean.toString(durable))); + } + catch (AMQException e) + { + assertEquals("Should be an ACCESS_REFUSED error", 403, e.getErrorCode().getCode()); + } + } + + public void setUpAuthoriseCreateQueueAutodelete() throws Exception + { + writeACLFile("acl allow client access virtualhost", + "acl allow server access virtualhost", + "acl allow client create queue name=\"temp.true.*\" autodelete=true", + "acl allow client create queue name=\"temp.false.*\" autodelete=false", + "acl deny client create queue", + "acl allow client delete queue", + "acl deny all create queue" + ); + } + + /** + * Test creation of temporary queues, with the autodelete property set to true. + */ + public void testAuthoriseCreateQueueAutodelete() throws Exception + { + createQueueSuccess("test", "client", "temp.true.00", true, false); + createQueueSuccess("test", "client", "temp.true.01", true, false); + createQueueSuccess("test", "client", "temp.true.02", true, true); + createQueueSuccess("test", "client", "temp.false.03", false, false); + createQueueSuccess("test", "client", "temp.false.04", false, false); + createQueueSuccess("test", "client", "temp.false.05", false, true); + createQueueFailure("test", "client", "temp.true.06", false, false); + createQueueFailure("test", "client", "temp.false.07", true, false); + createQueueFailure("test", "server", "temp.true.08", true, false); + createQueueFailure("test", "client", "temp.other.09", false, false); + } + + + public void setUpAuthoriseQueueAutodeleteDeleteByOther() throws Exception + { + writeACLFile("acl allow client access virtualhost", + "acl allow server access virtualhost", + "acl allow client create queue name=\"temp.true.*\" autodelete=true", + "acl allow server consume queue name=\"temp.true.*\"", + "acl allow server bind exchange", + "acl deny client create queue", + "acl allow client delete queue", + "acl deny all create queue" + ); + } + /** + * Test creation of temporary queues, with the autodelete property and then autodeleted. + */ + public void testAuthoriseQueueAutodeleteDeleteByOther() throws Exception + { + // stop the consumer trying to redeclare the queue + setTestSystemProperty(ClientProperties.QPID_DECLARE_QUEUES_PROP_NAME, "false"); + + // create a temp queue as use client + createQueueSuccess("test", "client", "temp.true.00", true, false); + + // consume from temp queue as user server + Connection conn = getConnection("test", "server", "guest"); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + Queue queue = sess.createQueue("temp.true.00"); + MessageConsumer cons = sess.createConsumer(queue); + cons.close(); + sess.close(); + + sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + + // test if the queue is bound to the default exchange + assertFalse(((AMQSession)sess).isQueueBound("","temp.true.00","temp.true.00",null)); + sess.close(); + + conn.close(); + + + } + + public void setUpAuthoriseCreateQueue() throws Exception + { + writeACLFile("acl allow client access virtualhost", + "acl allow server access virtualhost", + "acl allow client create queue name=\"create.*\"" + ); + } + + /** + * Tests creation of named queues. + * + * If a named queue is specified + */ + public void testAuthoriseCreateQueue() throws Exception + { + createQueueSuccess("test", "client", "create.00", true, true); + createQueueSuccess("test", "client", "create.01", true, false); + createQueueSuccess("test", "client", "create.02", false, true); + createQueueSuccess("test", "client", "create.03", true, false); + createQueueFailure("test", "server", "create.04", true, true); + createQueueFailure("test", "server", "create.05", true, false); + createQueueFailure("test", "server", "create.06", false, true); + createQueueFailure("test", "server", "create.07", true, false); + } + + public void setUpAuthoriseCreateQueueBoth() throws Exception + { + writeACLFile("acl allow all access virtualhost", + "acl allow client create queue name=\"create.*\"", + "acl allow all create queue temporary=true" + ); + } + + /** + * Tests creation of named queues. + * + * If a named queue is specified + */ + public void testAuthoriseCreateQueueBoth() throws Exception + { + createQueueSuccess("test", "client", "create.00", true, false); + createQueueSuccess("test", "client", "create.01", false, false); + createQueueFailure("test", "server", "create.02", false, false); + createQueueFailure("test", "guest", "create.03", false, false); + createQueueSuccess("test", "client", "tmp.00", true, false); + createQueueSuccess("test", "server", "tmp.01", true, false); + createQueueSuccess("test", "guest", "tmp.02", true, false); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java new file mode 100644 index 0000000000..165fbed00c --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java @@ -0,0 +1,320 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.acl; + +import org.apache.qpid.management.common.mbeans.ServerInformation; +import org.apache.qpid.server.security.access.ObjectType; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; + +/** + * Tests that access to the JMX interface is governed only by {@link ObjectType#METHOD}/{@link ObjectType#ALL} + * rules and AMQP rights have no effect. + * + * Ensures that objects outside the Qpid domain are not governed by the ACL model. + */ +public class ExternalACLJMXTest extends AbstractACLTestCase +{ + + private JMXTestUtils _jmx; + + private static final String TEST_QUEUE_OWNER = "admin"; + private static final String TEST_VHOST = "test"; + private static final String TEST2_VHOST = "test2"; + + @Override + public void setUp() throws Exception + { + //remove the normal 'test' vhost, we will configure the vhosts below + getBrokerConfiguration(0).removeObjectConfiguration(org.apache.qpid.server.model.VirtualHostNode.class, TestBrokerConfiguration.ENTRY_NAME_VIRTUAL_HOST); + + createTestVirtualHostNode(0, TEST_VHOST); + createTestVirtualHostNode(0, TEST2_VHOST); + + getBrokerConfiguration().addJmxManagementConfiguration(); + + _jmx = new JMXTestUtils(this); + super.setUp(); + _jmx.open(); + } + + @Override + public void tearDown() throws Exception + { + _jmx.close(); + super.tearDown(); + } + + public void setUpDenyAllIsCatchAllRule() throws Exception + { + writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", + "#No more rules, default catch all (deny all) should apply"); + } + + public void testDenyAllIsCatchAllRule() throws Exception + { + //try a broker-level method + ServerInformation info = _jmx.getServerInformation(); + try + { + info.resetStatistics(); + fail("Exception not thrown"); + } + catch (SecurityException e) + { + assertEquals("Cause message incorrect", "Permission denied: UPDATE resetStatistics", e.getMessage()); + } + + //try a vhost-level method + try + { + _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true); + fail("Exception not thrown"); + } + catch (Exception e) + { + assertEquals("Cause message incorrect", "Permission denied: UPDATE createNewQueue", e.getMessage()); + } + + // Ensure that calls to MBeans outside the Qpid domain are not impeded. + final RuntimeMXBean runtimeBean = _jmx.getManagedObject(RuntimeMXBean.class, ManagementFactory.RUNTIME_MXBEAN_NAME); + runtimeBean.getName(); + // PASS + } + + /** + * Ensure an ALLOW ALL ALL rule allows access to both getters/setters. + */ + public void setUpAllowAll() throws Exception + { + writeACLFile("ACL ALLOW ALL ALL"); + } + + public void testAllowAll() throws Exception + { + ServerInformation info = _jmx.getServerInformation(); + info.getBuildVersion(); // getter - requires ACCESS + info.resetStatistics(); // setter - requires UPDATE + // PASS + } + + public void setUpVhostWithName() throws Exception + { + writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", + "ACL ALLOW admin UPDATE METHOD component='VirtualHost.VirtualHostManager' name='createNewQueue' virtualhost_name='"+ TEST_VHOST + "'", + "ACL DENY admin UPDATE METHOD component='VirtualHost.VirtualHostManager' name='createNewQueue' virtualhost_name='"+ TEST2_VHOST + "'"); + } + + public void testVhostWithName() throws Exception + { + _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true); + + try + { + _jmx.createQueue(TEST2_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true); + fail("Exception not thrown"); + } + catch (SecurityException e) + { + assertEquals("Cause message incorrect", "Permission denied: UPDATE createNewQueue", e.getMessage()); + } + } + + + /** + * admin user is allowed all update methods on the component at broker level. + */ + public void setUpUpdateComponentOnlyAllow() throws Exception + { + writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", + "ACL ALLOW admin UPDATE METHOD component='VirtualHost.VirtualHostManager'"); + } + + public void testUpdateComponentOnlyAllow() throws Exception + { + _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true); + // PASS + _jmx.deleteQueue(TEST_VHOST, getTestQueueName()); + // PASS + } + + + /** + * admin user is allowed all update methods on all components at broker level. + */ + public void setUpUpdateMethodOnlyAllow() throws Exception + { + writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", + "ACL ALLOW admin UPDATE METHOD"); + } + + public void testUpdateMethodOnlyAllow() throws Exception + { + _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true); + //PASS + _jmx.deleteQueue(TEST_VHOST, getTestQueueName()); + // PASS + } + + + /** + * admin user has JMX right, AMQP right is irrelevant. + */ + public void setUpCreateQueueSuccess() throws Exception + { + writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", + "ACL ALLOW admin UPDATE METHOD component='VirtualHost.VirtualHostManager' name='createNewQueue'"); + } + + public void testCreateQueueSuccess() throws Exception + { + _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true); + } + + + /** + * admin user has JMX right, verifies lack of AMQP rights is irrelevant. + */ + public void setUpCreateQueueSuccessNoAMQPRights() throws Exception + { + writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", + "ACL ALLOW admin UPDATE METHOD component='VirtualHost.VirtualHostManager' name='createNewQueue'", + "ACL DENY admin CREATE QUEUE"); + } + + public void testCreateQueueSuccessNoAMQPRights() throws Exception + { + _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true); + } + + + /** + * admin user does not have JMX right, AMQP right is irrelevant. + */ + public void setUpCreateQueueDenied() throws Exception + { + writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", + "ACL DENY admin UPDATE METHOD component='VirtualHost.VirtualHostManager' name='createNewQueue'"); + } + + public void testCreateQueueDenied() throws Exception + { + try + { + _jmx.createQueue(TEST_VHOST, getTestQueueName(), TEST_QUEUE_OWNER, true); + fail("Exception not thrown"); + } + catch (SecurityException e) + { + assertEquals("Cause message incorrect", "Permission denied: UPDATE createNewQueue", e.getMessage()); + } + } + + + /** + * admin user does not have JMX right + */ + public void setUpServerInformationUpdateDenied() throws Exception + { + writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", + "ACL DENY admin UPDATE METHOD component='ServerInformation' name='resetStatistics'"); + } + + public void testServerInformationUpdateDenied() throws Exception + { + ServerInformation info = _jmx.getServerInformation(); + try + { + info.resetStatistics(); + fail("Exception not thrown"); + } + catch (SecurityException e) + { + assertEquals("Cause message incorrect", "Permission denied: UPDATE resetStatistics", e.getMessage()); + } + } + + + /** + * admin user has JMX right to check management API major version (but not minor version) + */ + public void setUpServerInformationAccessGranted() throws Exception + { + writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", + "ACL ALLOW-LOG admin ACCESS METHOD component='ServerInformation' name='getManagementApiMajorVersion'"); + } + + public void testServerInformationAccessGranted() throws Exception + { + ServerInformation info = _jmx.getServerInformation(); + info.getManagementApiMajorVersion(); + + try + { + info.getManagementApiMinorVersion(); + fail("Exception not thrown"); + } + catch (SecurityException e) + { + assertEquals("Cause message incorrect", "Permission denied: ACCESS getManagementApiMinorVersion", e.getMessage()); + } + } + + + /** + * admin user has JMX right to use the update method + */ + public void setUpServerInformationUpdateMethodPermission() throws Exception + { + writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", + "ACL ALLOW admin UPDATE METHOD component='ServerInformation' name='resetStatistics'"); + } + + public void testServerInformationUpdateMethodPermission() throws Exception + { + ServerInformation info = _jmx.getServerInformation(); + info.resetStatistics(); + // PASS + } + + + /** + * admin user has JMX right to use all types of method on ServerInformation + */ + public void setUpServerInformationAllMethodPermissions() throws Exception + { + writeACLFile("ACL ALLOW admin ACCESS MANAGEMENT", + "ACL ALLOW admin ALL METHOD component='ServerInformation'"); + } + + public void testServerInformationAllMethodPermissions() throws Exception + { + //try an update method + ServerInformation info = _jmx.getServerInformation(); + info.resetStatistics(); + // PASS + //try an access method + info.getManagementApiMinorVersion(); + // PASS + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/security/acl/ExternalACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/security/acl/ExternalACLTest.java new file mode 100644 index 0000000000..0e8f3cb7d8 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/security/acl/ExternalACLTest.java @@ -0,0 +1,487 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.acl; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.jms.TopicSubscriber; +import javax.naming.NamingException; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.url.URLSyntaxException; + +/** + * Tests the V2 ACLs. The tests perform basic AMQP operations like creating queues or exchanges and publishing and consuming messages, using + * JMS to contact the broker. + */ +public class ExternalACLTest extends AbstractACLTestCase +{ + + public void setUpAccessAuthorizedSuccess() throws Exception + { + writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST"); + } + + public void testAccessAuthorizedSuccess() throws Exception + { + Connection conn = getConnection("test", "client", "guest"); + conn.close(); + } + + public void setUpAccessNoRightsFailure() throws Exception + { + writeACLFile("ACL DENY-LOG client ACCESS VIRTUALHOST"); + } + + public void testAccessNoRightsFailure() throws Exception + { + try + { + getConnection("test", "client", "guest"); + fail("Connection was created."); + } + catch (JMSException e) + { + assertAccessDeniedException(e); + } + } + + private void assertAccessDeniedException(JMSException e) + { + assertEquals("Unexpected exception message", "Error creating connection: Permission denied: test", e.getMessage()); + + // JMSException -> linkedException -> cause = AMQException (403 or 320) + Exception linkedException = e.getLinkedException(); + assertNotNull("There was no linked exception", linkedException); + Throwable cause = linkedException.getCause(); + assertNotNull("Cause was null", cause); + assertTrue("Wrong linked exception type", cause instanceof AMQException); + AMQConstant errorCode = isBroker010() ? AMQConstant.CONNECTION_FORCED : AMQConstant.ACCESS_REFUSED; + assertEquals("Incorrect error code received", errorCode, ((AMQException) cause).getErrorCode()); + } + + public void setUpAccessVirtualHostWithName() throws Exception + { + writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST name='test'", "ACL DENY-LOG guest ACCESS VIRTUALHOST name='test'", + "ACL ALLOW-LOG server ACCESS VIRTUALHOST name='*'"); + } + + public void testAccessVirtualHostWithName() throws Exception + { + Connection conn = getConnection("test", "client", "guest"); + conn.close(); + + try + { + getConnection("test", "guest", "guest"); + fail("Access should be denied"); + } + catch (JMSException e) + { + assertAccessDeniedException(e); + } + + Connection conn2 = getConnection("test", "server", "guest"); + conn2.close(); + } + + public void setUpClientCreateVirtualHostQueue() throws Exception + { + writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", + "ACL ALLOW-LOG client CREATE QUEUE virtualhost_name='test'", + "ACL ALLOW-LOG client CONSUME QUEUE", + "ACL ALLOW-LOG client BIND EXCHANGE", + "ACL ALLOW-LOG guest ACCESS VIRTUALHOST", + "ACL DENY-LOG guest CREATE QUEUE virtualhost_name='test'"); + } + + public void testClientCreateVirtualHostQueue() throws NamingException, JMSException, AMQException, Exception + { + Connection conn = getConnection("test", "client", "guest"); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination dest = sess.createQueue(getTestQueueName()); + sess.createConsumer(dest); + conn.close(); + + try + { + conn = getConnection("test", "guest", "guest"); + sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + sess.createConsumer(dest); + + fail("Queue creation for user 'guest' is denied"); + } + catch (JMSException e) + { + check403Exception(e.getLinkedException()); + } + } + + + public void setUpClientDeleteQueueSuccess() throws Exception + { + writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", + "ACL ALLOW-LOG client CREATE QUEUE durable=\"true\"", + "ACL ALLOW-LOG client CONSUME QUEUE name=\"clientid:kipper\"" , + "ACL ALLOW-LOG client BIND EXCHANGE name=\"amq.topic\" durable=true routingKey=kipper", + "ACL ALLOW-LOG client DELETE QUEUE durable=\"true\"", + "ACL ALLOW-LOG client UNBIND EXCHANGE name=\"amq.topic\" durable=true routingKey=kipper"); + } + + public void testClientDeleteQueueSuccess() throws Exception + { + Connection conn = getConnection("test", "client", "guest"); + Session sess = conn.createSession(true, Session.SESSION_TRANSACTED); + conn.start(); + + // create kipper + Topic kipper = sess.createTopic("kipper"); + TopicSubscriber subscriber = sess.createDurableSubscriber(kipper, "kipper"); + + subscriber.close(); + sess.unsubscribe("kipper"); + + //Do something to show connection is active. + sess.rollback(); + conn.close(); + } + + + public void setUpClientDeleteQueueFailure() throws Exception + { + writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", + "ACL ALLOW-LOG client CREATE QUEUE durable=\"true\"", + "ACL ALLOW-LOG client CONSUME QUEUE name=\"clientid:kipper\"" , + "ACL ALLOW-LOG client BIND EXCHANGE name=\"amq.topic\" durable=true routingKey=kipper", + "ACL DENY-LOG client DELETE QUEUE durable=\"true\"", + "ACL DENY-LOG client UNBIND EXCHANGE name=\"amq.topic\" durable=true routingKey=kipper"); + } + + public void testClientDeleteQueueFailure() throws Exception + { + Connection conn = getConnection("test", "client", "guest"); + Session sess = conn.createSession(true, Session.SESSION_TRANSACTED); + conn.start(); + + // create kipper + Topic kipper = sess.createTopic("kipper"); + TopicSubscriber subscriber = sess.createDurableSubscriber(kipper, "kipper"); + + subscriber.close(); + try + { + sess.unsubscribe("kipper"); + + //Do something to show connection is active. + sess.rollback(); + + fail("Exception was not thrown"); + } + catch (JMSException e) + { + // JMSException -> linedException = AMQException.403 + check403Exception(e.getLinkedException()); + } + } + + + public void testClientConsumeFromTempQueueSuccess() throws Exception + { + Connection conn = getConnection("test", "client", "guest"); + + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + conn.start(); + + sess.createConsumer(sess.createTemporaryQueue()); + } + + public void setUpClientConsumeFromNamedQueueValid() throws Exception + { + writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", + "ACL ALLOW-LOG client CREATE QUEUE name=\"example.RequestQueue\"", + "ACL ALLOW-LOG client CONSUME QUEUE name=\"example.RequestQueue\"" , + "ACL ALLOW-LOG client BIND EXCHANGE name=\"amq.direct\" routingKey=\"example.RequestQueue\""); + } + + + public void testClientConsumeFromNamedQueueValid() throws Exception + { + Connection conn = getConnection("test", "client", "guest"); + + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + conn.start(); + + sess.createConsumer(sess.createQueue("example.RequestQueue")); + } + + public void setUpClientConsumeFromNamedQueueFailure() throws Exception + { + writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", + "ACL ALLOW-LOG client CREATE QUEUE", + "ACL ALLOW-LOG client BIND EXCHANGE" , + "ACL DENY-LOG client CONSUME QUEUE name=\"IllegalQueue\""); + } + + public void testClientConsumeFromNamedQueueFailure() throws NamingException, Exception + { + Connection conn = getConnection("test", "client", "guest"); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + Destination dest = sess.createQueue("IllegalQueue"); + + try + { + sess.createConsumer(dest); + + fail("Test failed as consumer was created."); + } + catch (JMSException e) + { + check403Exception(e.getLinkedException()); + } + } + + public void setUpClientCreateTemporaryQueueSuccess() throws Exception + { + writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", + "ACL ALLOW-LOG client CREATE QUEUE temporary=\"true\"", + "ACL ALLOW-LOG client BIND EXCHANGE name=\"amq.direct\" temporary=true" , + "ACL ALLOW-LOG client DELETE QUEUE temporary=\"true\"", + "ACL ALLOW-LOG client UNBIND EXCHANGE name=\"amq.direct\" temporary=true"); + } + + public void testClientCreateTemporaryQueueSuccess() throws JMSException, URLSyntaxException, Exception + { + Connection conn = getConnection("test", "client", "guest"); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + + sess.createTemporaryQueue(); + conn.close(); + } + + public void setUpClientCreateTemporaryQueueFailed() throws Exception + { + writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", + "ACL DENY-LOG client CREATE QUEUE temporary=\"true\""); + } + + public void testClientCreateTemporaryQueueFailed() throws NamingException, Exception + { + Connection conn = getConnection("test", "client", "guest"); + Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + + try + { + + session.createTemporaryQueue(); + + fail("Test failed as creation succeded."); + } + catch (JMSException e) + { + check403Exception(e.getLinkedException()); + } + } + + public void setUpClientCreateNamedQueueFailure() throws Exception + { + writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", + "ACL ALLOW-LOG client CREATE QUEUE name=\"ValidQueue\""); + } + + public void testClientCreateNamedQueueFailure() throws NamingException, JMSException, AMQException, Exception + { + Connection conn = getConnection("test", "client", "guest"); + Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + conn.start(); + Destination dest = sess.createQueue("IllegalQueue"); + + try + { + //Create a Named Queue as side effect + sess.createConsumer(dest); + fail("Test failed as Queue creation succeded."); + } + catch (JMSException e) + { + check403Exception(e.getLinkedException()); + } + } + + public void setUpClientPublishUsingTransactionSuccess() throws Exception + { + writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", + "ACL ALLOW-LOG client CREATE QUEUE", + "ACL ALLOW-LOG client BIND EXCHANGE" , + "ACL ALLOW-LOG client PUBLISH EXCHANGE name=\"amq.direct\" routingKey=\"example.RequestQueue\""); + } + + public void testClientPublishUsingTransactionSuccess() throws Exception + { + Connection conn = getConnection("test", "client", "guest"); + + Session sess = conn.createSession(true, Session.SESSION_TRANSACTED); + + conn.start(); + + Queue queue = sess.createQueue("example.RequestQueue"); + + ((AMQSession)sess).declareAndBind((AMQDestination)queue); + + MessageProducer sender = sess.createProducer(queue); + + sender.send(sess.createTextMessage("test")); + + //Send the message using a transaction as this will allow us to retrieve any errors that occur on the broker. + sess.commit(); + + conn.close(); + } + + public void setUpRequestResponseSuccess() throws Exception + { + // The group "messaging-users", referenced in the ACL below, is currently defined + // in broker/etc/groups-systests. + // We tolerate a dependency from this test to that file because its + // contents are expected to change rarely. + + writeACLFile("ACL ALLOW-LOG messaging-users ACCESS VIRTUALHOST", "# Server side", + "ACL ALLOW-LOG server CREATE QUEUE name=\"example.RequestQueue\"", + "ACL ALLOW-LOG server BIND EXCHANGE" , + "ACL ALLOW-LOG server PUBLISH EXCHANGE name=\"amq.direct\" routingKey=\"TempQueue*\"", + "ACL ALLOW-LOG server CONSUME QUEUE name=\"example.RequestQueue\"", + "# Client side", + "ACL ALLOW-LOG client PUBLISH EXCHANGE name=\"amq.direct\" routingKey=\"example.RequestQueue\"", + "ACL ALLOW-LOG client CONSUME QUEUE temporary=true", + "ACL ALLOW-LOG client BIND EXCHANGE name=\"amq.direct\" temporary=true", + "ACL ALLOW-LOG client UNBIND EXCHANGE name=\"amq.direct\" temporary=true", + "ACL ALLOW-LOG client CREATE QUEUE temporary=true", + "ACL ALLOW-LOG client DELETE QUEUE temporary=true"); + } + + + public void testRequestResponseSuccess() throws Exception + { + //Set up the Server + Connection serverConnection = getConnection("test", "server", "guest"); + Session serverSession = serverConnection.createSession(true, Session.SESSION_TRANSACTED); + Queue requestQueue = serverSession.createQueue("example.RequestQueue"); + MessageConsumer server = serverSession.createConsumer(requestQueue); + serverConnection.start(); + + //Set up the consumer + Connection clientConnection = getConnection("test", "client", "guest"); + Session clientSession = clientConnection.createSession(true, Session.SESSION_TRANSACTED); + Queue responseQueue = clientSession.createTemporaryQueue(); + MessageConsumer clientResponse = clientSession.createConsumer(responseQueue); + clientConnection.start(); + + // Client + Message request = clientSession.createTextMessage("Request"); + request.setJMSReplyTo(responseQueue); + + clientSession.createProducer(requestQueue).send(request); + clientSession.commit(); + + // Server + Message msg = server.receive(2000); + assertNotNull("Server should have received client's request", msg); + assertNotNull("Received msg should have Reply-To", msg.getJMSReplyTo()); + + MessageProducer sender = serverSession.createProducer(msg.getJMSReplyTo()); + sender.send(serverSession.createTextMessage("Response")); + serverSession.commit(); + + // Client + Message clientResponseMsg = clientResponse.receive(2000); + clientSession.commit(); + assertNotNull("Client did not receive response message,", clientResponseMsg); + assertEquals("Incorrect message received", "Response", ((TextMessage) clientResponseMsg).getText()); + } + + public void setUpClientDeleteQueueSuccessWithOnlyAllPermissions() throws Exception + { + writeACLFile("ACL ALLOW-LOG client ACCESS VIRTUALHOST", + "ACL ALLOW-LOG client ALL QUEUE", + "ACL ALLOW-LOG client ALL EXCHANGE"); + } + + public void testClientDeleteQueueSuccessWithOnlyAllPermissions() throws Exception + { + Connection conn = getConnection("test", "client", "guest"); + Session sess = conn.createSession(true, Session.SESSION_TRANSACTED); + conn.start(); + + // create kipper + String topicName = "kipper"; + Topic topic = sess.createTopic(topicName); + TopicSubscriber subscriber = sess.createDurableSubscriber(topic, topicName); + + subscriber.close(); + sess.unsubscribe(topicName); + + //Do something to show connection is active. + sess.rollback(); + conn.close(); + } + + public void setUpFirewallAllow() throws Exception + { + writeACLFile("ACL ALLOW client ACCESS VIRTUALHOST from_network=\"127.0.0.1\""); + } + + public void testFirewallAllow() throws Exception + { + getConnection("test", "client", "guest"); + // test pass because we successfully connected + } + + public void setUpFirewallDeny() throws Exception + { + writeACLFile("ACL DENY client ACCESS VIRTUALHOST from_network=\"127.0.0.1\""); + } + + public void testFirewallDeny() throws Exception + { + try + { + getConnection("test", "client", "guest"); + fail("We expected the connection to fail"); + } + catch(JMSException e) + { + // pass + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java new file mode 100644 index 0000000000..0d0c1257a2 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java @@ -0,0 +1,374 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.manager; + +import static org.apache.qpid.test.utils.TestSSLConstants.BROKER_PEERSTORE; +import static org.apache.qpid.test.utils.TestSSLConstants.BROKER_PEERSTORE_PASSWORD; +import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE; +import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE_PASSWORD; +import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE; +import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD; +import static org.apache.qpid.test.utils.TestSSLConstants.UNTRUSTED_KEYSTORE; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.JMSException; + +import org.apache.qpid.client.AMQConnectionURL; +import org.apache.qpid.management.common.mbeans.ManagedConnection; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Transport; +import org.apache.qpid.server.model.TrustStore; +import org.apache.qpid.server.security.FileTrustStore; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class ExternalAuthenticationTest extends QpidBrokerTestCase +{ + @Override + protected void setUp() throws Exception + { + // not calling super.setUp() to avoid broker start-up + setSystemProperty("javax.net.debug", "ssl"); + } + + /** + * Tests that when EXTERNAL authentication is used on the SSL port, clients presenting certificates are able to connect. + * Also, checks that default authentication manager PrincipalDatabaseAuthenticationManager is used on non SSL port. + */ + public void testExternalAuthenticationManagerOnSSLPort() throws Exception + { + setCommonBrokerSSLProperties(true); + super.setUp(); + + setClientKeystoreProperties(); + setClientTrustoreProperties(); + + try + { + getExternalSSLConnection(false); + } + catch (JMSException e) + { + fail("Should be able to create a connection to the SSL port: " + e.getMessage()); + } + + try + { + getConnection(); + } + catch (JMSException e) + { + fail("Should be able to create a connection with credentials to the standard port: " + e.getMessage()); + } + + } + + /** + * Tests that when EXTERNAL authentication manager is set on the non-SSL port, clients with valid username and password + * but not using ssl are unable to connect to the non-SSL port. + */ + public void testExternalAuthenticationManagerOnNonSslPort() throws Exception + { + setCommonBrokerSSLProperties(true); + getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT, Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_EXTERNAL_PROVIDER); + super.setUp(); + + setClientKeystoreProperties(); + setClientTrustoreProperties(); + + try + { + getConnection(); + fail("Connection should not succeed"); + } + catch (JMSException e) + { + // pass + } + } + + /** + * Tests that when EXTERNAL authentication manager is used, clients without certificates are unable to connect to the SSL port + * even with valid username and password. + */ + public void testExternalAuthenticationManagerWithoutClientKeyStore() throws Exception + { + setCommonBrokerSSLProperties(false); + super.setUp(); + + setClientTrustoreProperties(); + + try + { + getExternalSSLConnection(true); + fail("Connection should not succeed"); + } + catch (JMSException e) + { + // pass + } + } + + /** + * Tests that when using the EXTERNAL authentication provider and needing client auth, clients with + * untrusted certificates are unable to connect to the SSL port. + */ + public void testExternalAuthenticationDeniesUntrustedClientCert() throws Exception + { + setCommonBrokerSSLProperties(true); + super.setUp(); + + setUntrustedClientKeystoreProperties(); + setClientTrustoreProperties(); + + try + { + getExternalSSLConnection(false); + fail("Connection should not succeed"); + } + catch (JMSException e) + { + // pass + } + } + + /** + * Tests that when using the EXTERNAL auth provider and a 'peersOnly' truststore, clients using certs directly in + * in the store will be able to connect and clients using certs signed by the same CA but not in the store will not. + */ + public void testExternalAuthenticationWithPeersOnlyTrustStore() throws Exception + { + externalAuthenticationWithPeersOnlyTrustStoreTestImpl(false); + } + + /** + * Tests that when using the EXTERNAL auth provider, with both the regular trust store and a 'peersOnly' truststore, clients + * using certs signed by the CA in the trust store are allowed even if they are not present in the 'peersOnly' store. + */ + public void testExternalAuthenticationWithRegularAndPeersOnlyTrustStores() throws Exception + { + externalAuthenticationWithPeersOnlyTrustStoreTestImpl(true); + } + + private void externalAuthenticationWithPeersOnlyTrustStoreTestImpl(boolean useTrustAndPeerStore) throws Exception + { + String peerStoreName = "myPeerStore"; + + List storeNames = null; + if(useTrustAndPeerStore) + { + //Use the regular trust store AND the 'peersOnly' store. The regular trust store trusts the CA that + //signed both the app1 and app2 certs. The peersOnly store contains only app1 and so does not trust app2 + storeNames = Arrays.asList(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE, peerStoreName); + } + else + { + //use only the 'peersOnly' store, which contains only app1 and so does not trust app2 + storeNames = Arrays.asList(peerStoreName); + } + + //set the brokers SSL config, inc which SSL stores to use + setCommonBrokerSSLProperties(true, storeNames); + + //add the peersOnly store to the config + Map sslTrustStoreAttributes = new HashMap(); + sslTrustStoreAttributes.put(TrustStore.NAME, peerStoreName); + sslTrustStoreAttributes.put(FileTrustStore.PATH, BROKER_PEERSTORE); + sslTrustStoreAttributes.put(FileTrustStore.PASSWORD, BROKER_PEERSTORE_PASSWORD); + sslTrustStoreAttributes.put(FileTrustStore.PEERS_ONLY, true); + getBrokerConfiguration().addObjectConfiguration(TrustStore.class, sslTrustStoreAttributes); + + super.setUp(); + + setClientKeystoreProperties(); + setClientTrustoreProperties(); + + try + { + //use the app1 cert, which IS in the peerstore (and has CA in the trustStore) + getExternalSSLConnection(false, "&ssl_cert_alias='app1'"); + } + catch (JMSException e) + { + fail("Client's validation against the broker's multi store manager unexpectedly failed, when configured store was expected to allow."); + } + + try + { + //use the app2 cert, which is NOT in the peerstore (but is signed by the same CA as app1) + getExternalSSLConnection(false, "&ssl_cert_alias='app2'"); + if(!useTrustAndPeerStore) + { + fail("Client's validation against the broker's multi store manager unexpectedly passed, when configured store was expected to deny."); + } + } + catch (JMSException e) + { + if(useTrustAndPeerStore) + { + fail("Client's validation against the broker's multi store manager unexpectedly failed, when configured store was expected to allow."); + } + else + { + //expected, the CA in trust store should allow both app1 and app2 + } + } + } + + /** + * Tests the creation of usernames when EXTERNAL authentication is used. + * The username should be created as CN@DC1.DC2...DCn by default. + */ + public void testExternalAuthenticationManagerUsernameAsCN() throws Exception + { + JMXTestUtils jmxUtils = new JMXTestUtils(this); + + setCommonBrokerSSLProperties(true); + getBrokerConfiguration().addJmxManagementConfiguration(); + + super.setUp(); + + setClientKeystoreProperties(); + setClientTrustoreProperties(); + + try + { + getExternalSSLConnection(false, "&ssl_cert_alias='app2'"); + } + catch (JMSException e) + { + fail("Should be able to create a connection to the SSL port: " + e.getMessage()); + } + + // Getting the used username using JMX + jmxUtils.open(); + List connections = jmxUtils.getManagedConnections("test"); + assertNotNull("Connections are null", connections); + assertEquals("Unexpected number of connections", 1, connections.size()); + assertEquals("Wrong authorized ID", "app2@acme.org", connections.get(0).getAuthorizedId()); + } + + /** + * Tests the creation of usernames when EXTERNAL authentication is used. + * The username should be created as full DN when the useFullDN option is used. + */ + public void testExternalAuthenticationManagerUsernameAsDN() throws Exception + { + JMXTestUtils jmxUtils = new JMXTestUtils(this); + + setCommonBrokerSSLProperties(true); + getBrokerConfiguration().setObjectAttribute(AuthenticationProvider.class, TestBrokerConfiguration.ENTRY_NAME_EXTERNAL_PROVIDER, ExternalAuthenticationManager.ATTRIBUTE_USE_FULL_DN, "true"); + getBrokerConfiguration().addJmxManagementConfiguration(); + + super.setUp(); + + setClientKeystoreProperties(); + setClientTrustoreProperties(); + + try + { + getExternalSSLConnection(false, "&ssl_cert_alias='app2'"); + } + catch (JMSException e) + { + fail("Should be able to create a connection to the SSL port: " + e.getMessage()); + } + + // Getting the used username using JMX + jmxUtils.open(); + List connections = jmxUtils.getManagedConnections("test"); + assertNotNull("Connections are null", connections); + assertEquals("Unexpected number of connections", 1, connections.size()); + assertEquals("Wrong authorized ID", "CN=app2@acme.org,OU=art,O=acme,L=Toronto,ST=ON,C=CA", connections.get(0).getAuthorizedId()); + } + + private Connection getExternalSSLConnection(boolean includeUserNameAndPassword) throws Exception + { + return getExternalSSLConnection(includeUserNameAndPassword, ""); + } + + private Connection getExternalSSLConnection(boolean includeUserNameAndPassword, String optionString) throws Exception + { + String url = "amqp://%s@test/?brokerlist='tcp://localhost:%s?ssl='true'&sasl_mechs='EXTERNAL'%s'"; + if (includeUserNameAndPassword) + { + url = String.format(url, "guest:guest", String.valueOf(QpidBrokerTestCase.DEFAULT_SSL_PORT), optionString); + } + else + { + url = String.format(url, ":", String.valueOf(QpidBrokerTestCase.DEFAULT_SSL_PORT), optionString); + } + return getConnection(new AMQConnectionURL(url)); + } + + private void setCommonBrokerSSLProperties(boolean needClientAuth) + { + setCommonBrokerSSLProperties(needClientAuth, Collections.singleton(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE)); + } + + private void setCommonBrokerSSLProperties(boolean needClientAuth, Collection trustStoreNames) + { + TestBrokerConfiguration config = getBrokerConfiguration(); + + Map sslPortAttributes = new HashMap(); + sslPortAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); + sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT); + sslPortAttributes.put(Port.NEED_CLIENT_AUTH, String.valueOf(needClientAuth)); + sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT); + sslPortAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); + sslPortAttributes.put(Port.TRUST_STORES, trustStoreNames); + config.addObjectConfiguration(Port.class, sslPortAttributes); + + Map externalAuthProviderAttributes = new HashMap(); + externalAuthProviderAttributes.put(AuthenticationProvider.NAME, TestBrokerConfiguration.ENTRY_NAME_EXTERNAL_PROVIDER); + externalAuthProviderAttributes.put(AuthenticationProvider.TYPE, ExternalAuthenticationManager.PROVIDER_TYPE); + config.addObjectConfiguration(AuthenticationProvider.class, externalAuthProviderAttributes); + + config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT, Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_EXTERNAL_PROVIDER); + } + + private void setUntrustedClientKeystoreProperties() + { + setSystemProperty("javax.net.ssl.keyStore", UNTRUSTED_KEYSTORE); + setSystemProperty("javax.net.ssl.keyStorePassword", KEYSTORE_PASSWORD); + } + + private void setClientKeystoreProperties() + { + setSystemProperty("javax.net.ssl.keyStore", KEYSTORE); + setSystemProperty("javax.net.ssl.keyStorePassword", KEYSTORE_PASSWORD); + } + + private void setClientTrustoreProperties() + { + setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); + setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java new file mode 100644 index 0000000000..1c32a3f671 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.server.security.auth.manager; + +import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE; +import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE_PASSWORD; +import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE; +import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.JMSException; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Transport; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class MultipleAuthenticationManagersTest extends QpidBrokerTestCase +{ + @Override + protected void setUp() throws Exception + { + TestBrokerConfiguration config = getBrokerConfiguration(); + + Map externalAuthProviderAttributes = new HashMap(); + externalAuthProviderAttributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); + externalAuthProviderAttributes.put(AuthenticationProvider.NAME, TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER); + config.addObjectConfiguration(AuthenticationProvider.class, externalAuthProviderAttributes); + + Map sslPortAttributes = new HashMap(); + sslPortAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); + sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT); + sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT); + sslPortAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); + sslPortAttributes.put(Port.TRUST_STORES, Collections.singleton(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE)); + sslPortAttributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER); + config.addObjectConfiguration(Port.class, sslPortAttributes); + + // set the ssl system properties + setSystemProperty("javax.net.ssl.keyStore", KEYSTORE); + setSystemProperty("javax.net.ssl.keyStorePassword", KEYSTORE_PASSWORD); + setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); + setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); + setSystemProperty("javax.net.debug", "ssl"); + super.setUp(); + } + + private Connection getAnonymousSSLConnection() throws Exception + { + String url = "amqp://:@test/?brokerlist='tcp://localhost:%s?ssl='true''"; + + url = String.format(url,QpidBrokerTestCase.DEFAULT_SSL_PORT); + + return new AMQConnection(url); + + } + + private Connection getAnonymousConnection() throws Exception + { + String url = "amqp://:@test/?brokerlist='tcp://localhost:%s'"; + + url = String.format(url,QpidBrokerTestCase.DEFAULT_PORT); + + return new AMQConnection(url); + + } + + + public void testMultipleAuthenticationManagers() throws Exception + { + try + { + Connection conn = getConnection(); + assertNotNull("Connection unexpectedly null", conn); + } + catch(JMSException e) + { + fail("Should be able to create a connection with credentials to the standard port. " + e.getMessage()); + } + + try + { + Connection conn = getAnonymousSSLConnection(); + assertNotNull("Connection unexpectedly null", conn); + } + catch(JMSException e) + { + fail("Should be able to create a anonymous connection to the SSL port. " + e.getMessage()); + } + + try + { + Connection conn = getAnonymousConnection(); + fail("Should not be able to create anonymous connection to the standard port"); + } + catch(AMQException e) + { + // pass + } + + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/stats/StatisticsReportingTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/stats/StatisticsReportingTest.java new file mode 100644 index 0000000000..04b8385e69 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/stats/StatisticsReportingTest.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.server.stats; + +import java.util.List; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.model.VirtualHostNode; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.util.LogMonitor; + +/** + * Test generation of message/data statistics reporting and the ability + * to control from the configuration file. + */ +public class StatisticsReportingTest extends QpidBrokerTestCase +{ + private static final String VHOST_NAME1 = "vhost1"; + private static final String VHOST_NAME2 = "vhost2"; + private static final String VHOST_NAME3 = "vhost3"; + private static long STATISTICS_REPORTING_PERIOD_IN_SECONDS = 10l; + + protected LogMonitor _monitor; + protected static final String USER = "admin"; + + protected Connection _conToVhost1, _conToVhost2, _conToVhost3; + protected String _queueName = "statistics"; + protected Destination _queue; + protected String _brokerUrl; + private long _startTestTime; + + @Override + public void setUp() throws Exception + { + createTestVirtualHostNode(0, VHOST_NAME1); + createTestVirtualHostNode(0, VHOST_NAME2); + createTestVirtualHostNode(0, VHOST_NAME3); + + if (getName().equals("testEnabledStatisticsReporting")) + { + TestBrokerConfiguration config = getBrokerConfiguration(); + config.removeObjectConfiguration(VirtualHostNode.class, TestBrokerConfiguration.ENTRY_NAME_VIRTUAL_HOST); + config.setBrokerAttribute(Broker.STATISTICS_REPORTING_PERIOD, STATISTICS_REPORTING_PERIOD_IN_SECONDS); + } + + _monitor = new LogMonitor(_outputFile); + _startTestTime = System.currentTimeMillis(); + + super.setUp(); + + _brokerUrl = getBroker().toString(); + _conToVhost1 = new AMQConnection(_brokerUrl, USER, USER, "clientid", VHOST_NAME1); + _conToVhost2 = new AMQConnection(_brokerUrl, USER, USER, "clientid", VHOST_NAME2); + _conToVhost3 = new AMQConnection(_brokerUrl, USER, USER, "clientid", VHOST_NAME3); + + _conToVhost1.start(); + _conToVhost2.start(); + _conToVhost3.start(); + } + + @Override + public void tearDown() throws Exception + { + _conToVhost1.close(); + _conToVhost2.close(); + _conToVhost3.close(); + + super.tearDown(); + } + + /** + * Test enabling reporting. + */ + public void testEnabledStatisticsReporting() throws Exception + { + sendUsing(_conToVhost1, 10, 100); + sendUsing(_conToVhost2, 20, 100); + sendUsing(_conToVhost3, 15, 100); + + Thread.sleep(STATISTICS_REPORTING_PERIOD_IN_SECONDS * 1000); + + Map> brokerStatsData = _monitor.findMatches("BRK-1008", "BRK-1009", "VHT-1003", "VHT-1004"); + long endTestTime = System.currentTimeMillis(); + + int maxNumberOfReports = (int)((endTestTime - _startTestTime)/STATISTICS_REPORTING_PERIOD_IN_SECONDS); + + int brk1008LinesNumber = brokerStatsData.get("BRK-1008").size(); + int brk1009LinesNumber = brokerStatsData.get("BRK-1009").size(); + int vht1003LinesNumber = brokerStatsData.get("VHT-1003").size(); + int vht1004LinesNumber = brokerStatsData.get("VHT-1004").size(); + + assertTrue("Incorrect number of broker data stats log messages:" + brk1008LinesNumber, 2 <= brk1008LinesNumber + && brk1008LinesNumber <= maxNumberOfReports * 2); + assertTrue("Incorrect number of broker message stats log messages:" + brk1009LinesNumber, 2 <= brk1009LinesNumber + && brk1009LinesNumber <= maxNumberOfReports * 2); + assertTrue("Incorrect number of virtualhost data stats log messages:" + vht1003LinesNumber, 6 <= vht1003LinesNumber + && vht1003LinesNumber <= maxNumberOfReports * 6); + assertTrue("Incorrect number of virtualhost message stats log messages: " + vht1004LinesNumber, 6 <= vht1004LinesNumber + && vht1004LinesNumber <= maxNumberOfReports * 6); + } + + /** + * Test not enabling reporting. + */ + public void testNotEnabledStatisticsReporting() throws Exception + { + sendUsing(_conToVhost1, 10, 100); + sendUsing(_conToVhost2, 20, 100); + sendUsing(_conToVhost3, 15, 100); + + Thread.sleep(10 * 1000); // 15s + + List brokerStatsData = _monitor.findMatches("BRK-1008"); + List brokerStatsMessages = _monitor.findMatches("BRK-1009"); + List vhostStatsData = _monitor.findMatches("VHT-1003"); + List vhostStatsMessages = _monitor.findMatches("VHT-1004"); + + assertEquals("Incorrect number of broker data stats log messages", 0, brokerStatsData.size()); + assertEquals("Incorrect number of broker message stats log messages", 0, brokerStatsMessages.size()); + assertEquals("Incorrect number of virtualhost data stats log messages", 0, vhostStatsData.size()); + assertEquals("Incorrect number of virtualhost message stats log messages", 0, vhostStatsMessages.size()); + } + + private void sendUsing(Connection con, int number, int size) throws Exception + { + Session session = con.createSession(true, Session.SESSION_TRANSACTED); + createQueue(session); + MessageProducer producer = session.createProducer(_queue); + String content = new String(new byte[size]); + TextMessage msg = session.createTextMessage(content); + for (int i = 0; i < number; i++) + { + producer.send(msg); + } + session.commit(); + session.close(); + } + + private void createQueue(Session session) throws AMQException, JMSException + { + _queue = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, _queueName); + if (!((AMQSession) session).isQueueBound((AMQDestination) _queue)) + { + ((AMQSession) session).createQueue(new AMQShortString(_queueName), false, true, false, null); + ((AMQSession) session).declareAndBind((AMQDestination) new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, _queueName)); + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/store/PersistentStoreTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/store/PersistentStoreTest.java new file mode 100644 index 0000000000..c2ea420e4b --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/store/PersistentStoreTest.java @@ -0,0 +1,164 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.store; + +import java.util.ArrayList; +import java.util.List; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class PersistentStoreTest extends QpidBrokerTestCase +{ + private static final int NUM_MESSAGES = 100; + private Connection _con; + private Session _session; + private Destination _destination; + + public void setUp() throws Exception + { + super.setUp(); + _con = getConnection(); + } + + public void testCommittedMessagesSurviveBrokerNormalShutdown() throws Exception + { + sendAndCommitMessages(); + stopBroker(); + startBroker(); + confirmBrokerStillHasCommittedMessages(); + } + + public void testCommittedMessagesSurviveBrokerAbnormalShutdown() throws Exception + { + if (isInternalBroker()) + { + return; + } + + sendAndCommitMessages(); + killBroker(); + startBroker(); + confirmBrokerStillHasCommittedMessages(); + } + + public void testCommittedMessagesSurviveBrokerNormalShutdownMidTransaction() throws Exception + { + sendAndCommitMessages(); + sendMoreMessagesWithoutCommitting(); + stopBroker(); + startBroker(); + confirmBrokerStillHasCommittedMessages(); + } + + public void testCommittedMessagesSurviveBrokerAbnormalShutdownMidTransaction() throws Exception + { + if (isInternalBroker()) + { + return; + } + sendAndCommitMessages(); + sendMoreMessagesWithoutCommitting(); + killBroker(); + startBroker(); + confirmBrokerStillHasCommittedMessages(); + } + + private void sendAndCommitMessages() throws Exception + { + _session = _con.createSession(true, Session.SESSION_TRANSACTED); + _destination = _session.createQueue(getTestQueueName()); + // Create queue by consumer side-effect + _session.createConsumer(_destination).close(); + + sendMessage(_session, _destination, NUM_MESSAGES); + _session.commit(); + } + + private void sendMoreMessagesWithoutCommitting() throws Exception + { + sendMessage(_session, _destination, 5); + // sync to ensure that messages have reached the broker + ((AMQSession) _session).sync(); + } + + private void confirmBrokerStillHasCommittedMessages() throws Exception + { + Connection con = getConnection(); + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + con.start(); + Destination destination = session.createQueue(getTestQueueName()); + MessageConsumer consumer = session.createConsumer(destination); + for (int i = 1; i <= NUM_MESSAGES; i++) + { + Message msg = consumer.receive(RECEIVE_TIMEOUT); + assertNotNull("Message " + i + " not received", msg); + assertEquals("Did not receive the expected message", i, msg.getIntProperty(INDEX)); + } + + Message msg = consumer.receive(100); + if(msg != null) + { + fail("No more messages should be received, but received additional message with index: " + msg.getIntProperty(INDEX)); + } + } + + /** + * This test requires that we can send messages without committing. + * QTC always commits the messages sent via sendMessages. + * + * @param session the session to use for sending + * @param destination where to send them to + * @param count no. of messages to send + * + * @return the sent messages + * + * @throws Exception + */ + @Override + public List sendMessage(Session session, Destination destination, + int count) throws Exception + { + List messages = new ArrayList(count); + + MessageProducer producer = session.createProducer(destination); + + for (int i = 1;i <= (count); i++) + { + Message next = createNextMessage(session, i); + + producer.send(next); + + messages.add(next); + } + + return messages; + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/store/SplitStoreTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/store/SplitStoreTest.java new file mode 100644 index 0000000000..7916f39488 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/store/SplitStoreTest.java @@ -0,0 +1,141 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store; + +import java.io.File; +import java.util.Collections; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.server.model.VirtualHostNode; +import org.apache.qpid.server.virtualhostnode.AbstractVirtualHostNode; +import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNode; +import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNodeImpl; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.test.utils.TestFileUtils; +import org.apache.qpid.util.FileUtils; + +public class SplitStoreTest extends QpidBrokerTestCase +{ + private String _messageStorePath; + private String _configStorePath; + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + String virtualHostWorkDir = System.getProperty("QPID_WORK") + File.separator + TestBrokerConfiguration.ENTRY_NAME_VIRTUAL_HOST + File.separator; + _messageStorePath = virtualHostWorkDir + "messageStore"; + _configStorePath = virtualHostWorkDir + "configStore"; + } + + @Override + protected void tearDown() throws Exception + { + try + { + super.tearDown(); + } + finally + { + TestFileUtils.delete(new File(_messageStorePath), true); + } + } + + @Override + public void startBroker() throws Exception + { + // Overridden to prevent QBTC starting the Broker. + } + + public void testJsonConfigurationStoreWithPersistentMessageStore() throws Exception + { + doTest(JsonVirtualHostNodeImpl.VIRTUAL_HOST_NODE_TYPE, getTestProfileVirtualHostNodeType()); + } + + public void testSeparateConfigurationAndMessageStoresOfTheSameType() throws Exception + { + doTest(getTestProfileVirtualHostNodeType(), getTestProfileVirtualHostNodeType()); + } + + private void configureAndStartBroker(String virtualHostNodeType, String virtualHostType) throws Exception + { + final String blueprint = String.format( + "{ \"type\" : \"%s\", \"storePath\" : \"%s\" }", virtualHostType, _messageStorePath); + final Map contextMap = Collections.singletonMap(AbstractVirtualHostNode.VIRTUALHOST_BLUEPRINT_CONTEXT_VAR, + blueprint); + + TestBrokerConfiguration config = getBrokerConfiguration(); + config.setObjectAttribute(VirtualHostNode.class, TestBrokerConfiguration.ENTRY_NAME_VIRTUAL_HOST, VirtualHostNode.TYPE, virtualHostNodeType); + config.setObjectAttribute(VirtualHostNode.class, TestBrokerConfiguration.ENTRY_NAME_VIRTUAL_HOST, VirtualHostNode.CONTEXT, contextMap); + config.setObjectAttribute(VirtualHostNode.class, TestBrokerConfiguration.ENTRY_NAME_VIRTUAL_HOST, JsonVirtualHostNode.STORE_PATH, _configStorePath); + + super.startBroker(); + } + + private void doTest(String nodeType, String path) throws Exception + { + configureAndStartBroker(nodeType, path); + + Connection connection = getConnection(); + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Queue queue = session.createQueue(getTestQueueName()); + session.createConsumer(queue).close(); // Create durable queue by side effect + sendMessage(session, queue, 2); + connection.close(); + + restartBroker(); + + setTestSystemProperty(ClientProperties.QPID_DECLARE_QUEUES_PROP_NAME, "false"); + connection = getConnection(); + connection.start(); + session = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageConsumer consumer = session.createConsumer(queue); + Message message = consumer.receive(1000); + session.commit(); + + assertNotNull("Message was not received after first restart", message); + assertEquals("Unexpected message received after first restart", 0, message.getIntProperty(INDEX)); + + stopBroker(); + File messageStoreFile = new File(_messageStorePath); + FileUtils.delete(messageStoreFile, true); + assertFalse("Store folder was not deleted", messageStoreFile.exists()); + super.startBroker(); + + connection = getConnection(); + connection.start(); + session = connection.createSession(true, Session.SESSION_TRANSACTED); + consumer = session.createConsumer(queue); + message = consumer.receive(500); + + assertNull("Message was received after store removal", message); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/store/VirtualHostMessageStoreTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/store/VirtualHostMessageStoreTest.java new file mode 100644 index 0000000000..dfc507d88a --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/store/VirtualHostMessageStoreTest.java @@ -0,0 +1,875 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.store; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.security.auth.Subject; + +import org.codehaus.jackson.map.ObjectMapper; + +import org.apache.qpid.common.AMQPFilterTypes; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.abstraction.MessagePublishInfo; +import org.apache.qpid.framing.amqp_8_0.BasicConsumeBodyImpl; +import org.apache.qpid.server.configuration.updater.TaskExecutor; +import org.apache.qpid.server.configuration.updater.TaskExecutorImpl; +import org.apache.qpid.server.connection.SessionPrincipal; +import org.apache.qpid.server.exchange.ExchangeImpl; +import org.apache.qpid.server.message.InstanceProperties; +import org.apache.qpid.server.message.MessageSource; +import org.apache.qpid.server.model.Binding; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.ConfiguredObjectFactory; +import org.apache.qpid.server.model.ExclusivityPolicy; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.UUIDGenerator; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.model.VirtualHostNode; +import org.apache.qpid.server.protocol.AMQConnectionModel; +import org.apache.qpid.server.protocol.AMQSessionModel; +import org.apache.qpid.server.protocol.v0_8.AMQMessage; +import org.apache.qpid.server.protocol.v0_8.MessageMetaData; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.LastValueQueue; +import org.apache.qpid.server.queue.LastValueQueueImpl; +import org.apache.qpid.server.queue.PriorityQueue; +import org.apache.qpid.server.queue.PriorityQueueImpl; +import org.apache.qpid.server.queue.StandardQueueImpl; +import org.apache.qpid.server.txn.AutoCommitTransaction; +import org.apache.qpid.server.txn.ServerTransaction; +import org.apache.qpid.server.util.BrokerTestHelper; +import org.apache.qpid.server.virtualhost.TestMemoryVirtualHost; +import org.apache.qpid.server.virtualhost.VirtualHostImpl; +import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNode; +import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpid.util.FileUtils; + +/** + * + * Virtualhost/store integration test. Tests for correct behaviour of the message store + * when exercised via the higher level functions of the store. + * + * For persistent stores, it validates that Exchanges, Queues, Bindings and + * Messages are persisted and recovered correctly. + */ +public class VirtualHostMessageStoreTest extends QpidTestCase +{ + + public static final int DEFAULT_PRIORTY_LEVEL = 5; + public static final String SELECTOR_VALUE = "Test = 'MST'"; + public static final String LVQ_KEY = "MST-LVQ-KEY"; + + private String nonDurableExchangeName = "MST-NonDurableDirectExchange"; + private String directExchangeName = "MST-DirectExchange"; + private String topicExchangeName = "MST-TopicExchange"; + + private String durablePriorityTopicQueueName = "MST-PriorityTopicQueue-Durable"; + private String durableTopicQueueName = "MST-TopicQueue-Durable"; + private String priorityTopicQueueName = "MST-PriorityTopicQueue"; + private String topicQueueName = "MST-TopicQueue"; + + private String durableExclusiveQueueName = "MST-Queue-Durable-Exclusive"; + private String durablePriorityQueueName = "MST-PriorityQueue-Durable"; + private String durableLastValueQueueName = "MST-LastValueQueue-Durable"; + private String durableQueueName = "MST-Queue-Durable"; + private String priorityQueueName = "MST-PriorityQueue"; + private String queueName = "MST-Queue"; + + private String directRouting = "MST-direct"; + private String topicRouting = "MST-topic"; + + private String queueOwner = "MST"; + + private VirtualHostImpl _virtualHost; + private String _storePath; + private VirtualHostNode _node; + private TaskExecutor _taskExecutor; + + public void setUp() throws Exception + { + super.setUp(); + + String nodeName = "node" + getName(); + String hostName = "host" + getName(); + _storePath = System.getProperty("QPID_WORK", TMP_FOLDER + File.separator + getTestName()) + File.separator + nodeName; + cleanup(new File(_storePath)); + + Broker broker = BrokerTestHelper.createBrokerMock(); + _taskExecutor = new TaskExecutorImpl(); + _taskExecutor.start(); + when(broker.getTaskExecutor()).thenReturn(_taskExecutor); + + ConfiguredObjectFactory factory = broker.getObjectFactory(); + Map nodeAttributes = new HashMap<>(); + nodeAttributes.put(ConfiguredObject.TYPE, getTestProfileVirtualHostNodeType()); + nodeAttributes.put(JsonVirtualHostNode.STORE_PATH, _storePath); + nodeAttributes.put(VirtualHostNode.NAME, nodeName); + + _node = factory.create(VirtualHostNode.class, nodeAttributes, broker); + _node.start(); + + final Map virtualHostAttributes = new HashMap<>(); + virtualHostAttributes.put(VirtualHost.NAME, hostName); + virtualHostAttributes.put(VirtualHost.NAME, hostName); + String bluePrint = getTestProfileVirtualHostNodeBlueprint(); + if (bluePrint == null) + { + bluePrint = "{type=\"" + TestMemoryVirtualHost.VIRTUAL_HOST_TYPE + "\"}"; + } + ObjectMapper objectMapper = new ObjectMapper(); + Map attrs = objectMapper.readValue(bluePrint, Map.class); + virtualHostAttributes.putAll(attrs); + _node.createChild(VirtualHost.class, virtualHostAttributes, _node); + + _virtualHost = (VirtualHostImpl)_node.getVirtualHost(); + + } + + @Override + public void tearDown() throws Exception + { + try + { + if (_virtualHost != null) + { + VirtualHostNode node = _virtualHost.getParent(VirtualHostNode.class); + node.close(); + } + } + finally + { + _taskExecutor.stopImmediately(); + super.tearDown(); + } + } + + protected void reloadVirtualHost() + { + assertEquals("Virtual host node is not active", State.ACTIVE, _virtualHost.getState()); + _node.stop(); + State currentState = _node.getState(); + assertEquals("Virtual host node is not stopped", State.STOPPED, currentState); + + _node.start(); + currentState = _node.getState(); + assertEquals("Virtual host node is not active", State.ACTIVE, currentState); + _virtualHost = (VirtualHostImpl) _node.getVirtualHost(); + } + + public void testQueueExchangeAndBindingCreation() throws Exception + { + assertEquals("Should not be any existing queues", 0, _virtualHost.getQueues().size()); + + createAllQueues(); + createAllTopicQueues(); + + //Register Non-Durable DirectExchange + ExchangeImpl nonDurableExchange = createExchange(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, nonDurableExchangeName, false); + bindAllQueuesToExchange(nonDurableExchange, directRouting); + + //Register DirectExchange + ExchangeImpl directExchange = createExchange(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, directExchangeName, true); + bindAllQueuesToExchange(directExchange, directRouting); + + //Register TopicExchange + ExchangeImpl topicExchange = createExchange(ExchangeDefaults.TOPIC_EXCHANGE_CLASS, topicExchangeName, true); + bindAllTopicQueuesToExchange(topicExchange, topicRouting); + + //Send Message To NonDurable direct Exchange = persistent + sendMessageOnExchange(nonDurableExchange, directRouting, true); + // and non-persistent + sendMessageOnExchange(nonDurableExchange, directRouting, false); + + //Send Message To direct Exchange = persistent + sendMessageOnExchange(directExchange, directRouting, true); + // and non-persistent + sendMessageOnExchange(directExchange, directRouting, false); + + //Send Message To topic Exchange = persistent + sendMessageOnExchange(topicExchange, topicRouting, true); + // and non-persistent + sendMessageOnExchange(topicExchange, topicRouting, false); + + //Ensure all the Queues have four messages (one transient, one persistent) x 2 exchange routings + validateMessageOnQueues(4, true); + //Ensure all the topics have two messages (one transient, one persistent) + validateMessageOnTopics(2, true); + + assertEquals("Not all queues correctly registered", + 10, _virtualHost.getQueues().size()); + } + + public void testMessagePersistence() throws Exception + { + testQueueExchangeAndBindingCreation(); + + reloadVirtualHost(); + + //Validate durable queues and subscriptions still have the persistent messages + validateMessageOnQueues(2, false); + validateMessageOnTopics(1, false); + } + + /** + * Tests message removal by running the testMessagePersistence() method above before + * clearing the queues, reloading the virtual host, and ensuring that the persistent + * messages were removed from the queues. + */ + public void testMessageRemoval() throws Exception + { + testMessagePersistence(); + + assertEquals("Incorrect number of queues registered after recovery", + 6, _virtualHost.getQueues().size()); + + //clear the queue + _virtualHost.getQueue(durableQueueName).clearQueue(); + + //check the messages are gone + validateMessageOnQueue(durableQueueName, 0); + + //reload and verify messages arent restored + reloadVirtualHost(); + + validateMessageOnQueue(durableQueueName, 0); + } + + /** + * Tests queue persistence by creating a selection of queues with differing properties, both + * durable and non durable, and ensuring that following the recovery process the correct queues + * are present and any property manipulations (eg queue exclusivity) are correctly recovered. + */ + public void testQueuePersistence() throws Exception + { + assertEquals("Should not be any existing queues", + 0, _virtualHost.getQueues().size()); + + //create durable and non durable queues/topics + createAllQueues(); + createAllTopicQueues(); + + //reload the virtual host, prompting recovery of the queues/topics + reloadVirtualHost(); + + assertEquals("Incorrect number of queues registered after recovery", + 6, _virtualHost.getQueues().size()); + + //Validate the non-Durable Queues were not recovered. + assertNull("Non-Durable queue still registered:" + priorityQueueName, + _virtualHost.getQueue(priorityQueueName)); + assertNull("Non-Durable queue still registered:" + queueName, + _virtualHost.getQueue(queueName)); + assertNull("Non-Durable queue still registered:" + priorityTopicQueueName, + _virtualHost.getQueue(priorityTopicQueueName)); + assertNull("Non-Durable queue still registered:" + topicQueueName, + _virtualHost.getQueue(topicQueueName)); + + //Validate normally expected properties of Queues/Topics + validateDurableQueueProperties(); + + //Update the durable exclusive queue's exclusivity + setQueueExclusivity(false); + validateQueueExclusivityProperty(false); + } + + /** + * Tests queue removal by creating a durable queue, verifying it recovers, and + * then removing it from the store, and ensuring that following the second reload + * process it is not recovered. + */ + public void testDurableQueueRemoval() throws Exception + { + //Register Durable Queue + createQueue(durableQueueName, false, true, false, false); + + assertEquals("Incorrect number of queues registered before recovery", + 1, _virtualHost.getQueues().size()); + + reloadVirtualHost(); + + assertEquals("Incorrect number of queues registered after first recovery", + 1, _virtualHost.getQueues().size()); + + //test that removing the queue means it is not recovered next time + + final AMQQueue queue = _virtualHost.getQueue(durableQueueName); + _virtualHost.getDurableConfigurationStore().remove(queue.asObjectRecord()); + + reloadVirtualHost(); + + assertEquals("Incorrect number of queues registered after second recovery", + 0, _virtualHost.getQueues().size()); + assertNull("Durable queue was not removed:" + durableQueueName, + _virtualHost.getQueue(durableQueueName)); + } + + /** + * Tests exchange persistence by creating a selection of exchanges, both durable + * and non durable, and ensuring that following the recovery process the correct + * durable exchanges are still present. + */ + public void testExchangePersistence() throws Exception + { + int origExchangeCount = _virtualHost.getExchanges().size(); + + Map> oldExchanges = createExchanges(); + + assertEquals("Incorrect number of exchanges registered before recovery", + origExchangeCount + 3, _virtualHost.getExchanges().size()); + + reloadVirtualHost(); + + //verify the exchanges present after recovery + validateExchanges(origExchangeCount, oldExchanges); + } + + /** + * Tests exchange removal by creating a durable exchange, verifying it recovers, and + * then removing it from the store, and ensuring that following the second reload + * process it is not recovered. + */ + public void testDurableExchangeRemoval() throws Exception + { + int origExchangeCount = _virtualHost.getExchanges().size(); + + createExchange(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, directExchangeName, true); + + assertEquals("Incorrect number of exchanges registered before recovery", + origExchangeCount + 1, _virtualHost.getExchanges().size()); + + reloadVirtualHost(); + + assertEquals("Incorrect number of exchanges registered after first recovery", + origExchangeCount + 1, _virtualHost.getExchanges().size()); + + //test that removing the exchange means it is not recovered next time + + final ExchangeImpl exchange = _virtualHost.getExchange(directExchangeName); + _virtualHost.getDurableConfigurationStore().remove(exchange.asObjectRecord()); + + reloadVirtualHost(); + + assertEquals("Incorrect number of exchanges registered after second recovery", + origExchangeCount, _virtualHost.getExchanges().size()); + assertNull("Durable exchange was not removed:" + directExchangeName, + _virtualHost.getExchange(directExchangeName)); + } + + /** + * Tests binding persistence by creating a selection of queues and exchanges, both durable + * and non durable, then adding bindings with and without selectors before reloading the + * virtual host and verifying that following the recovery process the correct durable + * bindings (those for durable queues to durable exchanges) are still present. + */ + public void testBindingPersistence() throws Exception + { + int origExchangeCount = _virtualHost.getExchanges().size(); + + createAllQueues(); + createAllTopicQueues(); + + Map> exchanges = createExchanges(); + + ExchangeImpl nonDurableExchange = exchanges.get(nonDurableExchangeName); + ExchangeImpl directExchange = exchanges.get(directExchangeName); + ExchangeImpl topicExchange = exchanges.get(topicExchangeName); + + bindAllQueuesToExchange(nonDurableExchange, directRouting); + bindAllQueuesToExchange(directExchange, directRouting); + bindAllTopicQueuesToExchange(topicExchange, topicRouting); + + assertEquals("Incorrect number of exchanges registered before recovery", + origExchangeCount + 3, _virtualHost.getExchanges().size()); + + reloadVirtualHost(); + + validateExchanges(origExchangeCount, exchanges); + + validateBindingProperties(); + } + + /** + * Tests binding removal by creating a durable exchange, and queue, binding them together, + * recovering to verify the persistence, then removing it from the store, and ensuring + * that following the second reload process it is not recovered. + */ + public void testDurableBindingRemoval() throws Exception + { + //create durable queue and exchange, bind them + ExchangeImpl exch = createExchange(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, directExchangeName, true); + createQueue(durableQueueName, false, true, false, false); + bindQueueToExchange(exch, directRouting, _virtualHost.getQueue(durableQueueName), false); + + assertEquals("Incorrect number of bindings registered before recovery", + 1, _virtualHost.getQueue(durableQueueName).getBindings().size()); + + //verify binding is actually normally recovered + reloadVirtualHost(); + + assertEquals("Incorrect number of bindings registered after first recovery", + 1, _virtualHost.getQueue(durableQueueName).getBindings().size()); + + exch = _virtualHost.getExchange(directExchangeName); + assertNotNull("Exchange was not recovered", exch); + + //remove the binding and verify result after recovery + unbindQueueFromExchange(exch, directRouting, _virtualHost.getQueue(durableQueueName), false); + + reloadVirtualHost(); + + assertEquals("Incorrect number of bindings registered after second recovery", + 0, _virtualHost.getQueue(durableQueueName).getBindings().size()); + } + + /** + * Validates that the durable exchanges are still present, the non durable exchange is not, + * and that the new exchanges are not the same objects as the provided list (i.e. that the + * reload actually generated new exchange objects) + */ + private void validateExchanges(int originalNumExchanges, Map> oldExchanges) + { + Collection> exchanges = (Collection>) _virtualHost.getExchanges(); + Collection exchangeNames = new ArrayList(exchanges.size()); + for(ExchangeImpl exchange : exchanges) + { + exchangeNames.add(exchange.getName()); + } + assertTrue(directExchangeName + " exchange NOT reloaded", + exchangeNames.contains(directExchangeName)); + assertTrue(topicExchangeName + " exchange NOT reloaded", + exchangeNames.contains(topicExchangeName)); + assertTrue(nonDurableExchangeName + " exchange reloaded", + !exchangeNames.contains(nonDurableExchangeName)); + + //check the old exchange objects are not the same as the new exchanges + assertTrue(directExchangeName + " exchange NOT reloaded", + _virtualHost.getExchange(directExchangeName) != oldExchanges.get(directExchangeName)); + assertTrue(topicExchangeName + " exchange NOT reloaded", + _virtualHost.getExchange(topicExchangeName) != oldExchanges.get(topicExchangeName)); + + // There should only be the original exchanges + our 2 recovered durable exchanges + assertEquals("Incorrect number of exchanges available", + originalNumExchanges + 2, _virtualHost.getExchanges().size()); + } + + /** Validates the Durable queues and their properties are as expected following recovery */ + private void validateBindingProperties() + { + + assertEquals("Incorrect number of (durable) queues following recovery", 6, _virtualHost.getQueues().size()); + + validateBindingProperties(_virtualHost.getQueue(durablePriorityQueueName).getBindings(), false); + validateBindingProperties(_virtualHost.getQueue(durablePriorityTopicQueueName).getBindings(), true); + validateBindingProperties(_virtualHost.getQueue(durableQueueName).getBindings(), false); + validateBindingProperties(_virtualHost.getQueue(durableTopicQueueName).getBindings(), true); + validateBindingProperties(_virtualHost.getQueue(durableExclusiveQueueName).getBindings(), false); + } + + /** + * Validate that each queue is bound only once following recovery (i.e. that bindings for non durable + * queues or to non durable exchanges are not recovered), and if a selector should be present + * that it is and contains the correct value + * + * @param bindings the set of bindings to validate + * @param useSelectors if set, check the binding has a JMS_SELECTOR argument and the correct value for it + */ + private void validateBindingProperties(Collection> bindings, boolean useSelectors) + { + assertEquals("Each queue should only be bound once.", 1, bindings.size()); + + Binding binding = bindings.iterator().next(); + + if (useSelectors) + { + assertTrue("Binding does not contain a Selector argument.", + binding.getArguments().containsKey(AMQPFilterTypes.JMS_SELECTOR.toString())); + assertEquals("The binding selector argument is incorrect", SELECTOR_VALUE, + binding.getArguments().get(AMQPFilterTypes.JMS_SELECTOR.toString()).toString()); + } + } + + private void setQueueExclusivity(boolean exclusive) throws MessageSource.ExistingConsumerPreventsExclusive + { + AMQQueue queue = _virtualHost.getQueue(durableExclusiveQueueName); + queue.setAttribute(Queue.EXCLUSIVE, queue.getExclusive(), exclusive ? ExclusivityPolicy.CONTAINER : ExclusivityPolicy.NONE); + } + + private void validateQueueExclusivityProperty(boolean expected) + { + AMQQueue queue = _virtualHost.getQueue(durableExclusiveQueueName); + + assertEquals("Queue exclusivity was incorrect", queue.isExclusive(), expected); + } + + + private void validateDurableQueueProperties() + { + validateQueueProperties(_virtualHost.getQueue(durablePriorityQueueName), true, true, false, false); + validateQueueProperties(_virtualHost.getQueue(durablePriorityTopicQueueName), true, true, false, false); + validateQueueProperties(_virtualHost.getQueue(durableQueueName), false, true, false, false); + validateQueueProperties(_virtualHost.getQueue(durableTopicQueueName), false, true, false, false); + validateQueueProperties(_virtualHost.getQueue(durableExclusiveQueueName), false, true, true, false); + validateQueueProperties(_virtualHost.getQueue(durableLastValueQueueName), false, true, true, true); + } + + private void validateQueueProperties(AMQQueue queue, boolean usePriority, boolean durable, boolean exclusive, boolean lastValueQueue) + { + if(usePriority || lastValueQueue) + { + assertNotSame("Queues cant be both Priority and LastValue based", usePriority, lastValueQueue); + } + + if (usePriority) + { + assertEquals("Queue is no longer a Priority Queue", PriorityQueueImpl.class, queue.getClass()); + assertEquals("Priority Queue does not have set priorities", + DEFAULT_PRIORTY_LEVEL, ((PriorityQueueImpl) queue).getPriorities()); + } + else if (lastValueQueue) + { + assertEquals("Queue is no longer a LastValue Queue", LastValueQueueImpl.class, queue.getClass()); + assertEquals("LastValue Queue Key has changed", LVQ_KEY, ((LastValueQueueImpl) queue).getLvqKey()); + } + else + { + assertEquals("Queue is not 'simple'", StandardQueueImpl.class, queue.getClass()); + } + + assertEquals("Queue owner is not as expected for queue " + queue.getName(), exclusive ? queueOwner : null, queue.getOwner()); + assertEquals("Queue durability is not as expected for queue " + queue.getName(), durable, queue.isDurable()); + assertEquals("Queue exclusivity is not as expected for queue " + queue.getName(), exclusive, queue.isExclusive()); + } + + /** + * Delete the Store Environment path + * + * @param environmentPath The configuration that contains the store environment path. + */ + private void cleanup(File environmentPath) + { + if (environmentPath.exists()) + { + FileUtils.delete(environmentPath, true); + } + } + + private void sendMessageOnExchange(ExchangeImpl exchange, String routingKey, boolean deliveryMode) + { + //Set MessagePersistence + BasicContentHeaderProperties properties = new BasicContentHeaderProperties(); + properties.setDeliveryMode(deliveryMode ? Integer.valueOf(2).byteValue() : Integer.valueOf(1).byteValue()); + FieldTable headers = properties.getHeaders(); + headers.setString("Test", "MST"); + properties.setHeaders(headers); + + MessagePublishInfo messageInfo = new TestMessagePublishInfo(exchange, false, false, routingKey); + + ContentHeaderBody headerBody = new ContentHeaderBody(BasicConsumeBodyImpl.CLASS_ID,0,properties,0l); + + MessageMetaData mmd = new MessageMetaData(messageInfo, headerBody, System.currentTimeMillis()); + + final StoredMessage storedMessage = _virtualHost.getMessageStore().addMessage(mmd); + final AMQMessage currentMessage = new AMQMessage(storedMessage); + + + + ServerTransaction trans = new AutoCommitTransaction(_virtualHost.getMessageStore()); + exchange.send(currentMessage, routingKey, InstanceProperties.EMPTY, trans, null); + + } + + private void createAllQueues() throws Exception + { + //Register Durable Priority Queue + createQueue(durablePriorityQueueName, true, true, false, false); + + //Register Durable Simple Queue + createQueue(durableQueueName, false, true, false, false); + + //Register Durable Exclusive Simple Queue + createQueue(durableExclusiveQueueName, false, true, true, false); + + //Register Durable LastValue Queue + createQueue(durableLastValueQueueName, false, true, true, true); + + //Register NON-Durable Priority Queue + createQueue(priorityQueueName, true, false, false, false); + + //Register NON-Durable Simple Queue + createQueue(queueName, false, false, false, false); + } + + private void createAllTopicQueues() throws Exception + { + //Register Durable Priority Queue + createQueue(durablePriorityTopicQueueName, true, true, false, false); + + //Register Durable Simple Queue + createQueue(durableTopicQueueName, false, true, false, false); + + //Register NON-Durable Priority Queue + createQueue(priorityTopicQueueName, true, false, false, false); + + //Register NON-Durable Simple Queue + createQueue(topicQueueName, false, false, false, false); + } + + private void createQueue(String queueName, boolean usePriority, boolean durable, boolean exclusive, boolean lastValueQueue) + throws Exception + { + + final Map queueArguments = new HashMap(); + + if(usePriority || lastValueQueue) + { + assertNotSame("Queues cant be both Priority and LastValue based", usePriority, lastValueQueue); + } + + if (usePriority) + { + queueArguments.put(PriorityQueue.PRIORITIES, DEFAULT_PRIORTY_LEVEL); + } + + if (lastValueQueue) + { + queueArguments.put(LastValueQueue.LVQ_KEY, LVQ_KEY); + } + + queueArguments.put(Queue.ID, UUIDGenerator.generateRandomUUID()); + queueArguments.put(Queue.NAME, queueName); + queueArguments.put(Queue.DURABLE, durable); + queueArguments.put(Queue.LIFETIME_POLICY, LifetimePolicy.PERMANENT); + queueArguments.put(Queue.EXCLUSIVE, exclusive ? ExclusivityPolicy.CONTAINER : ExclusivityPolicy.NONE); + AMQSessionModel sessionModel = mock(AMQSessionModel.class); + AMQConnectionModel connectionModel = mock(AMQConnectionModel.class); + when(sessionModel.getConnectionModel()).thenReturn(connectionModel); + when(connectionModel.getRemoteContainerName()).thenReturn(queueOwner); + SessionPrincipal principal = new SessionPrincipal(sessionModel); + AMQQueue queue = Subject.doAs(new Subject(true, + Collections.singleton(principal), + Collections.emptySet(), + Collections.emptySet()), + new PrivilegedAction>() + { + @Override + public AMQQueue run() + { + return _virtualHost.createQueue(queueArguments); + + } + }); + + + validateQueueProperties(queue, usePriority, durable, exclusive, lastValueQueue); + } + + private Map> createExchanges() throws Exception + { + Map> exchanges = new HashMap>(); + + //Register non-durable DirectExchange + exchanges.put(nonDurableExchangeName, createExchange(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, nonDurableExchangeName, false)); + + //Register durable DirectExchange and TopicExchange + exchanges.put(directExchangeName ,createExchange(ExchangeDefaults.DIRECT_EXCHANGE_CLASS, directExchangeName, true)); + exchanges.put(topicExchangeName,createExchange(ExchangeDefaults.TOPIC_EXCHANGE_CLASS, topicExchangeName, true)); + + return exchanges; + } + + private ExchangeImpl createExchange(String type, String name, boolean durable) throws Exception + { + ExchangeImpl exchange = null; + + Map attributes = new HashMap(); + + attributes.put(org.apache.qpid.server.model.Exchange.NAME, name); + attributes.put(org.apache.qpid.server.model.Exchange.TYPE, type); + attributes.put(org.apache.qpid.server.model.Exchange.DURABLE, durable); + attributes.put(org.apache.qpid.server.model.Exchange.LIFETIME_POLICY, + durable ? LifetimePolicy.DELETE_ON_NO_LINKS : LifetimePolicy.PERMANENT); + attributes.put(org.apache.qpid.server.model.Exchange.ALTERNATE_EXCHANGE, null); + exchange = _virtualHost.createExchange(attributes); + + return exchange; + } + + private void bindAllQueuesToExchange(ExchangeImpl exchange, String routingKey) + { + bindQueueToExchange(exchange, routingKey, _virtualHost.getQueue(durablePriorityQueueName), false); + bindQueueToExchange(exchange, routingKey, _virtualHost.getQueue(durableQueueName), false); + bindQueueToExchange(exchange, routingKey, _virtualHost.getQueue(priorityQueueName), false); + bindQueueToExchange(exchange, routingKey, _virtualHost.getQueue(queueName), false); + bindQueueToExchange(exchange, routingKey, _virtualHost.getQueue(durableExclusiveQueueName), false); + } + + private void bindAllTopicQueuesToExchange(ExchangeImpl exchange, String routingKey) + { + + bindQueueToExchange(exchange, routingKey, _virtualHost.getQueue(durablePriorityTopicQueueName), true); + bindQueueToExchange(exchange, routingKey, _virtualHost.getQueue(durableTopicQueueName), true); + bindQueueToExchange(exchange, routingKey, _virtualHost.getQueue(priorityTopicQueueName), true); + bindQueueToExchange(exchange, routingKey, _virtualHost.getQueue(topicQueueName), true); + } + + + protected void bindQueueToExchange(ExchangeImpl exchange, + String routingKey, + AMQQueue queue, + boolean useSelector) + { + Map bindArguments = new HashMap(); + + if (useSelector) + { + bindArguments.put(AMQPFilterTypes.JMS_SELECTOR.toString(), SELECTOR_VALUE ); + } + + try + { + exchange.addBinding(routingKey, queue, bindArguments); + } + catch (Exception e) + { + fail(e.getMessage()); + } + } + + protected void unbindQueueFromExchange(ExchangeImpl exchange, + String routingKey, + AMQQueue queue, + boolean useSelector) + { + Map bindArguments = new HashMap(); + + if (useSelector) + { + bindArguments.put(AMQPFilterTypes.JMS_SELECTOR.toString(), SELECTOR_VALUE ); + } + + try + { + exchange.deleteBinding(routingKey, queue); + } + catch (Exception e) + { + fail(e.getMessage()); + } + } + + private void validateMessageOnTopics(long messageCount, boolean allQueues) + { + validateMessageOnQueue(durablePriorityTopicQueueName, messageCount); + validateMessageOnQueue(durableTopicQueueName, messageCount); + + if (allQueues) + { + validateMessageOnQueue(priorityTopicQueueName, messageCount); + validateMessageOnQueue(topicQueueName, messageCount); + } + } + + private void validateMessageOnQueues(long messageCount, boolean allQueues) + { + validateMessageOnQueue(durablePriorityQueueName, messageCount); + validateMessageOnQueue(durableQueueName, messageCount); + + if (allQueues) + { + validateMessageOnQueue(priorityQueueName, messageCount); + validateMessageOnQueue(queueName, messageCount); + } + } + + private void validateMessageOnQueue(String queueName, long messageCount) + { + AMQQueue queue = _virtualHost.getQueue(queueName); + + assertNotNull("Queue(" + queueName + ") not correctly registered:", queue); + + assertEquals("Incorrect Message count on queue:" + queueName, messageCount, queue.getQueueDepthMessages()); + } + + private class TestMessagePublishInfo implements MessagePublishInfo + { + + ExchangeImpl _exchange; + boolean _immediate; + boolean _mandatory; + String _routingKey; + + TestMessagePublishInfo(ExchangeImpl exchange, boolean immediate, boolean mandatory, String routingKey) + { + _exchange = exchange; + _immediate = immediate; + _mandatory = mandatory; + _routingKey = routingKey; + } + + @Override + public AMQShortString getExchange() + { + return new AMQShortString(_exchange.getName()); + } + + @Override + public void setExchange(AMQShortString exchange) + { + //no-op + } + + @Override + public boolean isImmediate() + { + return _immediate; + } + + @Override + public boolean isMandatory() + { + return _mandatory; + } + + @Override + public AMQShortString getRoutingKey() + { + return new AMQShortString(_routingKey); + } + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/util/AveragedRun.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/util/AveragedRun.java new file mode 100644 index 0000000000..941c1d9499 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/util/AveragedRun.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.server.util; + +import java.util.Collection; +import java.util.concurrent.Callable; + +import org.apache.log4j.Logger; + +public class AveragedRun implements Callable +{ + private static final Logger _logger = Logger.getLogger(AveragedRun.class); + + private final RunStats stats = new RunStats(); + private final TimedRun test; + private final int iterations; + + public AveragedRun(TimedRun test, int iterations) + { + this.test = test; + this.iterations = iterations; + } + + public RunStats call() throws Exception + { + for (int i = 0; i < iterations; i++) + { + stats.record(test.call()); + } + return stats; + } + + public void run() throws Exception + { + _logger.info(test + ": " + call()); + } + + public String toString() + { + return test.toString(); + } + + static void run(Collection tests) throws Exception + { + for(AveragedRun test : tests) + { + test.run(); + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/util/RunStats.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/util/RunStats.java new file mode 100644 index 0000000000..ec67fc68b3 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/util/RunStats.java @@ -0,0 +1,57 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.util; + +public class RunStats +{ + private long min = Long.MAX_VALUE; + private long max; + private long total; + private int count; + + public void record(long time) + { + max = Math.max(time, max); + min = Math.min(time, min); + total += time; + count++; + } + + public long getMin() + { + return min; + } + + public long getMax() + { + return max; + } + + public long getAverage() + { + return total / count; + } + + public String toString() + { + return "avg=" + getAverage() + ", min=" + min + ", max=" + max; + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/server/util/TimedRun.java b/qpid/java/systests/src/test/java/org/apache/qpid/server/util/TimedRun.java new file mode 100644 index 0000000000..1291380311 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/server/util/TimedRun.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.server.util; + +import java.util.concurrent.Callable; + +public abstract class TimedRun implements Callable +{ + private final String description; + + public TimedRun(String description) + { + this.description = description; + } + + public Long call() throws Exception + { + setup(); + long start = System.currentTimeMillis(); + run(); + long stop = System.currentTimeMillis(); + teardown(); + return stop - start; + } + + public String toString() + { + return description; + } + + protected void setup() throws Exception{} + protected void teardown() throws Exception{} + protected abstract void run() throws Exception; +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.java new file mode 100644 index 0000000000..f6b56f64ce --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.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.management.jmx; + +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.management.common.mbeans.ManagedBroker; +import org.apache.qpid.management.common.mbeans.ManagedExchange; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +/** + * Tests the JMX API for the Managed Broker. + * + */ +public class BrokerManagementTest extends QpidBrokerTestCase +{ + private static final String VIRTUAL_HOST = "test"; + + /** + * JMX helper. + */ + private JMXTestUtils _jmxUtils; + private ManagedBroker _managedBroker; + + public void setUp() throws Exception + { + getBrokerConfiguration().addJmxManagementConfiguration(); + + _jmxUtils = new JMXTestUtils(this); + + super.setUp(); + _jmxUtils.open(); + _managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST); + } + + public void tearDown() throws Exception + { + if (_jmxUtils != null) + { + _jmxUtils.close(); + } + super.tearDown(); + } + + /** + * Tests queue creation/deletion also verifying the automatic binding to the default exchange. + */ + public void testCreateQueueAndDeletion() throws Exception + { + final String queueName = getTestQueueName(); + + + _managedBroker.createNewQueue(queueName, "testowner", true); + + // Ensure the queue exists + assertNotNull("Queue object name expected to exist", _jmxUtils.getQueueObjectName(VIRTUAL_HOST, queueName)); + assertNotNull("Manager queue expected to be available", _jmxUtils.getManagedQueue(queueName)); + + + // Now delete the queue + _managedBroker.deleteQueue(queueName); + + + } + + /** + * Tests exchange creation/deletion via JMX API. + */ + public void testCreateExchangeAndUnregister() throws Exception + { + String exchangeName = getTestName(); + _managedBroker.createNewExchange(exchangeName, "topic", true); + + ManagedExchange exchange = _jmxUtils.getManagedExchange(exchangeName); + assertNotNull("Exchange should exist", exchange); + + _managedBroker.unregisterExchange(exchangeName); + } + + /** + * Tests that it is disallowed to unregister the default exchange. + */ + public void testUnregisterOfAmqDirectExchangeDisallowed() throws Exception + { + String amqDirectExchangeName = "amq.direct"; + + ManagedExchange amqDirectExchange = _jmxUtils.getManagedExchange(amqDirectExchangeName); + assertNotNull("Exchange should exist", amqDirectExchange); + try + { + _managedBroker.unregisterExchange(amqDirectExchangeName); + fail("Exception not thrown"); + } + catch (UnsupportedOperationException e) + { + // PASS + assertEquals("'"+amqDirectExchangeName+"' is a reserved exchange and can't be deleted", e.getMessage()); + } + amqDirectExchange = _jmxUtils.getManagedExchange(amqDirectExchangeName); + assertNotNull("Exchange should exist", amqDirectExchange); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java new file mode 100644 index 0000000000..34b13dfaca --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java @@ -0,0 +1,285 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.management.jmx; + +import java.io.IOException; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.management.JMException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.TabularData; + +import org.apache.commons.lang.StringUtils; +import org.apache.qpid.common.QpidProperties; +import org.apache.qpid.management.common.mbeans.ManagedConnection; +import org.apache.qpid.management.common.mbeans.ManagedQueue; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class ConnectionManagementTest extends QpidBrokerTestCase +{ + private static final String VIRTUAL_HOST_NAME = "test"; + + private JMXTestUtils _jmxUtils; + private Connection _connection; + + public void setUp() throws Exception + { + getBrokerConfiguration().addJmxManagementConfiguration(); + + _jmxUtils = new JMXTestUtils(this); + + super.setUp(); + _jmxUtils.open(); + } + + public void tearDown() throws Exception + { + try + { + if (_jmxUtils != null) + { + _jmxUtils.close(); + } + } + finally + { + super.tearDown(); + } + } + + public void testNumberOfManagedConnectionsMatchesNumberOfClientConnections() throws Exception + { + assertEquals("Expected no managed connections", 0, getManagedConnections().size()); + + _connection = getConnection(); + assertEquals("Expected one managed connection", 1, getManagedConnections().size()); + + _connection.close(); + assertEquals("Expected no managed connections after client connection closed", 0, getManagedConnections().size()); + } + + public void testGetAttributes() throws Exception + { + _connection = getConnection(); + final ManagedConnection mBean = getConnectionMBean(); + + checkAuthorisedId(mBean); + checkClientVersion(mBean); + checkClientId(mBean); + } + + public void testNonTransactedSession() throws Exception + { + _connection = getConnection(); + + boolean transactional = false; + boolean flowBlocked = false; + + _connection.createSession(transactional, Session.AUTO_ACKNOWLEDGE); + + final ManagedConnection mBean = getConnectionMBean(); + final CompositeDataSupport row = getTheOneChannelRow(mBean); + assertChannelRowData(row, 0, transactional, flowBlocked); + } + + public void testTransactedSessionWithUnackMessages() throws Exception + { + _connection = getConnection(); + _connection.start(); + + boolean transactional = true; + int numberOfMessages = 2; + final Session session = _connection.createSession(transactional, Session.SESSION_TRANSACTED); + final Destination destination = session.createQueue(getTestQueueName()); + final MessageConsumer consumer = session.createConsumer(destination); + + sendMessage(session, destination, numberOfMessages); + receiveMessagesWithoutCommit(consumer, numberOfMessages); + + final ManagedConnection mBean = getConnectionMBean(); + final CompositeDataSupport row = getTheOneChannelRow(mBean); + boolean flowBlocked = false; + assertChannelRowData(row, numberOfMessages, transactional, flowBlocked); + + // check that commit advances the lastIoTime + final Date initialLastIOTime = mBean.getLastIoTime(); + session.commit(); + assertTrue("commit should have caused last IO time to advance", mBean.getLastIoTime().after(initialLastIOTime)); + + // check that channels() now returns one session with no unacknowledged messages + final CompositeDataSupport rowAfterCommit = getTheOneChannelRow(mBean); + final Number unackCountAfterCommit = (Number) rowAfterCommit.get(ManagedConnection.UNACKED_COUNT); + assertEquals("Unexpected number of unacknowledged messages", 0, unackCountAfterCommit); + } + + + public void testProducerFlowBlocked() throws Exception + { + _connection = getConnection(); + _connection.start(); + + String queueName = getTestQueueName(); + Session session = _connection.createSession(true, Session.SESSION_TRANSACTED); + Queue queue = session.createQueue(queueName); + createQueueOnBroker(session, queue); + + ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + managedQueue.setFlowResumeCapacity(DEFAULT_MESSAGE_SIZE * 2l); + managedQueue.setCapacity(DEFAULT_MESSAGE_SIZE * 3l); + + final ManagedConnection managedConnection = getConnectionMBean(); + + // Check that producer flow is not block before test + final CompositeDataSupport rowBeforeSend = getTheOneChannelRow(managedConnection); + assertFlowBlocked(rowBeforeSend, false); + + + // Check that producer flow does not become block too soon + sendMessage(session, queue, 3); + final CompositeDataSupport rowBeforeFull = getTheOneChannelRow(managedConnection); + assertFlowBlocked(rowBeforeFull, false); + + // Fourth message will over-fill the queue (but as we are not sending more messages, client thread wont't block) + sendMessage(session, queue, 1); + final CompositeDataSupport rowAfterFull = getTheOneChannelRow(managedConnection); + assertFlowBlocked(rowAfterFull, true); + + // Consume two to bring the queue down to the resume capacity + MessageConsumer consumer = session.createConsumer(queue); + assertNotNull("Could not receive first message", consumer.receive(1000)); + assertNotNull("Could not receive second message", consumer.receive(1000)); + session.commit(); + + // Check that producer flow is no longer blocked + final CompositeDataSupport rowAfterReceive = getTheOneChannelRow(managedConnection); + assertFlowBlocked(rowAfterReceive, false); + } + + private void createQueueOnBroker(Session session, Destination destination) throws JMSException + { + session.createConsumer(destination).close(); // Create a consumer only to cause queue creation + } + + private void assertChannelRowData(final CompositeData row, int unacknowledgedMessages, boolean isTransactional, boolean flowBlocked) + { + assertNotNull(row); + assertEquals("Unexpected transactional flag", isTransactional, row.get(ManagedConnection.TRANSACTIONAL)); + assertEquals("Unexpected unacknowledged message count", unacknowledgedMessages, row.get(ManagedConnection.UNACKED_COUNT)); + assertEquals("Unexpected flow blocked", flowBlocked, row.get(ManagedConnection.FLOW_BLOCKED)); + } + + private void assertFlowBlocked(final CompositeData row, boolean flowBlocked) + { + assertNotNull(row); + assertEquals("Unexpected flow blocked", flowBlocked, row.get(ManagedConnection.FLOW_BLOCKED)); + } + + private void checkAuthorisedId(ManagedConnection mBean) throws Exception + { + assertEquals("Unexpected authorized id", GUEST_USERNAME, mBean.getAuthorizedId()); + } + + private void checkClientVersion(ManagedConnection mBean) throws Exception + { + String expectedVersion = QpidProperties.getReleaseVersion(); + assertTrue(StringUtils.isNotBlank(expectedVersion)); + + assertEquals("Unexpected version", expectedVersion, mBean.getVersion()); + } + + private void checkClientId(ManagedConnection mBean) throws Exception + { + String expectedClientId = _connection.getClientID(); + assertTrue(StringUtils.isNotBlank(expectedClientId)); + + assertEquals("Unexpected ClientId", expectedClientId, mBean.getClientId()); + } + + private ManagedConnection getConnectionMBean() + { + List connections = getManagedConnections(); + assertNotNull("Connection MBean is not found", connections); + assertEquals("Unexpected number of connection mbeans", 1, connections.size()); + final ManagedConnection mBean = connections.get(0); + assertNotNull("Connection MBean is null", mBean); + return mBean; + } + + private List getManagedConnections() + { + return _jmxUtils.getManagedConnections(VIRTUAL_HOST_NAME); + } + + private CompositeDataSupport getTheOneChannelRow(final ManagedConnection mBean) throws Exception + { + TabularData channelsData = getChannelsDataWithRetry(mBean); + + assertEquals("Unexpected number of rows in channel table", 1, channelsData.size()); + + @SuppressWarnings("unchecked") + final Iterator rowItr = (Iterator) channelsData.values().iterator(); + final CompositeDataSupport row = rowItr.next(); + return row; + } + + private void receiveMessagesWithoutCommit(final MessageConsumer consumer, int numberOfMessages) throws Exception + { + for (int i = 0; i < numberOfMessages; i++) + { + final Message m = consumer.receive(1000l); + assertNotNull("Message " + i + " is not received", m); + } + } + + private TabularData getChannelsDataWithRetry(final ManagedConnection mBean) + throws IOException, JMException + { + TabularData channelsData = mBean.channels(); + int retries = 0; + while(channelsData.size() == 0 && retries < 5) + { + sleep(); + channelsData = mBean.channels(); + retries++; + } + return channelsData; + } + + private void sleep() + { + try + { + Thread.sleep(50); + } + catch (InterruptedException ie) + { + Thread.currentThread().interrupt(); + } + }} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ExchangeManagementTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ExchangeManagementTest.java new file mode 100644 index 0000000000..8c0a11b7cc --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ExchangeManagementTest.java @@ -0,0 +1,164 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.management.jmx; + +import java.util.Collections; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.qpid.common.AMQPFilterTypes; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.management.common.mbeans.ManagedBroker; +import org.apache.qpid.management.common.mbeans.ManagedExchange; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class ExchangeManagementTest extends QpidBrokerTestCase +{ + private static final String MESSAGE_PROPERTY_INDEX = "index"; + private static final String MESSAGE_PROPERTY_TEST = "test"; + private static final String MESSAGE_PROPERTY_DUMMY = "dummy"; + private static final String SELECTOR_ARGUMENT = AMQPFilterTypes.JMS_SELECTOR.toString(); + private static final String SELECTOR = MESSAGE_PROPERTY_TEST + "='test'"; + private static final String VIRTUAL_HOST = "test"; + + private JMXTestUtils _jmxUtils; + private ManagedBroker _managedBroker; + private String _testQueueName; + private ManagedExchange _directExchange; + private ManagedExchange _topicExchange; + private ManagedExchange _fanoutExchange; + private ManagedExchange _headersExchange; + private Connection _connection; + private Session _session; + + public void setUp() throws Exception + { + getBrokerConfiguration().addJmxManagementConfiguration(); + + // to test exchange selectors the publishing of unroutable messages should be allowed + getBrokerConfiguration().setBrokerAttribute(Broker.CONNECTION_CLOSE_WHEN_NO_ROUTE, false); + + _jmxUtils = new JMXTestUtils(this); + + super.setUp(); + + _jmxUtils.open(); + + _managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST); + _testQueueName = getTestName(); + _managedBroker.createNewQueue(_testQueueName, null, true); + _directExchange = _jmxUtils.getManagedExchange(ExchangeDefaults.DIRECT_EXCHANGE_NAME); + _topicExchange = _jmxUtils.getManagedExchange(ExchangeDefaults.TOPIC_EXCHANGE_NAME); + _fanoutExchange = _jmxUtils.getManagedExchange(ExchangeDefaults.FANOUT_EXCHANGE_NAME); + _headersExchange = _jmxUtils.getManagedExchange(ExchangeDefaults.HEADERS_EXCHANGE_NAME); + + _connection = getConnection(); + _connection.start(); + _session = _connection.createSession(true, Session.SESSION_TRANSACTED); + } + + public void testCreateNewBindingWithArgumentsOnDirectExchange() throws Exception + { + String bindingKey = "test-direct-binding"; + + _directExchange.createNewBinding(_testQueueName, bindingKey, + Collections. singletonMap(SELECTOR_ARGUMENT, SELECTOR)); + + bindingTest(_session.createQueue(bindingKey)); + } + + public void testCreateNewBindingWithArgumentsOnTopicExchange() throws Exception + { + String bindingKey = "test-topic-binding"; + + _topicExchange.createNewBinding(_testQueueName, bindingKey, + Collections. singletonMap(SELECTOR_ARGUMENT, SELECTOR)); + + bindingTest(_session.createTopic(bindingKey)); + } + + public void testCreateNewBindingWithArgumentsOnFanoutExchange() throws Exception + { + _fanoutExchange.createNewBinding(_testQueueName, null, + Collections. singletonMap(SELECTOR_ARGUMENT, SELECTOR)); + + bindingTest(_session.createQueue("fanout://amq.fanout//?routingkey='routing-key-must-not-be-null'")); + } + + public void testCreateNewBindingWithArgumentsOnHeadersExchange() throws Exception + { + // headers exchange uses 'dummy' property to match messages + // i.e. all test messages have matching header value + _headersExchange.createNewBinding(_testQueueName, "x-match=any,dummy=test", + Collections. singletonMap(SELECTOR_ARGUMENT, SELECTOR)); + + bindingTest(_session.createQueue("headers://amq.match//?routingkey='routing-key-must-not-be-null'")); + } + + private void bindingTest(Destination destination) throws JMSException + { + publishMessages(destination, 4); + receiveAndAssertMessages(2); + } + + private void publishMessages(Destination destination, int messageNumber) throws JMSException + { + MessageProducer producer = _session.createProducer(destination); + + for (int i = 0; i < messageNumber; i++) + { + Message m = _session.createMessage(); + m.setStringProperty(MESSAGE_PROPERTY_TEST, i % 2 == 0 ? MESSAGE_PROPERTY_TEST : ""); + m.setIntProperty(MESSAGE_PROPERTY_INDEX, i); + m.setStringProperty(MESSAGE_PROPERTY_DUMMY, "test"); + producer.send(m); + } + _session.commit(); + } + + private void receiveAndAssertMessages(int messageNumber) throws JMSException + { + MessageConsumer consumer = _session.createConsumer(_session.createQueue(_testQueueName)); + + for (int i = 0; i < messageNumber; i++) + { + int index = i * 2; + Message message = consumer.receive(1000l); + assertNotNull("Expected message is not received at " + i, message); + assertEquals("Unexpected test property at " + i, MESSAGE_PROPERTY_TEST, + message.getStringProperty(MESSAGE_PROPERTY_TEST)); + assertEquals("Unexpected index property at " + i, index, message.getIntProperty(MESSAGE_PROPERTY_INDEX)); + } + + Message message = consumer.receive(1000l); + assertNull("Unexpected message received", message); + _session.commit(); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java new file mode 100644 index 0000000000..3717c1594d --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.systest.management.jmx; + +import java.io.File; +import java.util.List; + +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularData; + +import org.apache.qpid.management.common.mbeans.LoggingManagement; +import org.apache.qpid.server.logging.log4j.LoggingManagementFacadeTest; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.util.FileUtils; +import org.apache.qpid.util.LogMonitor; + +/** + * System test for Logging Management. These tests rely on value set within + * test-profiles/log4j-test.xml. + * + * @see LoggingManagementMBeanTest + * @see LoggingManagementFacadeTest + * + */ +public class LoggingManagementTest extends QpidBrokerTestCase +{ + private JMXTestUtils _jmxUtils; + private LoggingManagement _loggingManagement; + private LogMonitor _monitor; + + public void setUp() throws Exception + { + getBrokerConfiguration().addJmxManagementConfiguration(); + + _jmxUtils = new JMXTestUtils(this); + + // System test normally run with log for4j test config from beneath test-profiles. We need to + // copy it as some of our tests write to this file. + + File tmpLogFile = File.createTempFile("log4j" + "." + getName(), ".xml"); + tmpLogFile.deleteOnExit(); + FileUtils.copy(getBrokerCommandLog4JFile(), tmpLogFile); + setBrokerCommandLog4JFile(tmpLogFile); + + super.setUp(); + _jmxUtils.open(); + + _loggingManagement = _jmxUtils.getLoggingManagement(); + _monitor = new LogMonitor(_outputFile); + } + + public void tearDown() throws Exception + { + try + { + if (_jmxUtils != null) + { + _jmxUtils.close(); + } + } + finally + { + super.tearDown(); + } + } + + public void testViewEffectiveRuntimeLoggerLevels() throws Exception + { + final String qpidMainLogger = "org.apache.qpid"; + + TabularData table = _loggingManagement.viewEffectiveRuntimeLoggerLevels(); + final CompositeData row = table.get(new String[] {qpidMainLogger} ); + assertChannelRow(row, qpidMainLogger, "DEBUG"); + } + + public void testViewConfigFileLoggerLevels() throws Exception + { + final String operationalLoggingLogger = "qpid.message"; + + TabularData table = _loggingManagement.viewConfigFileLoggerLevels(); + final CompositeData row = table.get(new String[] {operationalLoggingLogger} ); + assertChannelRow(row, operationalLoggingLogger, "INFO"); + } + + public void testTurnOffOrgApacheQpidAtRuntime() throws Exception + { + final String logger = "org.apache.qpid"; + _monitor.markDiscardPoint(); + _loggingManagement.setRuntimeLoggerLevel(logger, "OFF"); + + List matches = _monitor.waitAndFindMatches("Setting level to OFF for logger 'org.apache.qpid'", 5000); + assertEquals(1, matches.size()); + + TabularData table = _loggingManagement.viewEffectiveRuntimeLoggerLevels(); + final CompositeData row1 = table.get(new String[] {logger} ); + assertChannelRow(row1, logger, "OFF"); + } + + public void testChangesToConfigFileBecomeEffectiveAfterReload() throws Exception + { + final String operationalLoggingLogger = "qpid.message"; + assertEffectiveLoggingLevel(operationalLoggingLogger, "INFO"); + + _monitor.markDiscardPoint(); + _loggingManagement.setConfigFileLoggerLevel(operationalLoggingLogger, "OFF"); + + List matches = _monitor.waitAndFindMatches("Setting level to OFF for logger 'qpid.message'", 5000); + assertEquals(1, matches.size()); + + assertEffectiveLoggingLevel(operationalLoggingLogger, "INFO"); + + _loggingManagement.reloadConfigFile(); + + assertEffectiveLoggingLevel(operationalLoggingLogger, "OFF"); + } + + private void assertEffectiveLoggingLevel(String operationalLoggingLogger, String expectedLevel) + { + TabularData table = _loggingManagement.viewEffectiveRuntimeLoggerLevels(); + final CompositeData row1 = table.get(new String[] {operationalLoggingLogger} ); + assertChannelRow(row1, operationalLoggingLogger, expectedLevel); + } + + private void assertChannelRow(final CompositeData row, String logger, String level) + { + assertNotNull("No row for " + logger, row); + assertEquals("Unexpected logger name", logger, row.get(LoggingManagement.LOGGER_NAME)); + assertEquals("Unexpected level", level, row.get(LoggingManagement.LOGGER_LEVEL)); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/MBeanLifeCycleTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/MBeanLifeCycleTest.java new file mode 100644 index 0000000000..71f911627e --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/MBeanLifeCycleTest.java @@ -0,0 +1,140 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.systest.management.jmx; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.management.ObjectName; +import javax.servlet.http.HttpServletResponse; + +import org.apache.qpid.management.common.mbeans.ManagedBroker; +import org.apache.qpid.server.management.plugin.HttpManagement; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.VirtualHostNode; +import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager; +import org.apache.qpid.server.virtualhost.ProvidedStoreVirtualHostImpl; +import org.apache.qpid.server.virtualhostnode.memory.MemoryVirtualHostNode; +import org.apache.qpid.systest.rest.QpidRestTestCase; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class MBeanLifeCycleTest extends QpidRestTestCase +{ + private final static String TEST_VIRTUAL_HOST_MBEAN_SEARCH_QUERY = "org.apache.qpid:type=VirtualHost.VirtualHostManager,VirtualHost=" + + ObjectName.quote(TEST2_VIRTUALHOST); + private JMXTestUtils _jmxUtils; + + @Override + public void setUp() throws Exception + { + super.setUp(); + _jmxUtils = new JMXTestUtils(this); + _jmxUtils.open(); + } + + @Override + protected void customizeConfiguration() throws IOException + { + TestBrokerConfiguration config = getBrokerConfiguration(); + config.addHttpManagementConfiguration(); + config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.PORT, getRestTestHelper().getHttpPort()); + + Map anonymousProviderAttributes = new HashMap(); + anonymousProviderAttributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); + anonymousProviderAttributes.put(AuthenticationProvider.NAME, ANONYMOUS_AUTHENTICATION_PROVIDER); + config.addObjectConfiguration(AuthenticationProvider.class, anonymousProviderAttributes); + + // set password authentication provider on http port for the tests + config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER, + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); + config.setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); + getBrokerConfiguration().addJmxManagementConfiguration(); + } + + @Override + public void tearDown() throws Exception + { + if (_jmxUtils != null) + { + _jmxUtils.close(); + } + super.tearDown(); + } + + public void testVirtualHostMBeanIsRegisteredOnVirtualHostCreation() throws Exception + { + String nodeName = "ntmp"; + String hostName = "htmp"; + + Map nodeData = new HashMap<>(); + nodeData.put(VirtualHostNode.NAME, nodeName); + nodeData.put(VirtualHostNode.TYPE, MemoryVirtualHostNode.VIRTUAL_HOST_NODE_TYPE); + getRestTestHelper().submitRequest("virtualhostnode/" + nodeName, "PUT", nodeData, HttpServletResponse.SC_CREATED); + + Map virtualhostData = new HashMap<>(); + virtualhostData.put(VirtualHost.NAME, nodeName); + virtualhostData.put(VirtualHost.TYPE, ProvidedStoreVirtualHostImpl.VIRTUAL_HOST_TYPE); + getRestTestHelper().submitRequest("virtualhost/" + nodeName + "/" + hostName, + "PUT", + virtualhostData, + HttpServletResponse.SC_CREATED); + + + ManagedBroker managedBroker = _jmxUtils.getManagedBroker(hostName); + assertNotNull("Host mBean is not created", managedBroker); + } + + public void testVirtualHostMBeanIsUnregisteredOnVirtualHostDeletion() throws Exception + { + boolean mBeanExists =_jmxUtils.doesManagedObjectExist(TEST_VIRTUAL_HOST_MBEAN_SEARCH_QUERY); + assertTrue("Host mBean is not registered", mBeanExists); + + getRestTestHelper().submitRequest("virtualhostnode/" + TEST2_VIRTUALHOST, "DELETE", HttpServletResponse.SC_OK); + + mBeanExists =_jmxUtils.doesManagedObjectExist(TEST_VIRTUAL_HOST_MBEAN_SEARCH_QUERY); + assertFalse("Host mBean is not unregistered", mBeanExists); + } + + public void testVirtualHostMBeanIsUnregisteredOnVirtualHostNodeStop() throws Exception + { + boolean mBeanExists =_jmxUtils.doesManagedObjectExist(TEST_VIRTUAL_HOST_MBEAN_SEARCH_QUERY); + assertTrue("Host mBean is not registered", mBeanExists); + + ManagedBroker managedBroker = _jmxUtils.getManagedBroker(TEST2_VIRTUALHOST); + assertNotNull("Host mBean is not created", managedBroker); + + Map nodeData = new HashMap(); + nodeData.put(VirtualHostNode.NAME, TEST2_VIRTUALHOST); + nodeData.put(VirtualHostNode.DESIRED_STATE, State.STOPPED.name()); + + int status = getRestTestHelper().submitRequest("virtualhostnode/" + TEST2_VIRTUALHOST, "PUT", nodeData); + assertEquals("Unexpected code", 200, status); + + mBeanExists =_jmxUtils.doesManagedObjectExist(TEST_VIRTUAL_HOST_MBEAN_SEARCH_QUERY); + assertFalse("Host mBean is not unregistered", mBeanExists); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java new file mode 100644 index 0000000000..4358b4b450 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java @@ -0,0 +1,482 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.management.jmx; + +import org.apache.qpid.management.common.mbeans.ManagedBroker; +import org.apache.qpid.management.common.mbeans.ManagedConnection; +import org.apache.qpid.management.common.mbeans.ManagedExchange; +import org.apache.qpid.server.logging.AbstractTestLogging; +import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject; +import org.apache.qpid.test.utils.JMXTestUtils; + +import javax.jms.Connection; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.management.JMException; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * Test class to test if any change in the broker JMX code is affesting the management console + * There are some hardcoding of management feature names and parameter names to create a customized + * look in the console. + */ +public class ManagementActorLoggingTest extends AbstractTestLogging +{ + private JMXTestUtils _jmxUtils; + private boolean _closed = false; + + @Override + public void setUp() throws Exception + { + getBrokerConfiguration().addJmxManagementConfiguration(); + + _jmxUtils = new JMXTestUtils(this); + + super.setUp(); + _jmxUtils.open(); + } + + @Override + public void tearDown() throws Exception + { + if(!_closed) + { + _jmxUtils.close(); + } + super.tearDown(); + } + + /** + * Description: + * When a connected client has its connection closed via the Management Console this will be logged as a CON-1002 message. + * Input: + * + * 1. Running Broker + * 2. Connected Client + * 3. Connection is closed via Management Console + * Output: + * + * CON-1002 : Close + * + * Validation Steps: + * 4. The CON ID is correct + * 5. This must be the last CON message for the Connection + * 6. It must be preceded by a CON-1001 for this Connection + * + * @throws Exception - {@see ManagedConnection.closeConnection and #getConnection} + * @throws java.io.IOException - if there is a problem reseting the log monitor + */ + public void testConnectionCloseViaManagement() throws IOException, Exception + { + //Create a connection to the broker + Connection connection = getConnection(); + + // Monitor the connection for an exception being thrown + // this should be a DisconnectionException but it is not this tests + // job to valiate that. Only use the exception as a synchronisation + // to check the log file for the Close message + final CountDownLatch exceptionReceived = new CountDownLatch(1); + connection.setExceptionListener(new ExceptionListener() + { + public void onException(JMSException e) + { + //Failover being attempted. + exceptionReceived.countDown(); + } + }); + + //Remove the connection close from any 0-10 connections + _monitor.markDiscardPoint(); + + // Get a managedConnection + ManagedConnection mangedConnection = _jmxUtils.getManagedObject(ManagedConnection.class, "org.apache.qpid:type=VirtualHost.Connection,*"); + + //Close the connection + mangedConnection.closeConnection(); + + //Wait for the connection to close + assertTrue("Timed out waiting for conneciton to report close", + exceptionReceived.await(2, TimeUnit.SECONDS)); + + //Validate results + List results = waitAndFindMatches("CON-1002"); + + assertEquals("Unexpected Connection Close count", 1, results.size()); + } + + /** + * Description: + * Exchange creation is possible from the Management Console. + * When an exchanged is created in this way then a EXH-1001 create message + * is expected to be logged. + * Input: + * + * 1. Running broker + * 2. Connected Management Console + * 3. Exchange Created via Management Console + * Output: + * + * EXH-1001 : Create : [Durable] Type: Name: + * + * Validation Steps: + * 4. The EXH ID is correct + * 5. The correct tags are present in the message based on the create options + * + * @throws java.io.IOException - if there is a problem reseting the log monitor + * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.deleteQueue} + */ + public void testCreateExchangeDirectTransientViaManagementConsole() throws IOException, JMException + { + _monitor.markDiscardPoint(); + + _jmxUtils.createExchange("test", getName(), "direct", false); + + // Validate + + //1 - ID is correct + List results = waitAndFindMatches("EXH-1001"); + + assertEquals("More than one exchange creation found", 1, results.size()); + + String log = getLogMessage(results, 0); + + // Validate correct exchange name + assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName())); + + // Validate it was a management actor. + String actor = fromActor(log); + assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); + } + + public void testCreateExchangeTopicTransientViaManagementConsole() throws IOException, JMException + { + //Remove any previous exchange declares + _monitor.markDiscardPoint(); + + _jmxUtils.createExchange("test", getName(), "topic", false); + + // Validate + + //1 - ID is correct + List results = waitAndFindMatches("EXH-1001"); + + assertEquals("More than one exchange creation found", 1, results.size()); + + String log = getLogMessage(results, 0); + + // Validate correct exchange name + assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName())); + + // Validate it was a management actor. + String actor = fromActor(log); + assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); + + } + + public void testCreateExchangeFanoutTransientViaManagementConsole() throws IOException, JMException + { + //Remove any previous exchange declares + _monitor.markDiscardPoint(); + + _jmxUtils.createExchange("test", getName(), "fanout", false); + + // Validate + + //1 - ID is correct + List results = waitAndFindMatches("EXH-1001"); + + assertEquals("More than one exchange creation found", 1, results.size()); + + String log = getLogMessage(results, 0); + + // Validate correct exchange name + assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName())); + + // Validate it was a management actor. + String actor = fromActor(log); + assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); + + } + + public void testCreateExchangeHeadersTransientViaManagementConsole() throws IOException, JMException + { + //Remove any previous exchange declares + _monitor.markDiscardPoint(); + + _jmxUtils.createExchange("test", getName(), "headers", false); + + // Validate + + //1 - ID is correct + List results = waitAndFindMatches("EXH-1001"); + + assertEquals("More than one exchange creation found", 1, results.size()); + + String log = getLogMessage(results, 0); + + // Validate correct exchange name + assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName())); + + // Validate it was a management actor. + String actor = fromActor(log); + assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); + + } + + /** + * Description: + * Queue creation is possible from the Management Console. When a queue is created in this way then a QUE-1001 create message is expected to be logged. + * Input: + * + * 1. Running broker + * 2. Connected Management Console + * 3. Queue Created via Management Console + * Output: + * + * QUE-1001 : Create : Transient Owner: + * + * Validation Steps: + * 4. The QUE ID is correct + * 5. The correct tags are present in the message based on the create options + * + * @throws java.io.IOException - if there is a problem reseting the log monitor + * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.deleteQueue} + */ + public void testCreateQueueTransientViaManagementConsole() throws IOException, JMException + { + //Remove any previous queue declares + _monitor.markDiscardPoint(); + + _jmxUtils.createQueue("test", getName(), null, false); + + // Validate + + List results = waitAndFindMatches("QUE-1001"); + + assertEquals("More than one queue creation found", 1, results.size()); + + String log = getLogMessage(results, 0); + + // Validate correct queue name + String subject = fromSubject(log); + assertEquals("Incorrect queue name created", getName(), AbstractTestLogSubject.getSlice("qu", subject)); + + // Validate it was a management actor. + String actor = fromActor(log); + assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); + } + + /** + * Description: + * The ManagementConsole can be used to delete a queue. When this is done a QUE-1002 Deleted message must be logged. + * Input: + * + * 1. Running Broker + * 2. Queue created on the broker with no subscribers + * 3. Management Console connected + * 4. Queue is deleted via Management Console + * Output: + * + * QUE-1002 : Deleted + * + * Validation Steps: + * 5. The QUE ID is correct + * + * @throws java.io.IOException - if there is a problem reseting the log monitor + * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.deleteQueue} + */ + public void testQueueDeleteViaManagementConsole() throws IOException, JMException + { + //Remove any previous queue declares + _monitor.markDiscardPoint(); + + _jmxUtils.createQueue("test", getName(), null, false); + + ManagedBroker managedBroker = _jmxUtils.getManagedBroker("test"); + + managedBroker.deleteQueue(getName()); + + List results = waitAndFindMatches("QUE-1002"); + + assertEquals("More than one queue deletion found", 1, results.size()); + + String log = getLog(results.get(0)); + + // Validate correct binding + String subject = fromSubject(log); + assertEquals("Incorrect queue named in delete", getName(), AbstractTestLogSubject.getSlice("qu", subject)); + + // Validate it was a management actor. + String actor = fromActor(log); + assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); + + } + + /** + * Description: + * The binding of a Queue and an Exchange is done via a Binding. When this Binding is created via the Management Console a BND-1001 Create message will be logged. + * Input: + * + * 1. Running Broker + * 2. Connected Management Console + * 3. Use Management Console to perform binding + * Output: + * + * BND-1001 : Create + * + * Validation Steps: + * 4. The BND ID is correct + * 5. This will be the first message for the given binding + * + * @throws java.io.IOException - if there is a problem reseting the log monitor + * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.createNewBinding} + */ + public void testBindingCreateOnDirectViaManagementConsole() throws IOException, JMException + { + //Remove any previous queue declares + _monitor.markDiscardPoint(); + + _jmxUtils.createQueue("test", getName(), null, false); + + ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.direct"); + + managedExchange.createNewBinding(getName(), getName()); + + List results = waitAndFindMatches("BND-1001"); + + assertEquals("Unexpected number of bindings logged", 1, results.size()); + + String log = getLogMessage(results, 0); + + // Validate correct binding + String subject = fromSubject(log); + assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject)); + assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject)); + + // Validate it was a management actor. + String actor = fromActor(log); + assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); + } + + public void testBindingCreateOnTopicViaManagementConsole() throws IOException, JMException + { + //Remove any previous queue declares + _monitor.markDiscardPoint(); + + _jmxUtils.createQueue("test", getName(), null, false); + + ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.topic"); + + managedExchange.createNewBinding(getName(), getName()); + + List results = waitAndFindMatches("BND-1001"); + + assertEquals("Unexpected number of bindings logged", 1, results.size()); + + String log = getLogMessage(results, 0); + + // Validate correct binding + String subject = fromSubject(log); + assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject)); + assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject)); + + // Validate it was a management actor. + String actor = fromActor(log); + assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); + } + + public void testBindingCreateOnFanoutViaManagementConsole() throws IOException, JMException + { + //Remove any previous queue declares + _monitor.markDiscardPoint(); + + _jmxUtils.createQueue("test", getName(), null, false); + + ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.fanout"); + + managedExchange.createNewBinding(getName(), getName()); + + List results = waitAndFindMatches("BND-1001"); + + assertEquals("Unexpected number of bindings logged", 1, results.size()); + + String log = getLogMessage(results, 0); + + // Validate correct binding + String subject = fromSubject(log); + assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject)); + assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject)); + + // Validate it was a management actor. + String actor = fromActor(log); + assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); + } + + /** + * Description: + * Bindings can be deleted so that a queue can be rebound with a different set of values. This can be performed via the Management Console + * Input: + * + * 1. Running Broker + * 2. Management Console connected + * 3. Management Console is used to perform unbind. + * Output: + * + * BND-1002 : Deleted + * + * Validation Steps: + * 4. The BND ID is correct + * 5. There must have been a BND-1001 Create message first. + * 6. This will be the last message for the given binding + * + * @throws java.io.IOException - if there is a problem reseting the log monitor or an issue with the JMX Connection + * @throws javax.management.JMException - {@see #createExchange and ManagedBroker.unregisterExchange} + */ + public void testUnRegisterExchangeViaManagementConsole() throws IOException, JMException + { + //Remove any previous queue declares + _monitor.markDiscardPoint(); + + _jmxUtils.createExchange("test", getName(), "direct", false); + + ManagedBroker managedBroker = _jmxUtils.getManagedBroker("test"); + + managedBroker.unregisterExchange(getName()); + + List results = waitAndFindMatches("EXH-1002"); + + assertEquals("More than one exchange deletion found", 1, results.size()); + + String log = getLog(results.get(0)); + + // Validate correct binding + String subject = fromSubject(log); + assertEquals("Incorrect exchange named in delete", "direct/" + getName(), AbstractTestLogSubject.getSlice("ex", subject)); + + // Validate it was a management actor. + String actor = fromActor(log); + assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java new file mode 100644 index 0000000000..cb6eae013e --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java @@ -0,0 +1,324 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.management.jmx; + + +import java.util.Collections; +import java.util.List; + +import org.apache.qpid.server.logging.AbstractTestLogging; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Transport; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.util.LogMonitor; + +/** + * Management Console Test Suite + * + * The Management Console test suite validates that the follow log messages as specified in the Functional Specification. + * + * This suite of tests validate that the management console messages occur correctly and according to the following format: + * + * MNG-1001 : Management Startup + * MNG-1002 : Starting : : Listening on port + * MNG-1003 : Shutting down : : port + * MNG-1004 : Management Ready + * MNG-1005 : Management Stopped + * MNG-1006 : Using SSL Keystore : + * MNG-1007 : Open : User + * MNG-1008 : Close : User + */ +public class ManagementLoggingTest extends AbstractTestLogging +{ + private static final String MNG_PREFIX = "MNG-"; + + public void setUp() throws Exception + { + setLogMessagePrefix(); + + // We either do this here or have a null check in tearDown. + // As when this test is run against profiles other than java it will NPE + _monitor = new LogMonitor(_outputFile); + //We explicitly do not call super.setUp as starting up the broker is + //part of the test case. + + } + + /** + * Description: + * Using the startup configuration validate that the management startup + * message is logged correctly. + * Input: + * Standard configuration with management enabled + * Output: + * + * MNG-1001 : Startup + * + * Constraints: + * This is the FIRST message logged by MNG + * Validation Steps: + * + * 1. The BRK ID is correct + * 2. This is the FIRST message logged by MNG + */ + public void testManagementStartupEnabled() throws Exception + { + // This test only works on java brokers + if (isJavaBroker()) + { + startBrokerAndCreateMonitor(true, false); + + // Ensure we have received the MNG log msg. + waitForMessage("MNG-1001"); + + List results = findMatches(MNG_PREFIX); + // Validation + + assertTrue("MNGer message not logged", results.size() > 0); + + String log = getLogMessage(results, 0); + + //1 + validateMessageID("MNG-1001", log); + + //2 + //There will be 2 copies of the startup message (one via SystemOut, and one via Log4J) + results = findMatches("MNG-1001"); + assertEquals("Unexpected startup message count.", + 2, results.size()); + + //3 + assertEquals("Startup log message is not 'Startup'.", "JMX Management Startup", + getMessageString(log)); + } + } + + /** + * Description: + * Verify that when management is disabled in the configuration file the + * startup message is not logged. + * Input: + * Standard configuration with management disabled + * Output: + * NO MNG messages + * Validation Steps: + * + * 1. Validate that no MNG messages are produced. + */ + public void testManagementStartupDisabled() throws Exception + { + if (isJavaBroker()) + { + startBrokerAndCreateMonitor(false, false); + + List results = findMatches(MNG_PREFIX); + // Validation + + assertEquals("MNGer messages logged", 0, results.size()); + } + } + + /** + * The two MNG-1002 messages are logged at the same time so lets test them + * at the same time. + * + * Description: + * Using the default configuration validate that the RMI Registry socket is + * correctly reported as being opened + * + * Input: + * The default configuration file + * Output: + * + * MESSAGE MNG-1002 : Starting : RMI Registry : Listening on port 8999 + * + * Constraints: + * The RMI ConnectorServer and Registry log messages do not have a prescribed order + * Validation Steps: + * + * 1. The MNG ID is correct + * 2. The specified port is the correct '8999' + * + * Description: + * Using the default configuration validate that the RMI ConnectorServer + * socket is correctly reported as being opened + * + * Input: + * The default configuration file + * Output: + * + * MESSAGE MNG-1002 : Starting : RMI ConnectorServer : Listening on port 9099 + * + * Constraints: + * The RMI ConnectorServer and Registry log messages do not have a prescribed order + * Validation Steps: + * + * 1. The MNG ID is correct + * 2. The specified port is the correct '9099' + */ + public void testManagementStartupRMIEntries() throws Exception + { + if (isJavaBroker()) + { + startBrokerAndCreateMonitor(true, false); + + List results = waitAndFindMatches("MNG-1002"); + // Validation + + //There will be 4 startup messages (two via SystemOut, and two via Log4J) + assertEquals("Unexpected MNG-1002 message count", 4, results.size()); + + String log = getLogMessage(results, 0); + + //1 + validateMessageID("MNG-1002", log); + + //Check the RMI Registry port is as expected + int mPort = getManagementPort(getPort()); + assertTrue("RMI Registry port not as expected(" + mPort + ").:" + getMessageString(log), + getMessageString(log).endsWith(String.valueOf(mPort))); + + log = getLogMessage(results, 2); + + //1 + validateMessageID("MNG-1002", log); + + // We expect the RMI Registry port (the defined 'management port') to be + // 100 lower than the JMX RMIConnector Server Port (the actual JMX server) + int jmxPort = mPort + JMXPORT_CONNECTORSERVER_OFFSET; + assertTrue("JMX RMIConnectorServer port not as expected(" + jmxPort + ").:" + getMessageString(log), + getMessageString(log).endsWith(String.valueOf(jmxPort))); + } + } + + /** + * Description: + * Using the default configuration with SSL enabled for the management port the SSL Keystore path should be reported via MNG-1006 + * Input: + * Management SSL enabled default configuration. + * Output: + * + * MESSAGE MNG-1006 : Using SSL Keystore : test_resources/ssl/keystore.jks + * + * Validation Steps: + * + * 1. The MNG ID is correct + * 2. The keystore path is as specified in the configuration + */ + public void testManagementStartupSSLKeystore() throws Exception + { + if (isJavaBroker()) + { + setSystemProperty("javax.net.debug", "ssl"); + startBrokerAndCreateMonitor(true, true); + + List results = waitAndFindMatches("MNG-1006"); + + assertTrue("MNGer message not logged", results.size() > 0); + + String log = getLogMessage(results, 0); + + //1 + validateMessageID("MNG-1006", log); + + // Validate we only have two MNG-1002 (one via stdout, one via log4j) + results = findMatches("MNG-1006"); + assertEquals("Upexpected SSL Keystore message count", + 2, results.size()); + + // Validate the keystore path is as expected + assertTrue("SSL Keystore entry expected.:" + getMessageString(log), + getMessageString(log).endsWith("systestsKeyStore")); + } + } + + /** + * Description: Tests the management connection open/close are logged correctly. + * + * Output: + * + * MESSAGE MNG-1007 : Open : User + * MESSAGE MNG-1008 : Close : User + * + * Validation Steps: + * + * 1. The MNG ID is correct + * 2. The message and username are correct + */ + public void testManagementUserOpenClose() throws Exception + { + if (isJavaBroker()) + { + startBrokerAndCreateMonitor(true, false); + + final JMXTestUtils jmxUtils = new JMXTestUtils(this); + List openResults = null; + List closeResults = null; + try + { + jmxUtils.open(); + openResults = waitAndFindMatches("MNG-1007"); + } + finally + { + if (jmxUtils != null) + { + jmxUtils.close(); + closeResults = waitAndFindMatches("MNG-1008"); + } + } + + assertNotNull("Management Open results null", openResults.size()); + assertEquals("Management Open logged unexpected number of times", 1, openResults.size()); + + assertNotNull("Management Close results null", closeResults.size()); + assertEquals("Management Close logged unexpected number of times", 1, closeResults.size()); + + final String openMessage = getMessageString(getLogMessage(openResults, 0)); + assertTrue("Unexpected open message " + openMessage, openMessage.endsWith("Open : User admin")); + final String closeMessage = getMessageString(getLogMessage(closeResults, 0)); + assertTrue("Unexpected close message " + closeMessage, closeMessage.endsWith("Close : User admin")); + } + } + + private void startBrokerAndCreateMonitor(boolean managementEnabled, boolean useManagementSSL) throws Exception + { + TestBrokerConfiguration config = getBrokerConfiguration(); + + if (managementEnabled) + { + config.addJmxManagementConfiguration(); + } + + if(useManagementSSL) + { + // This test requires we have ssl, change the transport and add they keystore to the port config + config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_JMX_PORT, Port.TRANSPORTS, Collections.singleton(Transport.SSL)); + config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_JMX_PORT, Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); + } + + startBroker(); + + // Now we can create the monitor as _outputFile will now be defined + _monitor = new LogMonitor(_outputFile); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java new file mode 100644 index 0000000000..d0f133aa73 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java @@ -0,0 +1,869 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.management.jmx; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.management.Notification; +import javax.management.NotificationListener; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularData; +import javax.naming.NamingException; + +import org.apache.commons.lang.time.FastDateFormat; +import org.apache.log4j.Logger; + +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.management.common.mbeans.ManagedBroker; +import org.apache.qpid.management.common.mbeans.ManagedQueue; +import org.apache.qpid.server.queue.NotificationCheckTest; +import org.apache.qpid.server.queue.QueueArgumentsConverter; +import org.apache.qpid.server.queue.StandardQueueImpl; +import org.apache.qpid.test.client.destination.AddressBasedDestinationTest; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +/** + * Tests the JMX API for the Managed Queue. + * + */ +public class QueueManagementTest extends QpidBrokerTestCase +{ + + private static final Logger LOGGER = Logger.getLogger(QueueManagementTest.class); + + private static final String VIRTUAL_HOST = "test"; + private static final String TEST_QUEUE_DESCRIPTION = "my description"; + + private JMXTestUtils _jmxUtils; + private Connection _connection; + private Session _session; + + private String _sourceQueueName; + private String _destinationQueueName; + private Destination _sourceQueue; + private Destination _destinationQueue; + private ManagedQueue _managedSourceQueue; + private ManagedQueue _managedDestinationQueue; + + public void setUp() throws Exception + { + getBrokerConfiguration().addJmxManagementConfiguration(); + + _jmxUtils = new JMXTestUtils(this); + + super.setUp(); + _sourceQueueName = getTestQueueName() + "_src"; + _destinationQueueName = getTestQueueName() + "_dest"; + + createConnectionAndSession(); + + _sourceQueue = _session.createQueue(_sourceQueueName); + _destinationQueue = _session.createQueue(_destinationQueueName); + createQueueOnBroker(_sourceQueue); + createQueueOnBroker(_destinationQueue); + + _jmxUtils.open(); + + createManagementInterfacesForQueues(); + } + + public void tearDown() throws Exception + { + if (_jmxUtils != null) + { + _jmxUtils.close(); + } + super.tearDown(); + } + + public void testQueueAttributes() throws Exception + { + Queue queue = _session.createQueue(getTestQueueName()); + createQueueOnBroker(queue); + + final String queueName = queue.getQueueName(); + + final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + assertEquals("Unexpected name", queueName, managedQueue.getName()); + assertEquals("Unexpected queue type", "standard", managedQueue.getQueueType()); + } + + public void testExclusiveQueueHasJmsClientIdAsOwner() throws Exception + { + final String subName = "testOwner"; + _session.createDurableSubscriber(getTestTopic(), subName); + + final String queueName = _connection.getClientID() + ":" + subName; + + final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + assertNotNull(_connection.getClientID()); + assertEquals("Unexpected owner", _connection.getClientID(), managedQueue.getOwner()); + } + + public void testNonExclusiveQueueHasNoOwner() throws Exception + { + Queue nonExclusiveQueue = _session.createQueue(getTestQueueName()); + createQueueOnBroker(nonExclusiveQueue); + + final String queueName = nonExclusiveQueue.getQueueName(); + + final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + assertNull("Unexpected owner", managedQueue.getOwner()); + } + + public void testSetNewQueueDescriptionOnExistingQueue() throws Exception + { + Queue queue = _session.createQueue(getTestQueueName()); + createQueueOnBroker(queue); + + final String queueName = queue.getQueueName(); + + final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + assertNull("Unexpected description", managedQueue.getDescription()); + + managedQueue.setDescription(TEST_QUEUE_DESCRIPTION); + assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription()); + } + + public void testNewQueueWithDescription() throws Exception + { + String queueName = getTestQueueName(); + Map arguments = Collections.singletonMap(QueueArgumentsConverter.X_QPID_DESCRIPTION, (Object)TEST_QUEUE_DESCRIPTION); + ((AMQSession)_session).createQueue(AMQShortString.valueOf(queueName), false, true, false, arguments); + + final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription()); + } + + /** + * Requires persistent store. + */ + public void testQueueDescriptionSurvivesRestart() throws Exception + { + String queueName = getTestQueueName(); + Map arguments = Collections.singletonMap(QueueArgumentsConverter.X_QPID_DESCRIPTION, (Object)TEST_QUEUE_DESCRIPTION); + + ((AMQSession)_session).createQueue(AMQShortString.valueOf(queueName), false, true, false, arguments); + + ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription()); + + restartBroker(); + + managedQueue = _jmxUtils.getManagedQueue(queueName); + assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription()); + } + + /** + * Tests queue creation with {@link QueueArgumentsConverter#X_QPID_MAXIMUM_DELIVERY_COUNT} argument. Also tests + * that the attribute is exposed correctly through {@link ManagedQueue#getMaximumDeliveryCount()}. + */ + public void testCreateQueueWithMaximumDeliveryCountSet() throws Exception + { + final String queueName = getName(); + final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST); + + final Integer deliveryCount = 1; + final Map arguments = Collections.singletonMap(QueueArgumentsConverter.X_QPID_MAXIMUM_DELIVERY_COUNT, (Object)deliveryCount); + managedBroker.createNewQueue(queueName, null, true, arguments); + + // Ensure the queue exists + assertNotNull("Queue object name expected to exist", _jmxUtils.getQueueObjectName(VIRTUAL_HOST, queueName)); + assertNotNull("Manager queue expected to be available", _jmxUtils.getManagedQueue(queueName)); + + final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + assertEquals("Unexpected maximum delivery count", deliveryCount, managedQueue.getMaximumDeliveryCount()); + } + + public void testCreateQueueWithAlertingThresholdsSet() throws Exception + { + final String queueName = getName(); + final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST); + + final Long maximumMessageCount = 100l; + final Long maximumMessageSize = 200l; + final Long maximumQueueDepth = 300l; + final Long maximumMessageAge = 400l; + final Map arguments = new HashMap(); + arguments.put(QueueArgumentsConverter.X_QPID_MAXIMUM_MESSAGE_COUNT, maximumMessageCount); + arguments.put(QueueArgumentsConverter.X_QPID_MAXIMUM_MESSAGE_SIZE, maximumMessageSize); + arguments.put(QueueArgumentsConverter.X_QPID_MAXIMUM_QUEUE_DEPTH, maximumQueueDepth); + arguments.put(QueueArgumentsConverter.X_QPID_MAXIMUM_MESSAGE_AGE, maximumMessageAge); + + managedBroker.createNewQueue(queueName, null, true, arguments); + + // Ensure the queue exists + assertNotNull("Queue object name expected to exist", _jmxUtils.getQueueObjectName(VIRTUAL_HOST, queueName)); + assertNotNull("Manager queue expected to be available", _jmxUtils.getManagedQueue(queueName)); + + ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + assertEquals("Unexpected maximum message count", maximumMessageCount, managedQueue.getMaximumMessageCount()); + assertEquals("Unexpected maximum message size", maximumMessageSize, managedQueue.getMaximumMessageSize()); + assertEquals("Unexpected maximum queue depth", maximumQueueDepth, managedQueue.getMaximumQueueDepth()); + assertEquals("Unexpected maximum message age", maximumMessageAge, managedQueue.getMaximumMessageAge()); + } + + /** + * Requires 0-10 as relies on ADDR addresses. + * @see AddressBasedDestinationTest for the testing of message routing to the alternate exchange + */ + public void testGetSetAlternateExchange() throws Exception + { + String queueName = getTestQueueName(); + String altExchange = "amq.fanout"; + String addrWithAltExch = String.format("ADDR:%s;{create:always,node:{type:queue,x-declare:{alternate-exchange:'%s'}}}", queueName, altExchange); + Queue queue = _session.createQueue(addrWithAltExch); + + createQueueOnBroker(queue); + + final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + assertEquals("Newly created queue does not have expected alternate exchange", altExchange, managedQueue.getAlternateExchange()); + + String newAltExch = "amq.topic"; + managedQueue.setAlternateExchange(newAltExch); + assertEquals("Unexpected alternate exchange after set", newAltExch, managedQueue.getAlternateExchange()); + } + + /** + * Requires 0-10 as relies on ADDR addresses. + */ + public void testRemoveAlternateExchange() throws Exception + { + String queueName = getTestQueueName(); + String altExchange = "amq.fanout"; + String addrWithAltExch = String.format("ADDR:%s;{create:always,node:{type:queue,x-declare:{alternate-exchange:'%s'}}}", queueName, altExchange); + Queue queue = _session.createQueue(addrWithAltExch); + + createQueueOnBroker(queue); + + final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + assertEquals("Newly created queue does not have expected alternate exchange", altExchange, managedQueue.getAlternateExchange()); + + managedQueue.setAlternateExchange(""); + assertNull("Unexpected alternate exchange after set", managedQueue.getAlternateExchange()); + } + + /** + * Requires persistent store + * Requires 0-10 as relies on ADDR addresses. + */ + public void testAlternateExchangeSurvivesRestart() throws Exception + { + String nonMandatoryExchangeName = "exch" + getName(); + + final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST); + managedBroker.createNewExchange(nonMandatoryExchangeName, "fanout", true); + + String queueName1 = getTestQueueName() + "1"; + String altExchange1 = "amq.fanout"; + String addr1WithAltExch = String.format("ADDR:%s;{create:always,node:{durable: true,type:queue,x-declare:{alternate-exchange:'%s'}}}", queueName1, altExchange1); + Queue queue1 = _session.createQueue(addr1WithAltExch); + + String queueName2 = getTestQueueName() + "2"; + String addr2WithoutAltExch = String.format("ADDR:%s;{create:always,node:{durable: true,type:queue}}", queueName2); + Queue queue2 = _session.createQueue(addr2WithoutAltExch); + + createQueueOnBroker(queue1); + createQueueOnBroker(queue2); + + ManagedQueue managedQueue1 = _jmxUtils.getManagedQueue(queueName1); + assertEquals("Newly created queue1 does not have expected alternate exchange", altExchange1, managedQueue1.getAlternateExchange()); + + ManagedQueue managedQueue2 = _jmxUtils.getManagedQueue(queueName2); + assertNull("Newly created queue2 does not have expected alternate exchange", managedQueue2.getAlternateExchange()); + + String altExchange2 = nonMandatoryExchangeName; + managedQueue2.setAlternateExchange(altExchange2); + + restartBroker(); + + managedQueue1 = _jmxUtils.getManagedQueue(queueName1); + assertEquals("Queue1 does not have expected alternate exchange after restart", altExchange1, managedQueue1.getAlternateExchange()); + + managedQueue2 = _jmxUtils.getManagedQueue(queueName2); + assertEquals("Queue2 does not have expected updated alternate exchange after restart", altExchange2, managedQueue2.getAlternateExchange()); + } + + /** + * Tests the ability to receive queue alerts as JMX notifications. + * + * @see NotificationCheckTest + * @see SimpleAMQQueueTest#testNotificationFiredAsync() + * @see SimpleAMQQueueTest#testNotificationFiredOnEnqueue() + */ + public void testQueueNotification() throws Exception + { + final String queueName = getName(); + final long maximumMessageCount = 3; + + Queue queue = _session.createQueue(queueName); + createQueueOnBroker(queue); + + ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + managedQueue.setMaximumMessageCount(maximumMessageCount); + + RecordingNotificationListener listener = new RecordingNotificationListener(1); + + _jmxUtils.addNotificationListener(_jmxUtils.getQueueObjectName(VIRTUAL_HOST, queueName), listener, null, null); + + // Send two messages - this should *not* trigger the notification + sendMessage(_session, queue, 2); + + assertEquals("Premature notification received", 0, listener.getNumberOfNotificationsReceived()); + + // A further message should trigger the message count alert + sendMessage(_session, queue, 1); + + listener.awaitExpectedNotifications(5, TimeUnit.SECONDS); + + assertEquals("Unexpected number of JMX notifications received", 1, listener.getNumberOfNotificationsReceived()); + + Notification notification = listener.getLastNotification(); + assertEquals("Unexpected notification message", "MESSAGE_COUNT_ALERT 3: Maximum count on queue threshold (3) breached.", notification.getMessage()); + } + + /** + * Tests {@link ManagedQueue#viewMessages(long, long)} interface. + */ + public void testViewSingleMessage() throws Exception + { + final List sentMessages = sendMessage(_session, _sourceQueue, 1); + syncSession(_session); + final Message sentMessage = sentMessages.get(0); + + assertEquals("Unexpected queue depth", 1, _managedSourceQueue.getMessageCount().intValue()); + + // Check the contents of the message + final TabularData tab = _managedSourceQueue.viewMessages(1l, 1l); + assertEquals("Unexpected number of rows in table", 1, tab.size()); + final Iterator rowItr = (Iterator) tab.values().iterator(); + + final CompositeData row1 = rowItr.next(); + assertNotNull("Message should have AMQ message id", row1.get(ManagedQueue.MSG_AMQ_ID)); + assertEquals("Unexpected queue position", 1l, row1.get(ManagedQueue.MSG_QUEUE_POS)); + assertEquals("Unexpected redelivered flag", Boolean.FALSE, row1.get(ManagedQueue.MSG_REDELIVERED)); + + // Check the contents of header (encoded in a string array) + final String[] headerArray = (String[]) row1.get(ManagedQueue.MSG_HEADER); + assertNotNull("Expected message header array", headerArray); + final Map headers = headerArrayToMap(headerArray); + + final String expectedJMSMessageID = isBroker010() ? sentMessage.getJMSMessageID().replace("ID:", "") : sentMessage.getJMSMessageID(); + final String expectedFormattedJMSTimestamp = FastDateFormat.getInstance(ManagedQueue.JMSTIMESTAMP_DATETIME_FORMAT).format(sentMessage.getJMSTimestamp()); + assertEquals("Unexpected JMSMessageID within header", expectedJMSMessageID, headers.get("JMSMessageID")); + assertEquals("Unexpected JMSPriority within header", String.valueOf(sentMessage.getJMSPriority()), headers.get("JMSPriority")); + assertEquals("Unexpected JMSTimestamp within header", expectedFormattedJMSTimestamp, headers.get("JMSTimestamp")); + } + + /** + * Tests {@link ManagedQueue#moveMessages(long, long, String)} interface. + */ + public void testMoveMessagesBetweenQueues() throws Exception + { + final int numberOfMessagesToSend = 10; + + sendMessage(_session, _sourceQueue, numberOfMessagesToSend); + syncSession(_session); + assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); + + List amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); + + // Move first three messages to destination + long fromMessageId = amqMessagesIds.get(0); + long toMessageId = amqMessagesIds.get(2); + _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName); + + assertEquals("Unexpected queue depth on destination queue after first move", 3, _managedDestinationQueue.getMessageCount().intValue()); + assertEquals("Unexpected queue depth on source queue after first move", 7, _managedSourceQueue.getMessageCount().intValue()); + + // Now move a further two messages to destination + fromMessageId = amqMessagesIds.get(7); + toMessageId = amqMessagesIds.get(8); + _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName); + assertEquals("Unexpected queue depth on destination queue after second move", 5, _managedDestinationQueue.getMessageCount().intValue()); + assertEquals("Unexpected queue depth on source queue after second move", 5, _managedSourceQueue.getMessageCount().intValue()); + + assertMessageIndicesOn(_destinationQueue, 0, 1, 2, 7, 8); + } + + /** + * Tests {@link ManagedQueue#copyMessages(long, long, String)} interface. + */ + public void testCopyMessagesBetweenQueues() throws Exception + { + final int numberOfMessagesToSend = 10; + sendMessage(_session, _sourceQueue, numberOfMessagesToSend); + syncSession(_session); + assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); + + List amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); + + // Copy first three messages to destination + long fromMessageId = amqMessagesIds.get(0); + long toMessageId = amqMessagesIds.get(2); + _managedSourceQueue.copyMessages(fromMessageId, toMessageId, _destinationQueueName); + + assertEquals("Unexpected queue depth on destination queue after first copy", 3, _managedDestinationQueue.getMessageCount().intValue()); + assertEquals("Unexpected queue depth on source queue after first copy", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); + + // Now copy a further two messages to destination + fromMessageId = amqMessagesIds.get(7); + toMessageId = amqMessagesIds.get(8); + _managedSourceQueue.copyMessages(fromMessageId, toMessageId, _destinationQueueName); + assertEquals("Unexpected queue depth on destination queue after second copy", 5, _managedDestinationQueue.getMessageCount().intValue()); + assertEquals("Unexpected queue depth on source queue after second copy", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); + + assertMessageIndicesOn(_destinationQueue, 0, 1, 2, 7, 8); + } + + + /** + * Tests {@link ManagedQueue#copyMessages(long, long, String)} interface. + */ + public void testCopyMessagesBetweenQueuesWithDuplicates() throws Exception + { + final int numberOfMessagesToSend = 10; + sendMessage(_session, _sourceQueue, numberOfMessagesToSend); + syncSession(_session); + assertEquals("Unexpected queue depth after send", + numberOfMessagesToSend, + _managedSourceQueue.getMessageCount().intValue()); + + List amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); + + // Copy first three messages to destination + long fromMessageId = amqMessagesIds.get(0); + long toMessageId = amqMessagesIds.get(2); + _managedSourceQueue.copyMessages(fromMessageId, toMessageId, _destinationQueueName); + + assertEquals("Unexpected queue depth on destination queue after first copy", + 3, + _managedDestinationQueue.getMessageCount().intValue()); + assertEquals("Unexpected queue depth on source queue after first copy", + numberOfMessagesToSend, + _managedSourceQueue.getMessageCount().intValue()); + + // Now copy a further two messages to destination + fromMessageId = amqMessagesIds.get(7); + toMessageId = amqMessagesIds.get(8); + _managedSourceQueue.copyMessages(fromMessageId, toMessageId, _destinationQueueName); + assertEquals("Unexpected queue depth on destination queue after second copy", + 5, + _managedDestinationQueue.getMessageCount().intValue()); + assertEquals("Unexpected queue depth on source queue after second copy", + numberOfMessagesToSend, + _managedSourceQueue.getMessageCount().intValue()); + + // Attempt to copy mixture of messages already on and some not already on the queue + + fromMessageId = amqMessagesIds.get(5); + toMessageId = amqMessagesIds.get(8); + _managedSourceQueue.copyMessages(fromMessageId, toMessageId, _destinationQueueName); + assertEquals("Unexpected queue depth on destination queue after second copy", + 7, + _managedDestinationQueue.getMessageCount().intValue()); + assertEquals("Unexpected queue depth on source queue after second copy", + numberOfMessagesToSend, + _managedSourceQueue.getMessageCount().intValue()); + + assertMessageIndicesOn(_destinationQueue, 0, 1, 2, 7, 8, 5, 6); + + + } + + public void testMoveMessagesBetweenQueuesWithActiveConsumerOnSourceQueue() throws Exception + { + setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, new Integer(1).toString()); + Connection asyncConnection = getConnection(); + asyncConnection.start(); + + final int numberOfMessagesToSend = 50; + sendMessage(_session, _sourceQueue, numberOfMessagesToSend); + syncSession(_session); + assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); + + List amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); + + long fromMessageId = amqMessagesIds.get(0); + long toMessageId = amqMessagesIds.get(numberOfMessagesToSend - 1); + + CountDownLatch consumerReadToHalfwayLatch = new CountDownLatch(numberOfMessagesToSend / 2); + AtomicInteger totalConsumed = new AtomicInteger(0); + startAsyncConsumerOn(_sourceQueue, asyncConnection, consumerReadToHalfwayLatch, totalConsumed); + + boolean halfwayPointReached = consumerReadToHalfwayLatch.await(5000, TimeUnit.MILLISECONDS); + assertTrue("Did not read half of messages within time allowed", halfwayPointReached); + + _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName); + + asyncConnection.stop(); + + // The exact number of messages moved will be non deterministic, as the number of messages processed + // by the consumer cannot be predicted. There is also the possibility that a message can remain + // on the source queue. This situation will arise if a message has been acquired by the consumer, but not + // yet delivered to the client application (i.e. MessageListener#onMessage()) when the Connection#stop() occurs. + // + // The number of messages moved + the number consumed + any messages remaining on source should + // *always* be equal to the number we originally sent. + + int numberOfMessagesReadByConsumer = totalConsumed.intValue(); + int numberOfMessagesOnDestinationQueue = _managedDestinationQueue.getMessageCount().intValue(); + int numberOfMessagesRemainingOnSourceQueue = _managedSourceQueue.getMessageCount().intValue(); + + LOGGER.debug("Async consumer read : " + numberOfMessagesReadByConsumer + + " Number of messages moved to destination : " + numberOfMessagesOnDestinationQueue + + " Number of messages remaining on source : " + numberOfMessagesRemainingOnSourceQueue); + assertEquals("Unexpected number of messages after move", numberOfMessagesToSend, numberOfMessagesReadByConsumer + numberOfMessagesOnDestinationQueue + numberOfMessagesRemainingOnSourceQueue); + } + + public void testMoveMessagesBetweenQueuesWithActiveConsumerOnDestinationQueue() throws Exception + { + setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, new Integer(1).toString()); + Connection asyncConnection = getConnection(); + asyncConnection.start(); + + final int numberOfMessagesToSend = 50; + sendMessage(_session, _sourceQueue, numberOfMessagesToSend); + syncSession(_session); + assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); + + List amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); + long fromMessageId = amqMessagesIds.get(0); + long toMessageId = amqMessagesIds.get(numberOfMessagesToSend - 1); + + AtomicInteger totalConsumed = new AtomicInteger(0); + CountDownLatch allMessagesConsumedLatch = new CountDownLatch(numberOfMessagesToSend); + startAsyncConsumerOn(_destinationQueue, asyncConnection, allMessagesConsumedLatch, totalConsumed); + + _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName); + + allMessagesConsumedLatch.await(5000, TimeUnit.MILLISECONDS); + assertEquals("Did not consume all messages from destination queue", numberOfMessagesToSend, totalConsumed.intValue()); + } + + /** + * Tests {@link ManagedQueue#moveMessages(long, long, String)} interface. + */ + public void testMoveMessageBetweenQueuesWithBrokerRestart() throws Exception + { + final int numberOfMessagesToSend = 1; + + sendMessage(_session, _sourceQueue, numberOfMessagesToSend); + syncSession(_session); + assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); + + restartBroker(); + + createManagementInterfacesForQueues(); + createConnectionAndSession(); + + List amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); + + // Move messages to destination + long messageId = amqMessagesIds.get(0); + _managedSourceQueue.moveMessages(messageId, messageId, _destinationQueueName); + + assertEquals("Unexpected queue depth on destination queue after move", 1, _managedDestinationQueue.getMessageCount().intValue()); + assertEquals("Unexpected queue depth on source queue after move", 0, _managedSourceQueue.getMessageCount().intValue()); + + assertMessageIndicesOn(_destinationQueue, 0); + } + + /** + * Tests {@link ManagedQueue#copyMessages(long, long, String)} interface. + */ + public void testCopyMessageBetweenQueuesWithBrokerRestart() throws Exception + { + final int numberOfMessagesToSend = 1; + + sendMessage(_session, _sourceQueue, numberOfMessagesToSend); + syncSession(_session); + assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); + + restartBroker(); + + createManagementInterfacesForQueues(); + createConnectionAndSession(); + + List amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); + + // Move messages to destination + long messageId = amqMessagesIds.get(0); + _managedSourceQueue.copyMessages(messageId, messageId, _destinationQueueName); + + assertEquals("Unexpected queue depth on destination queue after copy", 1, _managedDestinationQueue.getMessageCount().intValue()); + assertEquals("Unexpected queue depth on source queue after copy", 1, _managedSourceQueue.getMessageCount().intValue()); + + assertMessageIndicesOn(_destinationQueue, 0); + } + + /** + * Tests {@link ManagedQueue#deleteMessages(long, long)} interface. + */ + public void testDeleteMessages() throws Exception + { + final int numberOfMessagesToSend = 15; + + sendMessage(_session, _sourceQueue, numberOfMessagesToSend); + syncSession(_session); + assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); + List amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); + // Current expected queue state, in terms of message header indices: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14] + + // Delete the first message (Remember the amqMessagesIds list, and the message indices added as a property when sending, are both 0-based index) + long fromMessageId = amqMessagesIds.get(0); + long toMessageId = fromMessageId; + _managedSourceQueue.deleteMessages(fromMessageId, toMessageId); + assertEquals("Unexpected message count after first deletion", numberOfMessagesToSend - 1, _managedSourceQueue.getMessageCount().intValue()); + // Current expected queue state, in terms of message header indices: [X,1,2,3,4,5,6,7,8,9,10,11,12,13,14] + + // Delete the 9th-10th messages, in the middle of the queue + fromMessageId = amqMessagesIds.get(8); + toMessageId = amqMessagesIds.get(9); + _managedSourceQueue.deleteMessages(fromMessageId, toMessageId); + assertEquals("Unexpected message count after third deletion", numberOfMessagesToSend - 3, _managedSourceQueue.getMessageCount().intValue()); + // Current expected queue state, in terms of message header indices: [X,1,2,3,4,5,6,7,X,X,10,11,12,13,14] + + // Delete the 11th and 12th messages, but still include the IDs for the 9th and 10th messages in the + // range to ensure their IDs are 'skipped' until the matching messages are found + fromMessageId = amqMessagesIds.get(8); + toMessageId = amqMessagesIds.get(11); + _managedSourceQueue.deleteMessages(fromMessageId, toMessageId); + assertEquals("Unexpected message count after fourth deletion", numberOfMessagesToSend - 5, _managedSourceQueue.getMessageCount().intValue()); + // Current expected queue state, in terms of message header indices: [X,1,2,3,4,5,6,7,X,X,X,X,12,13,14] + + // Delete the 8th message and the 13th message, including the IDs for the 9th-12th messages in the + // range to ensure their IDs are 'skipped' and the other matching message is found + fromMessageId = amqMessagesIds.get(7); + toMessageId = amqMessagesIds.get(12); + _managedSourceQueue.deleteMessages(fromMessageId, toMessageId); + assertEquals("Unexpected message count after fourth deletion", numberOfMessagesToSend - 7, _managedSourceQueue.getMessageCount().intValue()); + // Current expected queue state, in terms of message header indices: [X,1,2,3,4,5,6,X,X,X,X,X,X,13,14] + + // Delete the last message message + fromMessageId = amqMessagesIds.get(numberOfMessagesToSend -1); + toMessageId = fromMessageId; + _managedSourceQueue.deleteMessages(fromMessageId, toMessageId); + assertEquals("Unexpected message count after second deletion", numberOfMessagesToSend - 8, _managedSourceQueue.getMessageCount().intValue()); + // Current expected queue state, in terms of message header indices: [X,1,2,3,4,5,6,X,X,X,X,X,X,13,X] + + // Verify the message indices with a consumer + assertMessageIndicesOn(_sourceQueue, 1,2,3,4,5,6,13); + } + + public void testGetMessageGroupKey() throws Exception + { + final String queueName = getName(); + final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST); + + final Object messageGroupKey = "test"; + final Map arguments = Collections.singletonMap(QueueArgumentsConverter.QPID_GROUP_HEADER_KEY, messageGroupKey); + managedBroker.createNewQueue(queueName, null, true, arguments); + + final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + + assertNotNull("Manager queue expected to be available", managedQueue); + assertEquals("Unexpected message group key", messageGroupKey, managedQueue.getMessageGroupKey()); + assertEquals("Unexpected message group sharing", false, managedQueue.isMessageGroupSharedGroups()); + } + + public void testIsMessageGroupSharedGroups() throws Exception + { + final String queueName = getName(); + final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST); + + final Object messageGroupKey = "test"; + final Map arguments = new HashMap(2); + arguments.put(QueueArgumentsConverter.QPID_GROUP_HEADER_KEY, messageGroupKey); + arguments.put(QueueArgumentsConverter.QPID_SHARED_MSG_GROUP, StandardQueueImpl.SHARED_MSG_GROUP_ARG_VALUE); + managedBroker.createNewQueue(queueName, null, true, arguments); + + final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + + assertNotNull("Manager queue expected to be available", managedQueue); + assertEquals("Unexpected message group key", messageGroupKey, managedQueue.getMessageGroupKey()); + assertEquals("Unexpected message group sharing", true, managedQueue.isMessageGroupSharedGroups()); + } + + @Override + public Message createNextMessage(Session session, int messageNumber) throws JMSException + { + Message message = session.createTextMessage(getContentForMessageNumber(messageNumber)); + message.setIntProperty(INDEX, messageNumber); + return message; + } + + private void startAsyncConsumerOn(Destination queue, Connection asyncConnection, + final CountDownLatch requiredNumberOfMessagesRead, final AtomicInteger totalConsumed) throws Exception + { + Session session = asyncConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(queue); + consumer.setMessageListener(new MessageListener() + { + + @Override + public void onMessage(Message arg0) + { + totalConsumed.incrementAndGet(); + requiredNumberOfMessagesRead.countDown(); + } + }); + } + + private void assertMessageIndicesOn(Destination queue, int... expectedIndices) throws Exception + { + MessageConsumer consumer = _session.createConsumer(queue); + + for (int i : expectedIndices) + { + TextMessage message = (TextMessage)consumer.receive(1000); + assertNotNull("Expected message with index " + i, message); + assertEquals("Expected message with index " + i, i, message.getIntProperty(INDEX)); + assertEquals("Expected message content", getContentForMessageNumber(i), message.getText()); + } + + assertNull("Unexpected message encountered", consumer.receive(1000)); + } + + private List getAMQMessageIdsOn(ManagedQueue managedQueue, long startIndex, long endIndex) throws Exception + { + final SortedSet messageIds = new TreeSet(); + + final TabularData tab = managedQueue.viewMessages(startIndex, endIndex); + final Iterator rowItr = (Iterator) tab.values().iterator(); + while(rowItr.hasNext()) + { + final CompositeData row = rowItr.next(); + long amqMessageId = (Long)row.get(ManagedQueue.MSG_AMQ_ID); + messageIds.add(amqMessageId); + } + + return new ArrayList(messageIds); + } + + /** + * + * Utility method to convert array of Strings in the form x = y into a + * map with key/value x => y. + * + */ + private Map headerArrayToMap(final String[] headerArray) + { + final Map headerMap = new HashMap(); + final List headerList = Arrays.asList(headerArray); + for (Iterator iterator = headerList.iterator(); iterator.hasNext();) + { + final String nameValuePair = iterator.next(); + final String[] nameValue = nameValuePair.split(" *= *", 2); + headerMap.put(nameValue[0], nameValue[1]); + } + return headerMap; + } + + private void createQueueOnBroker(Destination destination) throws JMSException + { + _session.createConsumer(destination).close(); // Create a consumer only to cause queue creation + } + + private void syncSession(Session session) throws Exception + { + ((AMQSession)session).sync(); + } + + private void createConnectionAndSession() throws JMSException, + NamingException + { + _connection = getConnection(); + _connection.start(); + _session = _connection.createSession(true, Session.SESSION_TRANSACTED); + } + + private void createManagementInterfacesForQueues() + { + _managedSourceQueue = _jmxUtils.getManagedQueue(_sourceQueueName); + _managedDestinationQueue = _jmxUtils.getManagedQueue(_destinationQueueName); + } + + private String getContentForMessageNumber(int msgCount) + { + return "Message count " + msgCount; + } + + private final class RecordingNotificationListener implements NotificationListener + { + private final CountDownLatch _notificationReceivedLatch; + private final AtomicInteger _numberOfNotifications; + private final AtomicReference _lastNotification; + + private RecordingNotificationListener(int expectedNumberOfNotifications) + { + _notificationReceivedLatch = new CountDownLatch(expectedNumberOfNotifications); + _numberOfNotifications = new AtomicInteger(0); + _lastNotification = new AtomicReference(); + } + + @Override + public void handleNotification(Notification notification, Object handback) + { + _lastNotification.set(notification); + _numberOfNotifications.incrementAndGet(); + _notificationReceivedLatch.countDown(); + } + + public int getNumberOfNotificationsReceived() + { + return _numberOfNotifications.get(); + } + + public Notification getLastNotification() + { + return _lastNotification.get(); + } + + public void awaitExpectedNotifications(long timeout, TimeUnit timeunit) throws InterruptedException + { + _notificationReceivedLatch.await(timeout, timeunit); + } + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java new file mode 100644 index 0000000000..4ea071f3ac --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java @@ -0,0 +1,211 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.systest.management.jmx; + +import java.util.List; + +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.management.common.mbeans.ManagedBroker; +import org.apache.qpid.management.common.mbeans.ManagedConnection; +import org.apache.qpid.management.common.mbeans.ServerInformation; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class StatisticsTest extends QpidBrokerTestCase +{ + private static final String TEST_VIRTUALHOST1 = "test1"; + private static final String TEST_VIRTUALHOST2 = "test2"; + + private static final String TEST_USER = "admin"; + private static final String TEST_PASSWORD = "admin"; + private static final int MESSAGE_COUNT_TEST = 5; + private static final int MESSAGE_COUNT_DEV = 9; + + private JMXTestUtils _jmxUtils; + private Connection _vhost1Connection, _vhost2Connection; + private Session _vhost1Session, _vhost2Session; + private Queue _vhost1Queue, _vhost2Queue; + protected String _brokerUrl; + + @Override + public void setUp() throws Exception + { + createTestVirtualHostNode(0, TEST_VIRTUALHOST1); + createTestVirtualHostNode(0, TEST_VIRTUALHOST2); + + getBrokerConfiguration().addJmxManagementConfiguration(); + + _jmxUtils = new JMXTestUtils(this, TEST_USER, TEST_PASSWORD); + + super.setUp(); + + _brokerUrl = getBroker().toString(); + _vhost1Connection = new AMQConnection(_brokerUrl, TEST_USER, TEST_PASSWORD, "clientid", TEST_VIRTUALHOST1); + _vhost2Connection = new AMQConnection(_brokerUrl, TEST_USER, TEST_PASSWORD, "clientid", TEST_VIRTUALHOST2); + _vhost1Connection.start(); + _vhost2Connection.start(); + + _vhost1Session = _vhost1Connection.createSession(true, Session.SESSION_TRANSACTED); + _vhost2Session = _vhost2Connection.createSession(true, Session.SESSION_TRANSACTED); + + _vhost1Queue = _vhost2Session.createQueue(getTestQueueName()); + _vhost2Queue = _vhost1Session.createQueue(getTestQueueName()); + + //Create queues by opening and closing consumers + final MessageConsumer vhost1Consumer = _vhost1Session.createConsumer(_vhost2Queue); + vhost1Consumer.close(); + final MessageConsumer vhost2Consumer = _vhost2Session.createConsumer(_vhost1Queue); + vhost2Consumer.close(); + + _jmxUtils.open(); + } + + @Override + public void tearDown() throws Exception + { + _jmxUtils.close(); + + super.tearDown(); + } + + public void testInitialStatisticValues() throws Exception + { + //Check initial values + checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, 0, 0, 0, 0); + checkVHostStatistics(TEST_VIRTUALHOST1, 0, 0, 0, 0); + checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0); + checkVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0); + checkBrokerStatistics(0, 0, 0, 0); + } + + public void testSendOnSingleVHost() throws Exception + { + sendMessagesAndSync(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST); + + //Check values + checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); + checkVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); + checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0); + checkVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0); + checkBrokerStatistics(MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); + } + + public void testSendOnTwoVHosts() throws Exception + { + sendMessagesAndSync(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST); + sendMessagesAndSync(_vhost2Session, _vhost1Queue, MESSAGE_COUNT_DEV); + + //Check values + checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); + checkVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); + checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, MESSAGE_COUNT_DEV, 0, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, 0); + checkVHostStatistics(TEST_VIRTUALHOST2, MESSAGE_COUNT_DEV, 0, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, 0); + checkBrokerStatistics(MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV, 0, (MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV) * DEFAULT_MESSAGE_SIZE, 0); + } + + public void testSendAndConsumeOnSingleVHost() throws Exception + { + sendMessagesAndSync(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST); + consumeMessages(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST); + + //Check values + checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); + checkVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); + checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0); + checkVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0); + checkBrokerStatistics(MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); + } + + public void testSendAndConsumeOnTwoVHosts() throws Exception + { + sendMessagesAndSync(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST); + sendMessagesAndSync(_vhost2Session, _vhost1Queue, MESSAGE_COUNT_DEV); + consumeMessages(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST); + consumeMessages(_vhost2Session, _vhost1Queue, MESSAGE_COUNT_DEV); + + //Check values + checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); + checkVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); + checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE); + checkVHostStatistics(TEST_VIRTUALHOST2, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE); + checkBrokerStatistics(MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV, MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV, (MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV) * DEFAULT_MESSAGE_SIZE, (MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV) * DEFAULT_MESSAGE_SIZE); + } + + private void sendMessagesAndSync(Session session, Queue queue, int numberOfMessages) throws Exception + { + //Send messages via connection on and sync + sendMessage(session, queue, numberOfMessages); + ((AMQSession)session).sync(); + } + + private void consumeMessages(Session session, Queue queue, int numberOfMessages) throws Exception + { + //consume the messages on the virtual host + final MessageConsumer consumer = session.createConsumer(queue); + for (int i = 0 ; i < numberOfMessages ; i++) + { + assertNotNull("an expected message was not received", consumer.receive(1500)); + } + session.commit(); + consumer.close(); + } + + private void checkSingleConnectionOnVHostStatistics(String vHostName, long messagesSent, long messagesReceived, long dataSent, long dataReceived) + { + List managedConnections = _jmxUtils.getManagedConnections(vHostName); + assertEquals(1, managedConnections.size()); + + ManagedConnection managedConnection = managedConnections.get(0); + + assertEquals(messagesSent, managedConnection.getTotalMessagesReceived()); + assertEquals(messagesReceived, managedConnection.getTotalMessagesDelivered()); + + assertEquals(dataSent, managedConnection.getTotalDataReceived()); + assertEquals(dataReceived, managedConnection.getTotalDataDelivered()); + } + + private void checkVHostStatistics(String vHostName, long messagesSent, long messagesReceived, long dataSent, long dataReceived) + { + ManagedBroker vhost = _jmxUtils.getManagedBroker(vHostName); + + assertEquals(messagesSent, vhost.getTotalMessagesReceived()); + assertEquals(messagesReceived, vhost.getTotalMessagesDelivered()); + + assertEquals(dataSent, vhost.getTotalDataReceived()); + assertEquals(dataReceived, vhost.getTotalDataDelivered()); + } + + private void checkBrokerStatistics(long messagesSent, long messagesReceived, long dataSent, long dataReceived) + { + ServerInformation broker = _jmxUtils.getServerInformation(); + + assertEquals(messagesSent, broker.getTotalMessagesReceived()); + assertEquals(messagesReceived, broker.getTotalMessagesDelivered()); + + assertEquals(dataSent, broker.getTotalDataReceived()); + assertEquals(dataReceived, broker.getTotalDataDelivered()); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java new file mode 100644 index 0000000000..25b09f04c3 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java @@ -0,0 +1,261 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.management.jmx; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.JMSException; + +import org.apache.qpid.management.common.mbeans.UserManagement; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.security.auth.manager.PlainPasswordDatabaseAuthenticationManager; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.tools.security.Passwd; + +/** + * System test for User Management. + * + */ +public class UserManagementTest extends QpidBrokerTestCase +{ + private static final String TEST_NEWPASSWORD = "newpassword"; + private static final String TEST_PASSWORD = "password"; + private JMXTestUtils _jmxUtils; + private String _testUserName; + private File _passwordFile; + private UserManagement _userManagement; + private Passwd _passwd; + + public void setUp() throws Exception + { + _passwd = createPasswordEncodingUtility(); + _passwordFile = createTemporaryPasswordFileWithJmxAdminUser(); + + Map newAttributes = new HashMap(); + newAttributes.put(AuthenticationProvider.TYPE, getAuthenticationManagerType()); + newAttributes.put("path", _passwordFile.getAbsolutePath()); + getBrokerConfiguration().setObjectAttributes(AuthenticationProvider.class,TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, newAttributes); + getBrokerConfiguration().addJmxManagementConfiguration(); + + _jmxUtils = new JMXTestUtils(this); + + super.setUp(); + _jmxUtils.open(); + + _testUserName = getTestName() + System.currentTimeMillis(); + + _userManagement = _jmxUtils.getUserManagement(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); + } + + + public void tearDown() throws Exception + { + try + { + if (_jmxUtils != null) + { + _jmxUtils.close(); + } + } + finally + { + super.tearDown(); + } + } + + public void testCreateUser() throws Exception + { + final int initialNumberOfUsers = _userManagement.viewUsers().size(); + assertFileDoesNotContainsPasswordForUser(_testUserName); + + boolean success = _userManagement.createUser(_testUserName, TEST_PASSWORD); + assertTrue("Should have been able to create new user " + _testUserName, success); + assertEquals("Unexpected number of users after add", initialNumberOfUsers + 1, _userManagement.viewUsers().size()); + + assertFileContainsPasswordForUser(_testUserName); + } + + public void testJmsLoginForNewUser() throws Exception + { + assertJmsConnectionFails(_testUserName, TEST_PASSWORD); + testCreateUser(); + + assertJmsConnectionSucceeds(_testUserName, TEST_PASSWORD); + } + + public void testDeleteUser() throws Exception + { + final int initialNumberOfUsers = _userManagement.viewUsers().size(); + + testCreateUser(); + + boolean success = _userManagement.deleteUser(_testUserName); + assertTrue("Should have been able to delete new user " + _testUserName, success); + assertEquals("Unexpected number of users after delete", initialNumberOfUsers, _userManagement.viewUsers().size()); + assertFileDoesNotContainsPasswordForUser(_testUserName); + } + + public void testJmsLoginNotPossibleForDeletedUser() throws Exception + { + testDeleteUser(); + + assertJmsConnectionFails(_testUserName, TEST_PASSWORD); + } + + public void testSetPassword() throws Exception + { + testCreateUser(); + + _userManagement.setPassword(_testUserName, TEST_NEWPASSWORD); + + assertFileContainsPasswordForUser(_testUserName); + } + + public void testJmsLoginForPasswordChangedUser() throws Exception + { + testSetPassword(); + + assertJmsConnectionSucceeds(_testUserName, TEST_NEWPASSWORD); + assertJmsConnectionFails(_testUserName, TEST_PASSWORD); + } + + public void testReload() throws Exception + { + writePasswordFile(_passwordFile, JMXTestUtils.DEFAULT_USERID, JMXTestUtils.DEFAULT_PASSWORD, _testUserName, TEST_PASSWORD); + + assertJmsConnectionFails(_testUserName, TEST_PASSWORD); + + _userManagement.reloadData(); + + assertJmsConnectionSucceeds(_testUserName, TEST_PASSWORD); + } + + public void testGetAuthenticationProviderType() throws Exception + { + String actualType = _userManagement.getAuthenticationProviderType(); + assertEquals("unexpected authentication provider type", getAuthenticationManagerType(), actualType); + } + + protected Passwd createPasswordEncodingUtility() + { + return new Passwd() + { + @Override + public String getOutput(String username, String password) + { + return username + ":" + password; + } + }; + } + + protected String getAuthenticationManagerType() + { + return PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE; + } + + private File createTemporaryPasswordFileWithJmxAdminUser() throws Exception + { + File passwordFile = File.createTempFile("passwd", "pwd"); + passwordFile.deleteOnExit(); + writePasswordFile(passwordFile, JMXTestUtils.DEFAULT_USERID, JMXTestUtils.DEFAULT_PASSWORD); + return passwordFile; + } + + private void writePasswordFile(File passwordFile, String... userNamePasswordPairs) throws Exception + { + FileWriter writer = null; + try + { + writer = new FileWriter(passwordFile); + for (int i = 0; i < userNamePasswordPairs.length; i=i+2) + { + String username = userNamePasswordPairs[i]; + String password = userNamePasswordPairs[i+1]; + writer.append(_passwd.getOutput(username, password) + "\n"); + } + } + finally + { + writer.close(); + } + } + + + private void assertFileContainsPasswordForUser(String username) throws IOException + { + assertTrue("Could not find password for user " + username + " within " + _passwordFile, passwordFileContainsUser(username)); + } + + private void assertFileDoesNotContainsPasswordForUser(String username) throws IOException + { + assertFalse("Could not find password for user " + username + " within " + _passwordFile, passwordFileContainsUser(username)); + } + + private boolean passwordFileContainsUser(String username) throws IOException + { + BufferedReader reader = null; + try + { + reader = new BufferedReader(new FileReader(_passwordFile)); + String line = reader.readLine(); + while(line != null) + { + if (line.startsWith(username)) + { + return true; + } + line = reader.readLine(); + } + + return false; + } + finally + { + reader.close(); + } + } + + private void assertJmsConnectionSucceeds(String username, String password) throws Exception + { + Connection connection = getConnection(username, password); + assertNotNull(connection); + } + + private void assertJmsConnectionFails(String username, String password) throws Exception + { + try + { + getConnection(username, password); + fail("Exception not thrown"); + } + catch (JMSException e) + { + // PASS + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java new file mode 100644 index 0000000000..ff441169b3 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.management.jmx; + +import org.apache.qpid.server.security.auth.manager.Base64MD5PasswordDatabaseAuthenticationManager; +import org.apache.qpid.tools.security.Passwd; + +public class UserManagementWithBase64MD5PasswordsTest extends UserManagementTest +{ + @Override + protected Passwd createPasswordEncodingUtility() + { + return new Passwd(); + } + + @Override + protected String getAuthenticationManagerType() + { + return Base64MD5PasswordDatabaseAuthenticationManager.PROVIDER_TYPE; + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AccessControlProviderRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AccessControlProviderRestTest.java new file mode 100644 index 0000000000..4140c9c12c --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AccessControlProviderRestTest.java @@ -0,0 +1,288 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.apache.qpid.server.BrokerOptions; +import org.apache.qpid.server.management.plugin.HttpManagement; +import org.apache.qpid.server.model.AccessControlProvider; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.security.access.FileAccessControlProviderConstants; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.test.utils.TestFileUtils; + +public class AccessControlProviderRestTest extends QpidRestTestCase +{ + private static final String ALLOWED_USER = "allowed"; + private static final String DENIED_USER = "denied"; + private static final String OTHER_USER = "other"; + + private String _aclFileContent1 = + "ACL ALLOW-LOG " + ALLOWED_USER + " ACCESS MANAGEMENT\n" + + "ACL ALLOW-LOG " + ALLOWED_USER + " CONFIGURE BROKER\n" + + "ACL DENY-LOG ALL ALL"; + + private String _aclFileContent2 = + "ACL ALLOW-LOG " + ALLOWED_USER + " ACCESS MANAGEMENT\n" + + "ACL ALLOW-LOG " + OTHER_USER + " ACCESS MANAGEMENT\n" + + "ACL ALLOW-LOG " + ALLOWED_USER + " CONFIGURE BROKER\n" + + "ACL DENY-LOG ALL ALL"; + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER, OTHER_USER); + + getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, + HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); + } + + public void testCreateAccessControlProvider() throws Exception + { + String accessControlProviderName = getTestName(); + + //verify that the access control provider doesn't exist, and + //in doing so implicitly verify that the 'denied' user can + //actually currently connect because no ACL is in effect yet + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + assertAccessControlProviderExistence(accessControlProviderName, false); + + //create the access control provider using the 'allowed' user + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + int responseCode = createAccessControlProvider(accessControlProviderName, _aclFileContent1); + assertEquals("Access control provider creation should be allowed", 201, responseCode); + + //verify it exists with the 'allowed' user + assertAccessControlProviderExistence(accessControlProviderName, true); + + //verify the 'denied' user can no longer access the management interface + //due to the just-created ACL file now preventing it + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + assertCanAccessManagementInterface(accessControlProviderName, false); + } + + public void testRemoveAccessControlProvider() throws Exception + { + String accessControlProviderName = getTestName(); + + //verify that the access control provider doesn't exist, and + //in doing so implicitly verify that the 'denied' user can + //actually currently connect because no ACL is in effect yet + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + assertAccessControlProviderExistence(accessControlProviderName, false); + + //create the access control provider using the 'allowed' user + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + int responseCode = createAccessControlProvider(accessControlProviderName, _aclFileContent1); + assertEquals("Access control provider creation should be allowed", 201, responseCode); + + //verify it exists with the 'allowed' user + assertAccessControlProviderExistence(accessControlProviderName, true); + + //verify the 'denied' user can no longer access the management interface + //due to the just-created ACL file now preventing it + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + assertCanAccessManagementInterface(accessControlProviderName, false); + + //remove the access control provider using the 'allowed' user + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "DELETE"); + assertEquals("Access control provider deletion should be allowed", 200, responseCode); + assertAccessControlProviderExistence(accessControlProviderName, false); + + //verify it is gone again, using the 'denied' user to implicitly confirm it is + //now able to connect to the management interface again because the ACL was removed. + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + assertAccessControlProviderExistence(accessControlProviderName, false); + } + + public void testReplaceAccessControlProvider() throws Exception + { + String accessControlProviderName1 = getTestName() + "1"; + + //verify that the access control provider doesn't exist, and + //in doing so implicitly verify that the 'denied' user can + //actually currently connect because no ACL is in effect yet + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + assertAccessControlProviderExistence(accessControlProviderName1, false); + + //create the access control provider using the 'allowed' user + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + int responseCode = createAccessControlProvider(accessControlProviderName1, _aclFileContent1); + assertEquals("Access control provider creation should be allowed", 201, responseCode); + + //verify it exists with the 'allowed' user + assertAccessControlProviderExistence(accessControlProviderName1, true); + + //verify the 'denied' and 'other' user can no longer access the management + //interface due to the just-created ACL file now preventing them + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + assertCanAccessManagementInterface(accessControlProviderName1, false); + getRestTestHelper().setUsernameAndPassword(OTHER_USER, OTHER_USER); + assertCanAccessManagementInterface(accessControlProviderName1, false); + + //create the replacement access control provider using the 'allowed' user. + String accessControlProviderName2 = getTestName() + "2"; + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + responseCode = createAccessControlProvider(accessControlProviderName2, _aclFileContent2); + assertEquals("Access control provider creation should be allowed", 201, responseCode); + + //Verify that it took effect immediately, replacing the first access control provider + + //verify the 'denied' user still can't access the management interface, but the 'other' user now CAN. + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + assertCanAccessManagementInterface(accessControlProviderName2, false); + getRestTestHelper().setUsernameAndPassword(OTHER_USER, OTHER_USER); + assertCanAccessManagementInterface(accessControlProviderName2, true); + + //remove the original access control provider using the 'allowed' user + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName1, "DELETE"); + assertEquals("Access control provider deletion should be allowed", 200, responseCode); + assertAccessControlProviderExistence(accessControlProviderName1, false); + + //verify the 'denied' user still can't access the management interface, the 'other' user still can, thus + //confirming that the second access control provider is still in effect + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + assertCanAccessManagementInterface(accessControlProviderName2, false); + getRestTestHelper().setUsernameAndPassword(OTHER_USER, OTHER_USER); + assertCanAccessManagementInterface(accessControlProviderName2, true); + } + + + public void testAddAndRemoveSecondAccessControlProviderReinstatesOriginal() throws Exception + { + String accessControlProviderName1 = getTestName() + "1"; + + //verify that the access control provider doesn't exist, and + //in doing so implicitly verify that the 'denied' user can + //actually currently connect because no ACL is in effect yet + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + assertAccessControlProviderExistence(accessControlProviderName1, false); + + //create the access control provider using the 'allowed' user + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + int responseCode = createAccessControlProvider(accessControlProviderName1, _aclFileContent1); + assertEquals("Access control provider creation should be allowed", 201, responseCode); + + //verify it exists with the 'allowed' user + assertAccessControlProviderExistence(accessControlProviderName1, true); + + //verify the 'denied' and 'other' user can no longer access the management + //interface due to the just-created ACL file now preventing them + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + assertCanAccessManagementInterface(accessControlProviderName1, false); + getRestTestHelper().setUsernameAndPassword(OTHER_USER, OTHER_USER); + assertCanAccessManagementInterface(accessControlProviderName1, false); + + //create the replacement access control provider using the 'allowed' user. + String accessControlProviderName2 = getTestName() + "2"; + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + responseCode = createAccessControlProvider(accessControlProviderName2, _aclFileContent2); + assertEquals("Access control provider creation should be allowed", 201, responseCode); + + //Verify that it took effect immediately, replacing the first access control provider + + //verify the 'denied' user still can't access the management interface, but the 'other' user now CAN. + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + assertCanAccessManagementInterface(accessControlProviderName2, false); + getRestTestHelper().setUsernameAndPassword(OTHER_USER, OTHER_USER); + assertCanAccessManagementInterface(accessControlProviderName2, true); + + //remove the second access control provider using the 'allowed' user + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName2, "DELETE"); + assertEquals("Access control provider deletion should be allowed", 200, responseCode); + assertAccessControlProviderExistence(accessControlProviderName2, false); + + //verify the 'denied' user still can't access the management interface, the + //'other' now CANT again, the 'allowed' still can, thus confirming that the + //first access control provider is now in effect once again + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + assertCanAccessManagementInterface(accessControlProviderName2, false); + getRestTestHelper().setUsernameAndPassword(OTHER_USER, OTHER_USER); + assertCanAccessManagementInterface(accessControlProviderName2, false); + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + assertCanAccessManagementInterface(accessControlProviderName2, true); + } + + public void testRemovalOfAccessControlProviderInErrorStateUsingManagementMode() throws Exception + { + stopBroker(); + + File file = new File(TMP_FOLDER, getTestName()); + if (file.exists()) + { + file.delete(); + } + assertFalse("ACL file should not exist", file.exists()); + UUID id = getBrokerConfiguration().addAclFileConfiguration(file.getAbsolutePath()); + getBrokerConfiguration().setSaved(false); + startBroker(0, true); + + getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD); + + Map acl = getRestTestHelper().getJsonAsSingletonList("accesscontrolprovider/" + TestBrokerConfiguration.ENTRY_NAME_ACL_FILE); + assertEquals("Unexpected id", id.toString(), acl.get(AccessControlProvider.ID)); + assertEquals("Unexpected path", file.getAbsolutePath() , acl.get(FileAccessControlProviderConstants.PATH)); + assertEquals("Unexpected state", State.ERRORED.name() , acl.get(AccessControlProvider.STATE)); + + int status = getRestTestHelper().submitRequest("accesscontrolprovider/" + TestBrokerConfiguration.ENTRY_NAME_ACL_FILE, "DELETE"); + assertEquals("ACL was not deleted", 200, status); + + List> acls = getRestTestHelper().getJsonAsList("accesscontrolprovider/" + TestBrokerConfiguration.ENTRY_NAME_ACL_FILE); + assertEquals("ACL exists", 0, acls.size()); + } + + private void assertCanAccessManagementInterface(String accessControlProviderName, boolean canAccess) throws Exception + { + int expected = canAccess ? 200 : 403; + int responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "GET"); + assertEquals("Unexpected response code", expected, responseCode); + } + + private void assertAccessControlProviderExistence(String accessControlProviderName, boolean exists) throws Exception + { + String path = "accesscontrolprovider/" + accessControlProviderName; + List> providers = getRestTestHelper().getJsonAsList(path); + assertEquals("Unexpected result", exists, !providers.isEmpty()); + } + + private int createAccessControlProvider(String accessControlProviderName, String content) throws Exception + { + File file = TestFileUtils.createTempFile(this, ".acl", content); + Map attributes = new HashMap(); + attributes.put(AccessControlProvider.NAME, accessControlProviderName); + attributes.put(AccessControlProvider.TYPE, FileAccessControlProviderConstants.ACL_FILE_PROVIDER_TYPE); + attributes.put(FileAccessControlProviderConstants.PATH, file.getAbsoluteFile()); + + return getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "PUT", attributes); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AnonymousAccessRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AnonymousAccessRestTest.java new file mode 100644 index 0000000000..3f944da8c7 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AnonymousAccessRestTest.java @@ -0,0 +1,115 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.qpid.server.management.plugin.HttpManagement; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class AnonymousAccessRestTest extends QpidRestTestCase +{ + @Override + public void startBroker() + { + // prevent broker from starting in setUp + } + + public void startBrokerNow() throws Exception + { + super.startBroker(); + } + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + TestBrokerConfiguration config = getBrokerConfiguration(); + + Map anonymousAuthProviderAttributes = new HashMap(); + anonymousAuthProviderAttributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); + anonymousAuthProviderAttributes.put(AuthenticationProvider.NAME, TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER); + config.addObjectConfiguration(AuthenticationProvider.class, anonymousAuthProviderAttributes); + + // set anonymous authentication provider on http port for the tests + config.setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER, + TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER); + config.setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, false); + + // reset credentials + getRestTestHelper().setUsernameAndPassword(null, null); + } + + public void testGetWithAnonymousProvider() throws Exception + { + startBrokerNow(); + + Map brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker"); + assertNotNull("Unexpected broker attributes", brokerDetails); + assertNotNull("Unexpected value of attribute " + Broker.ID, brokerDetails.get(Broker.ID)); + } + + public void testPutAnonymousProvider() throws Exception + { + startBrokerNow(); + + Map brokerAttributes = new HashMap(); + brokerAttributes.put(Broker.DEFAULT_VIRTUAL_HOST, TEST3_VIRTUALHOST); + + int response = getRestTestHelper().submitRequest("broker", "PUT", brokerAttributes); + assertEquals("Unexpected update response", 200, response); + + Map brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker"); + assertNotNull("Unexpected broker attributes", brokerDetails); + assertNotNull("Unexpected value of attribute " + Broker.ID, brokerDetails.get(Broker.ID)); + assertEquals("Unexpected default virtual host", TEST3_VIRTUALHOST, brokerDetails.get(Broker.DEFAULT_VIRTUAL_HOST)); + } + + public void testGetWithPasswordAuthProvider() throws Exception + { + getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER, + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); + startBrokerNow(); + + int response = getRestTestHelper().submitRequest("broker", "GET"); + assertEquals("Anonymous access should be denied", 401, response); + } + + public void testPutWithPasswordAuthProvider() throws Exception + { + getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER, + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); + startBrokerNow(); + + Map brokerAttributes = new HashMap(); + brokerAttributes.put(Broker.DEFAULT_VIRTUAL_HOST, TEST3_VIRTUALHOST); + + int response = getRestTestHelper().submitRequest("broker", "PUT", brokerAttributes); + assertEquals("Anonymous access should be denied", 401, response); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java new file mode 100644 index 0000000000..2467705903 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java @@ -0,0 +1,337 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest; + +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.apache.qpid.server.BrokerOptions; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.BrokerModel; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.ExternalFileBasedAuthenticationManager; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.User; +import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager; +import org.apache.qpid.server.security.auth.manager.PlainPasswordDatabaseAuthenticationManager; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class AuthenticationProviderRestTest extends QpidRestTestCase +{ + + public void testGet() throws Exception + { + List> providerDetails = getRestTestHelper().getJsonAsList("authenticationprovider"); + assertNotNull("Providers details cannot be null", providerDetails); + assertEquals("Unexpected number of providers", 2, providerDetails.size()); + for (Map provider : providerDetails) + { + boolean managesPrincipals = true; + String type = PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE; + if (ANONYMOUS_AUTHENTICATION_PROVIDER.equals(provider.get(AuthenticationProvider.NAME))) + { + type = AnonymousAuthenticationManager.PROVIDER_TYPE; + managesPrincipals = false; + } + assertProvider(managesPrincipals, type , provider); + Map data = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + + provider.get(AuthenticationProvider.NAME)); + assertNotNull("Cannot load data for " + provider.get(AuthenticationProvider.NAME), data); + assertProvider(managesPrincipals, type, data); + } + } + + public void testPutCreateSecondPlainPrincipalDatabaseProviderSucceeds() throws Exception + { + File principalDatabase = getRestTestHelper().createTemporaryPasswdFile(new String[]{"admin2", "guest2", "test2"}); + + String providerName = "test-provider"; + Map attributes = new HashMap(); + attributes.put(AuthenticationProvider.NAME, providerName); + attributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE); + attributes.put(ExternalFileBasedAuthenticationManager.PATH, principalDatabase.getAbsolutePath()); + + int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); + assertEquals("failed to create authentication provider", 201, responseCode); + } + + public void testPutCreateNewAnonymousProvider() throws Exception + { + String providerName = "test-provider"; + Map attributes = new HashMap(); + attributes.put(AuthenticationProvider.NAME, providerName); + attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); + + int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); + assertEquals("Unexpected response code", 201, responseCode); + + List> providerDetails = getRestTestHelper().getJsonAsList("authenticationprovider/" + providerName); + assertNotNull("Providers details cannot be null", providerDetails); + assertEquals("Unexpected number of providers", 1, providerDetails.size()); + Map provider = providerDetails.get(0); + assertProvider(false, AnonymousAuthenticationManager.PROVIDER_TYPE, provider); + } + + public void testUpdateAuthenticationProviderIdFails() throws Exception + { + String providerName = "test-provider"; + Map attributes = new HashMap(); + attributes.put(AuthenticationProvider.NAME, providerName); + attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); + + int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); + assertEquals("Unexpected response code", 201, responseCode); + + attributes.put(AuthenticationProvider.ID, UUID.randomUUID()); + + responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); + assertEquals("Update with new ID should fail", 409, responseCode); + } + + public void testDeleteOfUsedAuthenticationProviderFails() throws Exception + { + // create provider + String providerName = "test-provider"; + Map attributes = new HashMap(); + attributes.put(AuthenticationProvider.NAME, providerName); + attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); + + int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); + assertEquals("Unexpected response code for provider creation", 201, responseCode); + + // create port + String portName = "test-port"; + Map portAttributes = new HashMap(); + portAttributes.put(Port.NAME, portName); + portAttributes.put(Port.AUTHENTICATION_PROVIDER, providerName); + portAttributes.put(Port.PORT, findFreePort()); + + responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", portAttributes); + assertEquals("Unexpected response code for port creation", 201, responseCode); + + responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName , "DELETE"); + assertEquals("Unexpected response code for provider deletion", 409, responseCode); + + List> providerDetails = getRestTestHelper().getJsonAsList("authenticationprovider/" + providerName); + assertNotNull("Providers details cannot be null", providerDetails); + assertEquals("Unexpected number of providers", 1, providerDetails.size()); + assertProvider(false, AnonymousAuthenticationManager.PROVIDER_TYPE, providerDetails.get(0)); + } + + public void testDeleteOfUnusedAuthenticationProvider() throws Exception + { + // create provider + String providerName = "test-provider"; + Map attributes = new HashMap(); + attributes.put(AuthenticationProvider.NAME, providerName); + attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); + + int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); + assertEquals("Unexpected response code for provider creation", 201, responseCode); + + responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName , "DELETE"); + assertEquals("Unexpected response code for provider deletion", 200, responseCode); + + List> providerDetails = getRestTestHelper().getJsonAsList("authenticationprovider/" + providerName); + assertNotNull("Providers details cannot be null", providerDetails); + assertEquals("Unexpected number of providers", 0, providerDetails.size()); + } + + public void testRemovalOfAuthenticationProviderInErrorStateUsingManagementMode() throws Exception + { + stopBroker(); + + File file = new File(TMP_FOLDER, getTestName()); + if (file.exists()) + { + file.delete(); + } + assertFalse("Group file should not exist", file.exists()); + + TestBrokerConfiguration config = getBrokerConfiguration(); + + String providerName = getTestName(); + Map attributes = new HashMap(); + attributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE); + attributes.put(AuthenticationProvider.NAME, providerName); + attributes.put(ExternalFileBasedAuthenticationManager.PATH, file.getAbsoluteFile()); + + UUID id = config.addObjectConfiguration(AuthenticationProvider.class, attributes); + config.setSaved(false); + startBroker(0, true); + + getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD); + + Map provider = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + providerName); + assertEquals("Unexpected id", id.toString(), provider.get(AuthenticationProvider.ID)); + assertEquals("Unexpected name", providerName, provider.get(AuthenticationProvider.NAME)); + assertEquals("Unexpected path", file.getAbsolutePath() , provider.get(ExternalFileBasedAuthenticationManager.PATH)); + assertEquals("Unexpected state", State.ERRORED.name() , provider.get(AuthenticationProvider.STATE)); + + int status = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "DELETE"); + assertEquals("ACL was not deleted", 200, status); + + List> providers = getRestTestHelper().getJsonAsList("authenticationprovider/" + providerName); + assertEquals("Provider exists", 0, providers.size()); + } + + public void testUpdateOfAuthenticationProviderInErrorStateUsingManagementMode() throws Exception + { + stopBroker(); + + File file = new File(TMP_FOLDER, getTestName()); + if (file.exists()) + { + file.delete(); + } + assertFalse("Group file should not exist", file.exists()); + + TestBrokerConfiguration config = getBrokerConfiguration(); + + String providerName = getTestName(); + Map attributes = new HashMap(); + attributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE); + attributes.put(AuthenticationProvider.NAME, providerName); + attributes.put(ExternalFileBasedAuthenticationManager.PATH, file.getAbsoluteFile()); + + UUID id = config.addObjectConfiguration(AuthenticationProvider.class, attributes); + config.setSaved(false); + startBroker(0, true); + + getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD); + + Map provider = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + providerName); + assertEquals("Unexpected id", id.toString(), provider.get(AuthenticationProvider.ID)); + assertEquals("Unexpected name", providerName, provider.get(AuthenticationProvider.NAME)); + assertEquals("Unexpected path", file.getAbsolutePath() , provider.get(ExternalFileBasedAuthenticationManager.PATH)); + assertEquals("Unexpected state", State.ERRORED.name() , provider.get(AuthenticationProvider.STATE)); + + File principalDatabase = null; + try + { + principalDatabase = getRestTestHelper().createTemporaryPasswdFile(new String[]{"admin2", "guest2", "test2"}); + attributes = new HashMap(); + attributes.put(AuthenticationProvider.NAME, providerName); + attributes.put(AuthenticationProvider.ID, id); + attributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE); + attributes.put(ExternalFileBasedAuthenticationManager.PATH, principalDatabase.getAbsolutePath()); + + int status = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); + assertEquals("ACL was not deleted", 200, status); + + provider = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + providerName); + assertEquals("Unexpected id", id.toString(), provider.get(AuthenticationProvider.ID)); + assertEquals("Unexpected name", providerName, provider.get(AuthenticationProvider.NAME)); + assertEquals("Unexpected path", principalDatabase.getAbsolutePath() , provider.get( + ExternalFileBasedAuthenticationManager.PATH)); + assertEquals("Unexpected state", State.ACTIVE.name() , provider.get(AuthenticationProvider.STATE)); + } + finally + { + if (principalDatabase != null) + { + principalDatabase.delete(); + } + } + } + + public void testCreateAndDeletePasswordAuthenticationProviderWithNonExistingFile() throws Exception + { + stopBroker(); + getBrokerConfiguration().setSaved(false); + getBrokerConfiguration().removeObjectConfiguration(AuthenticationProvider.class, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); + getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT, Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER); + getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER); + + startBroker(); + + File file = new File(TMP_FOLDER + File.separator + getTestName()); + if (file.exists()) + { + file.delete(); + } + assertFalse("File " + file.getAbsolutePath() + " should not exist", file.exists()); + + // create provider + String providerName = "test-provider"; + Map attributes = new HashMap(); + attributes.put(AuthenticationProvider.NAME, providerName); + attributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE); + attributes.put(ExternalFileBasedAuthenticationManager.PATH, file.getAbsolutePath()); + + int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); + assertEquals("Password provider was not created", 201, responseCode); + + + Map providerDetails = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + providerName); + assertNotNull("Providers details cannot be null", providerDetails); + assertEquals("Unexpected name", providerName, providerDetails.get(AuthenticationProvider.NAME)); + assertEquals("Unexpected type", PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE, providerDetails.get(AuthenticationProvider.TYPE)); + assertEquals("Unexpected path", file.getAbsolutePath(), providerDetails.get( + ExternalFileBasedAuthenticationManager.PATH)); + + assertTrue("User file should be created", file.exists()); + + responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName , "DELETE"); + assertEquals("Unexpected response code for provider deletion", 200, responseCode); + + List> providers = getRestTestHelper().getJsonAsList("authenticationprovider/" + providerName); + assertNotNull("Providers details cannot be null", providers); + assertEquals("Unexpected number of providers", 0, providers.size()); + + assertFalse("File " + file.getAbsolutePath() + " should be deleted", file.exists()); + } + + private void assertProvider(boolean managesPrincipals, String type, Map provider) + { + Asserts.assertAttributesPresent(provider, BrokerModel.getInstance().getTypeRegistry().getAttributeNames( + AuthenticationProvider.class), + AuthenticationProvider.DESCRIPTION, ConfiguredObject.CONTEXT, + ConfiguredObject.DESIRED_STATE, ConfiguredObject.CREATED_BY, + ConfiguredObject.CREATED_TIME, ConfiguredObject.LAST_UPDATED_BY, ConfiguredObject.LAST_UPDATED_TIME); + assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.STATE, State.ACTIVE.name(), + provider.get(AuthenticationProvider.STATE)); + assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.LIFETIME_POLICY, + LifetimePolicy.PERMANENT.name(), provider.get(AuthenticationProvider.LIFETIME_POLICY)); + assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.DURABLE, Boolean.TRUE, + provider.get(AuthenticationProvider.DURABLE)); + assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.TYPE, type, + provider.get(AuthenticationProvider.TYPE)); + + if (managesPrincipals) + { + @SuppressWarnings("unchecked") + List> users = (List>) provider.get("users"); + assertNotNull("Users are not found", users); + assertTrue("Unexpected number of users", users.size() > 1); + for (Map user : users) + { + assertNotNull("Attribute " + User.ID, user.get(User.ID)); + assertNotNull("Attribute " + User.NAME, user.get(User.NAME)); + } + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java new file mode 100644 index 0000000000..c51457cdab --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BasicAuthRestTest.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.systest.rest; + +import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE; +import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD; + +import java.io.IOException; +import java.util.Collections; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.qpid.server.management.plugin.HttpManagement; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Transport; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class BasicAuthRestTest extends QpidRestTestCase +{ + private static final String USERNAME = "admin"; + + @Override + public void setUp() throws Exception + { + setSystemProperty("javax.net.debug", "ssl"); + + //don't call super method, we will configure the broker in the test before doing so + } + + @Override + protected void customizeConfiguration() throws IOException + { + //do nothing, we will configure this locally + } + + private void configure(boolean useSsl) throws IOException + { + getRestTestHelper().setUseSsl(useSsl); + if (useSsl) + { + getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.TRANSPORTS, Collections.singleton(Transport.SSL)); + getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); + } + super.customizeConfiguration(); + } + + private void verifyGetBrokerAttempt(int responseCode) throws IOException + { + assertEquals(responseCode, getRestTestHelper().submitRequest("broker", "GET")); + } + + public void testBasicAuthWhenEnabledWithHttps() throws Exception + { + configure(true); + super.setUp(); + setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); + setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); + + // Try the attempt with authentication, it should succeed because + // BASIC auth is enabled by default on secure connections. + getRestTestHelper().setUsernameAndPassword(USERNAME, USERNAME); + verifyGetBrokerAttempt(HttpServletResponse.SC_OK); + } + + public void testBasicAuthWhenDisabledWithHttp() throws Exception + { + configure(false); + getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, false); + super.setUp(); + + // Try the attempt with authentication, it should fail because + // BASIC auth is disabled by default on non-secure connections. + getRestTestHelper().setUsernameAndPassword(USERNAME, USERNAME); + verifyGetBrokerAttempt(HttpServletResponse.SC_UNAUTHORIZED); + } + + public void testEnablingForHttp() throws Exception + { + configure(false); + + getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); + super.setUp(); + + // Try the attempt with authentication, it should succeed because + // BASIC auth is now enabled on non-secure connections. + getRestTestHelper().setUsernameAndPassword(USERNAME, USERNAME); + verifyGetBrokerAttempt(HttpServletResponse.SC_OK); + } + + public void testDisablingForHttps() throws Exception + { + configure(true); + getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, "httpsBasicAuthenticationEnabled", false); + super.setUp(); + setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); + setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); + + // Try the attempt with authentication, it should fail because + // BASIC auth is now disabled on secure connections. + getRestTestHelper().setUsernameAndPassword(USERNAME, USERNAME); + verifyGetBrokerAttempt(HttpServletResponse.SC_UNAUTHORIZED); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BindingRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BindingRestTest.java new file mode 100644 index 0000000000..368bc90d3d --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BindingRestTest.java @@ -0,0 +1,131 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.qpid.server.model.Binding; + +public class BindingRestTest extends QpidRestTestCase +{ + + @Override + public void setUp() throws Exception + { + super.setUp(); + getRestTestHelper().createTestQueues(); + } + + public void testGetAllBindings() throws Exception + { + List> bindings = getRestTestHelper().getJsonAsList("binding/test"); + assertNotNull("Bindings cannot be null", bindings); + assertEquals("Unexpected number of bindings", RestTestHelper.EXPECTED_QUEUES.length, bindings.size()); + for (Map binding : bindings) + { + Asserts.assertBinding((String) binding.get(Binding.NAME), (String) binding.get(Binding.EXCHANGE), binding); + } + } + + public void testGetVirtualHostExchangeBindings() throws Exception + { + List> bindings = getRestTestHelper().getJsonAsList("binding/test/test/amq.direct"); + assertNotNull("Bindings cannot be null", bindings); + assertEquals("Unexpected number of bindings", RestTestHelper.EXPECTED_QUEUES.length, bindings.size()); + for (String queueName : RestTestHelper.EXPECTED_QUEUES) + { + Map binding = getRestTestHelper().find(Binding.NAME, queueName, bindings); + Asserts.assertBinding(queueName, "amq.direct", binding); + } + } + + public void testGetVirtualHostExchangeQueueBindings() throws Exception + { + List> bindings = getRestTestHelper().getJsonAsList("binding/test/test/amq.direct/queue"); + assertNotNull("Bindings cannot be null", bindings); + assertEquals("Unexpected number of bindings", 1, bindings.size()); + Asserts.assertBinding("queue", "amq.direct", bindings.get(0)); + } + + + public void testDeleteBinding() throws Exception + { + String bindingUrl = "binding/test/test/amq.direct/queue/queue"; + List> bindings = getRestTestHelper().getJsonAsList(bindingUrl); + assertEquals("Unexpected number of bindings", 1, bindings.size()); + Asserts.assertBinding("queue", "amq.direct", bindings.get(0)); + + int responseCode = getRestTestHelper().submitRequest(bindingUrl, "DELETE"); + assertEquals("Unexpected response code", 200, responseCode); + + bindings = getRestTestHelper().getJsonAsList(bindingUrl); + assertEquals("Binding should be deleted", 0, bindings.size()); + } + + public void testDeleteBindingById() throws Exception + { + Map binding = getRestTestHelper().getJsonAsSingletonList("binding/test/test/amq.direct/queue"); + int responseCode = getRestTestHelper().submitRequest("binding/test/test/amq.direct?id=" + binding.get(Binding.ID), "DELETE"); + assertEquals("Unexpected response code", 200, responseCode); + List> bindings = getRestTestHelper().getJsonAsList("binding/test/test/amq.direct/queue"); + assertEquals("Binding should be deleted", 0, bindings.size()); + } + + public void testCreateBinding() throws Exception + { + String bindingName = getTestName(); + Map bindingData = new HashMap(); + bindingData.put(Binding.NAME, bindingName); + bindingData.put(Binding.QUEUE, "queue"); + bindingData.put(Binding.EXCHANGE, "amq.direct"); + + String bindingUrl = "binding/test/test/amq.direct/queue/" + bindingName; + + int responseCode = getRestTestHelper().submitRequest(bindingUrl, "PUT", bindingData); + assertEquals("Unexpected response code", 201, responseCode); + + Map binding = getRestTestHelper().getJsonAsSingletonList(bindingUrl); + Asserts.assertBinding(bindingName, "queue", "amq.direct", binding); + } + + public void testSetBindingAttributesUnsupported() throws Exception + { + String bindingName = getTestName(); + Map attributes = new HashMap(); + attributes.put(Binding.NAME, bindingName); + attributes.put(Binding.QUEUE, "queue"); + attributes.put(Binding.EXCHANGE, "amq.direct"); + + String bindingUrl = "binding/test/test/amq.direct/queue/" + bindingName; + int responseCode = getRestTestHelper().submitRequest(bindingUrl, "PUT", attributes); + assertEquals("Unexpected response code", 201, responseCode); + + Map binding = getRestTestHelper().getJsonAsSingletonList(bindingUrl); + Asserts.assertBinding(bindingName, "queue", "amq.direct", binding); + + attributes.put(Binding.ARGUMENTS, "blah"); + + responseCode = getRestTestHelper().submitRequest(bindingUrl, "PUT", attributes); + assertEquals("Update should be unsupported", 409, responseCode); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpAndHttpsTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpAndHttpsTest.java new file mode 100644 index 0000000000..74db3e7040 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpAndHttpsTest.java @@ -0,0 +1,85 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest; + +import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE; +import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.model.Transport; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class BrokerRestHttpAndHttpsTest extends QpidRestTestCase +{ + @Override + public void setUp() throws Exception + { + setSystemProperty("javax.net.debug", "ssl"); + super.setUp(); + setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); + setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); + } + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + Map newAttributes = new HashMap(); + newAttributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.HTTP)); + newAttributes.put(Port.TRANSPORTS, Arrays.asList(Transport.SSL, Transport.TCP)); + newAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); + getBrokerConfiguration().setObjectAttributes(Port.class,TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT,newAttributes); + getBrokerConfiguration().setObjectAttribute(AuthenticationProvider.class, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, + "secureOnlyMechanisms", + "[\"PLAIN\"]"); + + } + + public void testGetWithHttps() throws Exception + { + Collection results = getMechanisms(true); + assertTrue("mechanisms did not contain PLAIN: " + results, results.contains("PLAIN")); + } + + + public void testGetWithHttp() throws Exception + { + Collection results = getMechanisms(false); + assertFalse("mechanisms incorrectly contain PLAIN: " + results, results.contains("PLAIN")); + } + + + private Collection getMechanisms(final boolean useSsl) throws IOException + { + getRestTestHelper().setUseSsl(useSsl); + Map mechanisms = getRestTestHelper().getJsonAsMap("/service/sasl"); + return (Collection) mechanisms.get("mechanisms"); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsClientCertAuthTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsClientCertAuthTest.java new file mode 100644 index 0000000000..5b8d919d3e --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsClientCertAuthTest.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.systest.rest; + +import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE; +import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE_PASSWORD; +import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE; +import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.model.Transport; +import org.apache.qpid.server.security.auth.manager.ExternalAuthenticationManager; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class BrokerRestHttpsClientCertAuthTest extends QpidRestTestCase +{ + + @Override + public void setUp() throws Exception + { + setSystemProperty("javax.net.debug", "ssl"); + super.setUp(); + setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); + setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); + setSystemProperty("javax.net.ssl.keystore", KEYSTORE); + setSystemProperty("javax.net.ssl.keyStorePassword", KEYSTORE_PASSWORD); + + } + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + getRestTestHelper().setUseSslAuth(true); + Map newAttributes = new HashMap(); + newAttributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.HTTP)); + newAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); + newAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); + newAttributes.put(Port.TRUST_STORES, Collections.singleton(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE)); + newAttributes.put(Port.NEED_CLIENT_AUTH,"true"); + + + Map externalProviderAttributes = new HashMap(); + externalProviderAttributes.put(AuthenticationProvider.TYPE, ExternalAuthenticationManager.PROVIDER_TYPE); + externalProviderAttributes.put(AuthenticationProvider.NAME, EXTERNAL_AUTHENTICATION_PROVIDER); + getBrokerConfiguration().addObjectConfiguration(AuthenticationProvider.class, externalProviderAttributes); + + // set password authentication provider on http port for the tests + getBrokerConfiguration().setObjectAttribute(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.AUTHENTICATION_PROVIDER, + EXTERNAL_AUTHENTICATION_PROVIDER); + + getBrokerConfiguration().setObjectAttributes(Port.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, newAttributes); + } + + public void testGetWithHttps() throws Exception + { + Map saslData = getRestTestHelper().getJsonAsMap("/service/sasl"); + + Asserts.assertAttributesPresent(saslData, "user"); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java new file mode 100644 index 0000000000..319cc1c9da --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java @@ -0,0 +1,77 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.systest.rest; + +import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE; +import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.BrokerModel; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.model.Transport; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class BrokerRestHttpsTest extends QpidRestTestCase +{ + @Override + public void setUp() throws Exception + { + setSystemProperty("javax.net.debug", "ssl"); + super.setUp(); + setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); + setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); + } + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + getRestTestHelper().setUseSsl(true); + Map newAttributes = new HashMap(); + newAttributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.HTTP)); + newAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); + newAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); + getBrokerConfiguration().setObjectAttributes(Port.class,TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT,newAttributes); + } + + public void testGetWithHttps() throws Exception + { + Map brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker"); + + Asserts.assertAttributesPresent(brokerDetails, BrokerModel.getInstance().getTypeRegistry().getAttributeNames(Broker.class), + Broker.PROCESS_PID, + ConfiguredObject.TYPE, + ConfiguredObject.CREATED_BY, + ConfiguredObject.CREATED_TIME, + ConfiguredObject.LAST_UPDATED_BY, + ConfiguredObject.LAST_UPDATED_TIME, + ConfiguredObject.DESCRIPTION, + ConfiguredObject.CONTEXT, + ConfiguredObject.DESIRED_STATE); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestTest.java new file mode 100644 index 0000000000..bae27b802c --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/BrokerRestTest.java @@ -0,0 +1,242 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import org.apache.qpid.common.QpidProperties; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.BrokerModel; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.VirtualHostNode; +import org.apache.qpid.test.client.UnroutableMessageTestExceptionListener; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.util.SystemUtils; + +public class BrokerRestTest extends QpidRestTestCase +{ + private static final String BROKER_AUTHENTICATIONPROVIDERS_ATTRIBUTE = "authenticationproviders"; + private static final String BROKER_PORTS_ATTRIBUTE = "ports"; + private static final String BROKER_VIRTUALHOST_NODES_ATTRIBUTE = "virtualhostnodes"; + private static final String BROKER_STATISTICS_ATTRIBUTE = "statistics"; + + public void testGet() throws Exception + { + Map brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker"); + + assertBrokerAttributes(brokerDetails); + + @SuppressWarnings("unchecked") + Map statistics = (Map) brokerDetails.get(BROKER_STATISTICS_ATTRIBUTE); + Asserts.assertAttributesPresent(statistics, new String[]{ "bytesIn", "messagesOut", "bytesOut", "messagesIn" }); + + @SuppressWarnings("unchecked") + List> nodes = (List>) brokerDetails.get(BROKER_VIRTUALHOST_NODES_ATTRIBUTE); + assertEquals("Unexpected number of virtual hosts", 3, nodes.size()); + + for (String nodeName: EXPECTED_VIRTUALHOSTS) + { + Map nodeAttributes = getRestTestHelper().find(VirtualHostNode.NAME, nodeName, nodes); + assertNotNull("Node attributes are not found for node with name " + nodeName, nodeAttributes); + } + + @SuppressWarnings("unchecked") + List> ports = (List>) brokerDetails.get(BROKER_PORTS_ATTRIBUTE); + assertEquals("Unexpected number of ports", 2, ports.size()); + + for (Map port : ports) + { + Asserts.assertPortAttributes(port); + } + + Map amqpPort = getRestTestHelper().find(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT, ports); + Map httpPort = getRestTestHelper().find(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, ports); + + assertEquals("Unexpected binding address", "*", amqpPort.get(Port.BINDING_ADDRESS)); + assertNotNull("Cannot find AMQP port", amqpPort); + assertNotNull("Cannot find HTTP port", httpPort); + + @SuppressWarnings("unchecked") + Collection port1Protocols = (Collection) amqpPort.get(Port.PROTOCOLS); + assertFalse("AMQP protocol list cannot contain HTTP", port1Protocols != null && port1Protocols.contains("HTTP")); + + @SuppressWarnings("unchecked") + Collection port2Protocols = (Collection) httpPort.get(Port.PROTOCOLS); + assertEquals("Unexpected value of attribute " + Port.PROTOCOLS, new HashSet(Arrays.asList("HTTP")), + new HashSet(port2Protocols)); + } + + public void testPutToUpdateWithValidAttributeValues() throws Exception + { + Map brokerAttributes = getValidBrokerAttributes(); + + int response = getRestTestHelper().submitRequest("broker", "PUT", brokerAttributes); + assertEquals("Unexpected update response", 200, response); + + restartBroker(); + Map brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker"); + assertBrokerAttributes(brokerAttributes, brokerDetails); + } + + public void testPutUpdateWhereNumericAttributesAreSetAsStringValues() throws Exception + { + Map validAttributes = getValidBrokerAttributes(); + Map attributes = new HashMap(); + + for (Map.Entry entry : validAttributes.entrySet()) + { + Object value = entry.getValue(); + if (value instanceof Number) + { + value = String.valueOf(value); + } + attributes.put(entry.getKey(), value); + } + + int response = getRestTestHelper().submitRequest("broker", "PUT", attributes); + assertEquals("Unexpected update response", 200, response); + + Map brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker"); + assertBrokerAttributes(validAttributes, brokerDetails); + } + + public void testPutToUpdateWithInvalidAttributeValues() throws Exception + { + Map invalidAttributes = new HashMap(); + invalidAttributes.put(Broker.DEFAULT_VIRTUAL_HOST, "non-existing-host"); + invalidAttributes.put(Broker.CONNECTION_SESSION_COUNT_LIMIT, -10); + invalidAttributes.put(Broker.CONNECTION_HEART_BEAT_DELAY, -11000); + invalidAttributes.put(Broker.STATISTICS_REPORTING_PERIOD, -12000); + + for (Map.Entry entry : invalidAttributes.entrySet()) + { + Map brokerAttributes = getValidBrokerAttributes(); + brokerAttributes.put(entry.getKey(), entry.getValue()); + int response = getRestTestHelper().submitRequest("broker", "PUT", brokerAttributes); + assertEquals("Unexpected update response for invalid attribute " + entry.getKey() + "=" + entry.getValue(), 409, response); + } + + } + + public void testSetCloseOnNoRoute() throws Exception + { + Map brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker"); + assertTrue("closeOnNoRoute should be true", (Boolean)brokerDetails.get(Broker.CONNECTION_CLOSE_WHEN_NO_ROUTE)); + + Map brokerAttributes = new HashMap(); + brokerAttributes.put(Broker.CONNECTION_CLOSE_WHEN_NO_ROUTE, false); + + int response = getRestTestHelper().submitRequest("broker", "PUT", brokerAttributes); + assertEquals("Unexpected update response", 200, response); + + brokerDetails = getRestTestHelper().getJsonAsSingletonList("broker"); + assertFalse("closeOnNoRoute should be false", (Boolean)brokerDetails.get(Broker.CONNECTION_CLOSE_WHEN_NO_ROUTE)); + + Connection connection = getConnection(); + UnroutableMessageTestExceptionListener exceptionListener = new UnroutableMessageTestExceptionListener(); + connection.setExceptionListener(exceptionListener); + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + MessageProducer producer = session.createProducer(getTestQueue()); + TextMessage message = session.createTextMessage("Test"); + producer.send(message); + + session.commit(); + + exceptionListener.assertReceivedNoRouteWithReturnedMessage(message, getTestQueueName()); + } + + private Map getValidBrokerAttributes() + { + Map brokerAttributes = new HashMap(); + brokerAttributes.put(Broker.DEFAULT_VIRTUAL_HOST, TEST3_VIRTUALHOST); + brokerAttributes.put(Broker.CONNECTION_SESSION_COUNT_LIMIT, 10); + brokerAttributes.put(Broker.CONNECTION_HEART_BEAT_DELAY, 11000); + brokerAttributes.put(Broker.STATISTICS_REPORTING_PERIOD, 12000); + brokerAttributes.put(Broker.STATISTICS_REPORTING_RESET_ENABLED, true); + return brokerAttributes; + } + + private void assertBrokerAttributes(Map expectedAttributes, Map actualAttributes) + { + for (Map.Entry entry : expectedAttributes.entrySet()) + { + String attributeName = entry.getKey(); + Object attributeValue = entry.getValue(); + + Object currentValue = actualAttributes.get(attributeName); + assertEquals("Unexpected attribute " + attributeName + " value:", attributeValue, currentValue); + } + } + + protected void assertBrokerAttributes(Map brokerDetails) + { + Asserts.assertAttributesPresent(brokerDetails, BrokerModel.getInstance().getTypeRegistry().getAttributeNames( + Broker.class), + Broker.PROCESS_PID, + ConfiguredObject.TYPE, + ConfiguredObject.CREATED_BY, + ConfiguredObject.CREATED_TIME, + ConfiguredObject.LAST_UPDATED_BY, + ConfiguredObject.LAST_UPDATED_TIME, + ConfiguredObject.DESCRIPTION, + ConfiguredObject.CONTEXT, + ConfiguredObject.DESIRED_STATE); + + assertEquals("Unexpected value of attribute " + Broker.BUILD_VERSION, QpidProperties.getBuildVersion(), + brokerDetails.get(Broker.BUILD_VERSION)); + assertEquals("Unexpected value of attribute " + Broker.OPERATING_SYSTEM, SystemUtils.getOSString(), + brokerDetails.get(Broker.OPERATING_SYSTEM)); + assertEquals( + "Unexpected value of attribute " + Broker.PLATFORM, + System.getProperty("java.vendor") + " " + + System.getProperty("java.runtime.version", System.getProperty("java.version")), + brokerDetails.get(Broker.PLATFORM)); + assertEquals("Unexpected value of attribute " + Broker.DURABLE, Boolean.TRUE, brokerDetails.get(Broker.DURABLE)); + assertEquals("Unexpected value of attribute " + Broker.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(), + brokerDetails.get(Broker.LIFETIME_POLICY)); + assertEquals("Unexpected value of attribute " + Broker.NAME, "Broker", brokerDetails.get(Broker.NAME)); + assertEquals("Unexpected value of attribute " + Broker.STATE, State.ACTIVE.name(), brokerDetails.get(Broker.STATE)); + + assertNotNull("Unexpected value of attribute " + Broker.ID, brokerDetails.get(Broker.ID)); + assertNotNull("Unexpected value of attribute statistics", brokerDetails.get(BROKER_STATISTICS_ATTRIBUTE)); + assertNotNull("Unexpected value of attribute virtual host nodes", brokerDetails.get(BROKER_VIRTUALHOST_NODES_ATTRIBUTE)); + assertNotNull("Unexpected value of attribute ports", brokerDetails.get(BROKER_PORTS_ATTRIBUTE)); + assertNotNull("Unexpected value of attribute authenticationproviders", brokerDetails.get(BROKER_AUTHENTICATIONPROVIDERS_ATTRIBUTE)); + + assertNotNull("Unexpected value of attribute supportedVirtualHostTypes", brokerDetails.get(Broker.SUPPORTED_VIRTUALHOST_TYPES)); + assertNotNull("Unexpected value of attribute supportedVirtualHostNodeTypes", brokerDetails.get(Broker.SUPPORTED_VIRTUALHOSTNODE_TYPES)); + + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/CompressedResponsesRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/CompressedResponsesRestTest.java new file mode 100644 index 0000000000..891b44cd25 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/CompressedResponsesRestTest.java @@ -0,0 +1,141 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.util.LinkedHashMap; +import java.util.zip.GZIPInputStream; + +import org.codehaus.jackson.JsonParseException; +import org.codehaus.jackson.map.JsonMappingException; +import org.codehaus.jackson.map.ObjectMapper; + +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class CompressedResponsesRestTest extends QpidRestTestCase +{ + + private boolean _compress; + + @Override + public void setUp() throws Exception + { + } + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + getBrokerConfiguration().setObjectAttribute(Plugin.class, + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, + "compressResponses", + _compress); + } + + public void testCompressionOffAcceptOff() throws Exception + { + doCompressionTest(false, false); + } + + public void testCompressionOffAcceptOn() throws Exception + { + doCompressionTest(false, true); + } + + public void testCompressionOnAcceptOff() throws Exception + { + doCompressionTest(true, false); + } + + public void testCompressionOnAcceptOn() throws Exception + { + doCompressionTest(true, true); + + } + + private void doCompressionTest(final boolean allowCompression, + final boolean acceptCompressed) throws Exception + { + final boolean expectCompression = allowCompression && acceptCompressed; + _compress = allowCompression; + super.setUp(); + + HttpURLConnection conn = getRestTestHelper().openManagementConnection("/service/metadata", "GET"); + if(acceptCompressed) + { + conn.setRequestProperty("Accept-Encoding", "gzip"); + } + + conn.connect(); + + String contentEncoding = conn.getHeaderField("Content-Encoding"); + + if(expectCompression) + { + assertEquals("gzip", contentEncoding); + } + else + { + if(contentEncoding != null) + { + assertEquals("identity", contentEncoding); + } + } + + ByteArrayOutputStream contentBuffer = new ByteArrayOutputStream(); + + InputStream connectionInputStream = conn.getInputStream(); + byte[] buf = new byte[1024]; + int read; + while((read = connectionInputStream.read(buf))!= -1) + { + contentBuffer.write(buf,0,read); + } + + InputStream jsonStream; + + if(expectCompression) + { + jsonStream = new GZIPInputStream(new ByteArrayInputStream(contentBuffer.toByteArray())); + } + else + { + jsonStream = new ByteArrayInputStream(contentBuffer.toByteArray()); + } + + ObjectMapper mapper = new ObjectMapper(); + try + { + mapper.readValue(jsonStream, LinkedHashMap.class); + } + catch (JsonParseException | JsonMappingException e) + { + fail("Message was not in correct format"); + } + } + + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ConnectionRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ConnectionRestTest.java new file mode 100644 index 0000000000..439e592a7e --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ConnectionRestTest.java @@ -0,0 +1,281 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest; + +import java.io.IOException; +import java.net.URLDecoder; +import java.util.List; +import java.util.Map; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.servlet.http.HttpServletResponse; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.server.model.BrokerModel; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.Connection; +import org.apache.qpid.server.model.Session; + +public class ConnectionRestTest extends QpidRestTestCase +{ + /** + * Message number to publish into queue + */ + private static final int MESSAGE_NUMBER = 5; + private static final int MESSAGE_SIZE = 6; + + private static final String SESSIONS_ATTRIBUTE = "sessions"; + + private javax.jms.Connection _connection; + private javax.jms.Session _session; + + public void setUp() throws Exception + { + super.setUp(); + + _connection = getConnection(); + _session = _connection.createSession(true, javax.jms.Session.SESSION_TRANSACTED); + String queueName = getTestQueueName(); + Destination queue = _session.createQueue(queueName); + MessageConsumer consumer = _session.createConsumer(queue); + MessageProducer producer = _session.createProducer(queue); + _connection.start(); + + // send messages + for (int i = 0; i < MESSAGE_NUMBER; i++) + { + producer.send(_session.createTextMessage("Test-" + i)); + } + _session.commit(); + Message m = consumer.receive(1000l); + assertNotNull("First message was not received", m); + _session.commit(); + + // receive the rest of messages for rollback + for (int i = 0; i < MESSAGE_NUMBER - 1; i++) + { + m = consumer.receive(1000l); + assertNotNull("Subsequent messages were not received", m); + } + _session.rollback(); + + // receive them again + for (int i = 0; i < MESSAGE_NUMBER - 1; i++) + { + m = consumer.receive(1000l); + assertNotNull("Message was not received after rollback", m); + } + + // Session left open + } + + public void testGetAllConnections() throws Exception + { + List> connections = getRestTestHelper().getJsonAsList("connection"); + assertEquals("Unexpected number of connections", 1, connections.size()); + Asserts.assertConnection(connections.get(0), (AMQConnection) _connection); + } + + public void testGetVirtualHostConnections() throws Exception + { + List> connections = getRestTestHelper().getJsonAsList("connection/test/test"); + assertEquals("Unexpected number of connections", 1, connections.size()); + Asserts.assertConnection(connections.get(0), (AMQConnection) _connection); + } + + public void testGetConnectionByName() throws Exception + { + // get connection name + String connectionName = getConnectionName(); + + Map connectionDetails = getRestTestHelper().getJsonAsSingletonList("connection/test/test/" + + URLDecoder.decode(connectionName, "UTF-8")); + assertConnection(connectionDetails); + } + + public void testDeleteConnection() throws Exception + { + // get connection name + String connectionName = getConnectionName(); + + List> connections = getRestTestHelper().getJsonAsList("connection/test/test"); + assertEquals("Unexpected number of connections before deletion", 1, connections.size()); + + String connectionUrl = "connection/test/test/" + URLDecoder.decode(connectionName, "UTF-8"); + getRestTestHelper().submitRequest(connectionUrl, "DELETE", HttpServletResponse.SC_OK); + + connections = getRestTestHelper().getJsonAsList("connection/test/test"); + assertEquals("Unexpected number of connections before deletion", 0, connections.size()); + + try + { + _connection.createSession(true, javax.jms.Session.SESSION_TRANSACTED); + fail("Exception not thrown"); + } + catch (JMSException je) + { + // PASS + } + } + + public void testGetAllSessions() throws Exception + { + List> sessions = getRestTestHelper().getJsonAsList("session"); + assertEquals("Unexpected number of sessions", 1, sessions.size()); + assertSession(sessions.get(0), (AMQSession) _session); + } + + public void testGetVirtualHostSessions() throws Exception + { + List> sessions = getRestTestHelper().getJsonAsList("session/test/test"); + assertEquals("Unexpected number of sessions", 1, sessions.size()); + assertSession(sessions.get(0), (AMQSession) _session); + } + + public void testGetConnectionSessions() throws Exception + { + // get connection name + String connectionName = getConnectionName(); + + List> sessions = getRestTestHelper().getJsonAsList("session/test/test/" + + URLDecoder.decode(connectionName, "UTF-8")); + assertEquals("Unexpected number of sessions", 1, sessions.size()); + assertSession(sessions.get(0), (AMQSession) _session); + } + + public void testGetSessionByName() throws Exception + { + // get connection name + String connectionName = getConnectionName(); + + List> sessions = getRestTestHelper().getJsonAsList("session/test/test/" + + URLDecoder.decode(connectionName, "UTF-8") + "/" + ((AMQSession) _session).getChannelId()); + assertEquals("Unexpected number of sessions", 1, sessions.size()); + assertSession(sessions.get(0), (AMQSession) _session); + } + + public void testProducerSessionOpenHasTransactionStartAndUpdateTimes() throws Exception + { + Destination queue = _session.createQueue(getTestQueueName()); + MessageProducer producer = _session.createProducer(queue); + producer.send(_session.createMessage()); + // session left open + ((AMQSession)_session).sync(); + String connectionName = getConnectionName(); + + List> sessions = getRestTestHelper().getJsonAsList("session/test/test/" + + URLDecoder.decode(connectionName, "UTF-8") + "/" + ((AMQSession) _session).getChannelId()); + assertEquals("Unexpected number of sessions", 1, sessions.size()); + + final Map sessionData = sessions.get(0); + + @SuppressWarnings("unchecked") + Map statistics = (Map) sessionData.get(Asserts.STATISTICS_ATTRIBUTE); + + long transactionStartTime = ((Number) statistics.get("transactionStartTime")).longValue(); + long transactionUpdateTime = ((Number) statistics.get("transactionUpdateTime")).longValue(); + + assertTrue("Unexpected transaction start value for open transaction " + transactionStartTime, transactionStartTime > 0); + assertTrue("Unexpected transaction update value for open transaction " + transactionUpdateTime, transactionUpdateTime > 0); + assertTrue("Expected transaction update value " + transactionUpdateTime + " to be greater than transaction start time " + transactionStartTime, transactionUpdateTime >= transactionStartTime); + + + } + + private void assertConnection(Map connectionDetails) throws JMSException + { + Asserts.assertConnection(connectionDetails, (AMQConnection) _connection); + + @SuppressWarnings("unchecked") + Map statistics = (Map) connectionDetails.get(Asserts.STATISTICS_ATTRIBUTE); + assertEquals("Unexpected value of connection statistics attribute " + "bytesIn", MESSAGE_NUMBER + * MESSAGE_SIZE, statistics.get("bytesIn")); + assertEquals("Unexpected value of connection statistics attribute " + "bytesOut", MESSAGE_SIZE + + ((MESSAGE_NUMBER - 1) * MESSAGE_SIZE) * 2, statistics.get("bytesOut")); + assertEquals("Unexpected value of connection statistics attribute " + "messagesIn", MESSAGE_NUMBER, + statistics.get("messagesIn")); + assertEquals("Unexpected value of connection statistics attribute " + "messagesOut", + MESSAGE_NUMBER * 2 - 1, statistics.get("messagesOut")); + + @SuppressWarnings("unchecked") + List> sessions = (List>) connectionDetails.get(SESSIONS_ATTRIBUTE); + assertNotNull("Sessions cannot be found", sessions); + assertEquals("Unexpected number of sessions", 1, sessions.size()); + assertSession(sessions.get(0), (AMQSession) _session); + } + + private void assertSession(Map sessionData, AMQSession session) + { + assertNotNull("Session map cannot be null", sessionData); + Asserts.assertAttributesPresent(sessionData, BrokerModel.getInstance().getTypeRegistry().getAttributeNames( + Session.class), + ConfiguredObject.TYPE, + ConfiguredObject.CREATED_BY, + ConfiguredObject.CREATED_TIME, + ConfiguredObject.LAST_UPDATED_BY, + ConfiguredObject.LAST_UPDATED_TIME, + ConfiguredObject.DESCRIPTION, + ConfiguredObject.CONTEXT, + ConfiguredObject.DESIRED_STATE, + Session.STATE, + Session.DURABLE, + Session.LIFETIME_POLICY); + assertEquals("Unexpected value of attribute " + Session.NAME, session.getChannelId() + "", + sessionData.get(Session.NAME)); + assertEquals("Unexpected value of attribute " + Session.PRODUCER_FLOW_BLOCKED, Boolean.FALSE, + sessionData.get(Session.PRODUCER_FLOW_BLOCKED)); + assertEquals("Unexpected value of attribute " + Session.CHANNEL_ID, session.getChannelId(), + sessionData.get(Session.CHANNEL_ID)); + + @SuppressWarnings("unchecked") + Map statistics = (Map) sessionData.get(Asserts.STATISTICS_ATTRIBUTE); + Asserts.assertAttributesPresent(statistics, "consumerCount", + "localTransactionBegins", "localTransactionOpen", + "localTransactionRollbacks", "unacknowledgedMessages", + "transactionStartTime", "transactionUpdateTime"); + + assertEquals("Unexpected value of statistic attribute " + "unacknowledgedMessages", MESSAGE_NUMBER - 1, + statistics.get("unacknowledgedMessages")); + assertEquals("Unexpected value of statistic attribute " + "localTransactionBegins", 4, + statistics.get("localTransactionBegins")); + assertEquals("Unexpected value of statistic attribute " + "localTransactionRollbacks", 1, + statistics.get("localTransactionRollbacks")); + assertEquals("Unexpected value of statistic attribute " + "consumerCount", 1, + statistics.get("consumerCount")); + } + + private String getConnectionName() throws IOException + { + Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test/test"); + @SuppressWarnings("unchecked") + List> connections = (List>) hostDetails + .get(VirtualHostRestTest.VIRTUALHOST_CONNECTIONS_ATTRIBUTE); + assertEquals("Unexpected number of connections", 1, connections.size()); + Map connection = connections.get(0); + String connectionName = (String) connection.get(Connection.NAME); + return connectionName; + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ExchangeRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ExchangeRestTest.java new file mode 100644 index 0000000000..51cb6dde1a --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/ExchangeRestTest.java @@ -0,0 +1,120 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest; + +import java.net.URLDecoder; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.qpid.server.model.Binding; +import org.apache.qpid.server.model.Exchange; + +public class ExchangeRestTest extends QpidRestTestCase +{ + @Override + public void setUp() throws Exception + { + super.setUp(); + getRestTestHelper().createTestQueues(); + } + + public void testGet() throws Exception + { + List> exchanges = getRestTestHelper().getJsonAsList("exchange"); + assertNotNull("Exchanges cannot be null", exchanges); + assertTrue("Unexpected number of exchanges", exchanges.size() >= EXPECTED_VIRTUALHOSTS.length * EXPECTED_EXCHANGES.length); + for (Map exchange : exchanges) + { + Asserts.assertExchange((String) exchange.get(Exchange.NAME), (String) exchange.get(Exchange.TYPE), exchange); + } + } + + public void testGetHostExchanges() throws Exception + { + List> exchanges = getRestTestHelper().getJsonAsList("exchange/test"); + assertNotNull("Users cannot be null", exchanges); + assertEquals("Unexpected number of exchanges", exchanges.size(), EXPECTED_EXCHANGES.length); + for (String exchangeName : EXPECTED_EXCHANGES) + { + Map exchange = getRestTestHelper().find(Exchange.NAME, exchangeName, exchanges); + assertExchange(exchangeName, exchange); + } + } + + public void testGetHostExchangeByName() throws Exception + { + for (String exchangeName : EXPECTED_EXCHANGES) + { + Map exchange = getRestTestHelper().getJsonAsSingletonList("exchange/test/test/" + + URLDecoder.decode(exchangeName, "UTF-8")); + assertExchange(exchangeName, exchange); + } + } + + public void testSetExchangeSupported() throws Exception + { + String exchangeName = getTestName(); + String exchangeUrl = "exchange/test/test/" + exchangeName; + + Map attributes = new HashMap(); + attributes.put(Exchange.NAME, exchangeName); + attributes.put(Exchange.TYPE, "direct"); + int responseCode = getRestTestHelper().submitRequest(exchangeUrl, "PUT", attributes); + assertEquals("Exchange should be created", 201, responseCode); + + Map exchange = getRestTestHelper().getJsonAsSingletonList(exchangeUrl); + assertNotNull("Exchange not found", exchange); + + attributes = new HashMap(); + attributes.put(Exchange.NAME, exchangeName); + attributes.put(Exchange.ALTERNATE_EXCHANGE, "amq.direct"); + + responseCode = getRestTestHelper().submitRequest(exchangeUrl, "PUT", attributes); + assertEquals("Exchange update should be supported", 200, responseCode); + exchange = getRestTestHelper().getJsonAsSingletonList(exchangeUrl); + assertNotNull("Exchange not found", exchange); + assertEquals("amq.direct",exchange.get(Exchange.ALTERNATE_EXCHANGE)); + } + + private void assertExchange(String exchangeName, Map exchange) + { + assertNotNull("Exchange with name " + exchangeName + " is not found", exchange); + String type = (String) exchange.get(Exchange.TYPE); + Asserts.assertExchange(exchangeName, type, exchange); + if ("direct".equals(type)) + { + assertBindings(exchange); + } + } + + private void assertBindings(Map exchange) + { + @SuppressWarnings("unchecked") + List> bindings = (List>) exchange.get("bindings"); + for (String queueName : RestTestHelper.EXPECTED_QUEUES) + { + Map binding = getRestTestHelper().find(Binding.NAME, queueName, bindings); + Asserts.assertBinding(queueName, (String) exchange.get(Exchange.NAME), binding); + } + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java new file mode 100644 index 0000000000..4f1c1ad7a7 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java @@ -0,0 +1,373 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.UUID; + +import org.apache.qpid.server.BrokerOptions; +import org.apache.qpid.server.model.BrokerModel; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.Group; +import org.apache.qpid.server.model.GroupProvider; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.adapter.FileBasedGroupProvider; +import org.apache.qpid.server.model.adapter.FileBasedGroupProviderImpl; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.test.utils.TestFileUtils; + +public class GroupProviderRestTest extends QpidRestTestCase +{ + private static final String FILE_GROUP_MANAGER = TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE; + private File _groupFile; + + @Override + public void setUp() throws Exception + { + _groupFile = createTemporaryGroupFile(); + + getBrokerConfiguration().addGroupFileConfiguration(_groupFile.getAbsolutePath()); + + super.setUp(); + } + + @Override + public void tearDown() throws Exception + { + super.tearDown(); + + if (_groupFile != null) + { + if (_groupFile.exists()) + { + _groupFile.delete(); + } + } + } + + public void testGet() throws Exception + { + List> providerDetails = getRestTestHelper().getJsonAsList("groupprovider"); + assertNotNull("Providers details cannot be null", providerDetails); + assertEquals("Unexpected number of providers", 1, providerDetails.size()); + for (Map provider : providerDetails) + { + assertProvider(FILE_GROUP_MANAGER, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE, provider); + Map data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + + provider.get(GroupProvider.NAME)); + assertNotNull("Cannot load data for " + provider.get(GroupProvider.NAME), data); + assertProvider(FILE_GROUP_MANAGER, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE, data); + } + } + + public void testCreateNewGroup() throws Exception + { + String groupName = "newGroup"; + + Map data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); + assertNotNull("Cannot load data for provider", data); + + getRestTestHelper().assertNumberOfGroups(data, 1); + + getRestTestHelper().createGroup(groupName, FILE_GROUP_MANAGER); + + data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); + assertNotNull("Cannot load data for provider", data); + + getRestTestHelper().assertNumberOfGroups(data, 2); + } + + public void testRemoveGroup() throws Exception + { + String groupName = "myGroup"; + + Map data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); + assertNotNull("Cannot load data for provider", data); + + getRestTestHelper().assertNumberOfGroups(data, 1); + + getRestTestHelper().removeGroup(groupName, FILE_GROUP_MANAGER); + + data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); + assertNotNull("Cannot load data for provider", data); + + getRestTestHelper().assertNumberOfGroups(data, 0); + } + + public void testCreateNewFileGroupProviderFromExistingGroupFile() throws Exception + { + String[] groupMemberNames = {"test1","test2"}; + File groupFile = TestFileUtils.createTempFile(this, ".groups", "testusers.users=" + groupMemberNames[0] + "," + groupMemberNames[1]); + try + { + String providerName = getTestName(); + Map attributes = new HashMap(); + attributes.put(GroupProvider.NAME, providerName); + attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); + attributes.put(FileBasedGroupProvider.PATH, groupFile.getAbsolutePath()); + + int responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes); + assertEquals("Group provider was not created", 201, responseCode); + + Map data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + providerName + "?depth=2"); + assertProvider(providerName, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE, data); + assertEquals("Unexpected name", providerName, data.get(GroupProvider.NAME)); + assertEquals("Unexpected path", groupFile.getAbsolutePath(), data.get(FileBasedGroupProvider.PATH)); + + @SuppressWarnings("unchecked") + List> groups = (List>) data.get("groups"); + assertEquals("Unexpected group size", 1, groups.size()); + Map group = groups.get(0); + assertEquals("Unexpected group name", "testusers",group.get("name")); + + @SuppressWarnings("unchecked") + List> groupMemberList = (List>) group.get("groupmembers"); + assertEquals("Unexpected group members size", 2, groupMemberList.size()); + + for (String memberName : groupMemberNames) + { + boolean found = false; + for (Map memberData : groupMemberList) + { + Object name = memberData.get("name"); + if (memberName.equals(name)) + { + found = true; + break; + } + } + assertTrue("Cannot find group member " + memberName + " in " + groupMemberList , found); + } + } + finally + { + groupFile.delete(); + } + } + + public void testCreationOfNewFileGroupProviderFailsWhenPathIsMissed() throws Exception + { + String providerName = getTestName(); + Map attributes = new HashMap(); + attributes.put(GroupProvider.NAME, providerName); + attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); + + int responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes); + assertEquals("Group provider was created", 409, responseCode); + } + + public void testCreateNewFileGroupProviderFromNonExistingGroupFile() throws Exception + { + File groupFile = new File(TMP_FOLDER + File.separator + getTestName() + File.separator + "groups"); + assertFalse("Group file should not exist", groupFile.exists()); + try + { + String providerName = getTestName(); + Map attributes = new HashMap(); + attributes.put(GroupProvider.NAME, providerName); + attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); + attributes.put(FileBasedGroupProvider.PATH, groupFile.getAbsolutePath()); + + int responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes); + assertEquals("Group provider was not created", 201, responseCode); + + Map data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + providerName); + assertEquals("Unexpected name", providerName, data.get(GroupProvider.NAME)); + assertEquals("Unexpected path", groupFile.getAbsolutePath(), data.get(FileBasedGroupProvider.PATH)); + + @SuppressWarnings("unchecked") + List> groups = (List>) data.get("groups"); + assertNull("Unexpected groups", groups); + + assertTrue("Group file has not been created", groupFile.exists()); + } + finally + { + groupFile.delete(); + groupFile.getParentFile().delete(); + } + } + + public void testCreateNewFileGroupProviderForTheSameGroupFileFails() throws Exception + { + File groupFile = TestFileUtils.createTempFile(this, ".groups", "testusers.users=test1,test2"); + String providerName = getTestName(); + try + { + Map attributes = new HashMap(); + attributes.put(GroupProvider.NAME, providerName); + attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); + attributes.put(FileBasedGroupProvider.PATH, groupFile.getAbsolutePath()); + + int responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes); + assertEquals("Group provider was not created", 201, responseCode); + + attributes.put(GroupProvider.NAME, providerName + 2); + responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName + 2, "PUT", attributes); + assertEquals("Group provider for the same group file was created", 409, responseCode); + } + finally + { + groupFile.delete(); + } + } + + public void testDeleteGroupProvider() throws Exception + { + File groupFile = TestFileUtils.createTempFile(this, ".groups", "testusers.users=test1,test2"); + String providerName = getTestName(); + try + { + Map attributes = new HashMap(); + attributes.put(GroupProvider.NAME, providerName); + attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); + attributes.put(FileBasedGroupProvider.PATH, groupFile.getAbsolutePath()); + + int responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes); + assertEquals("Expected to fail because we can have only one password provider", 201, responseCode); + + responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName , "DELETE"); + assertEquals("Group provider was not deleted", 200, responseCode); + + List> providerDetails = getRestTestHelper().getJsonAsList("groupprovider/" + providerName); + assertEquals("Provider was not deleted", 0, providerDetails.size()); + assertFalse("Groups file should be deleted", groupFile.exists()); + } + finally + { + groupFile.delete(); + } + } + + public void testUpdateGroupProviderAttributesFails() throws Exception + { + File groupFile = TestFileUtils.createTempFile(this, ".groups", "testusers.users=test1,test2"); + String providerName = getTestName(); + try + { + Map attributes = new HashMap(); + attributes.put(GroupProvider.NAME, providerName); + attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); + attributes.put(FileBasedGroupProvider.PATH, groupFile.getAbsolutePath()); + + int responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes); + assertEquals("Expected to fail because we can have only one password provider", 201, responseCode); + + File newGroupFile = new File(TMP_FOLDER + File.separator + getTestName() + File.separator + "groups"); + attributes.put(FileBasedGroupProvider.PATH, newGroupFile.getAbsolutePath()); + + responseCode = getRestTestHelper().submitRequest("groupprovider/" + providerName, "PUT", attributes); + assertEquals("Expected to fail because we can have only one password provider", 409, responseCode); + } + finally + { + groupFile.delete(); + } + } + + public void testRemovalOfGroupProviderInErrorStateUsingManagementMode() throws Exception + { + stopBroker(); + + File file = new File(TMP_FOLDER, getTestName()); + if (file.exists()) + { + file.delete(); + } + assertFalse("Group file should not exist", file.exists()); + + TestBrokerConfiguration config = getBrokerConfiguration(); + config.removeObjectConfiguration(GroupProvider.class, TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE); + UUID id = config.addGroupFileConfiguration(file.getAbsolutePath()); + config.setSaved(false); + startBroker(0, true); + + getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD); + + Map groupProvider = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE); + assertEquals("Unexpected id", id.toString(), groupProvider.get(GroupProvider.ID)); + assertEquals("Unexpected path", file.getAbsolutePath() , groupProvider.get(FileBasedGroupProvider.PATH)); + assertEquals("Unexpected state", State.ERRORED.name() , groupProvider.get(GroupProvider.STATE)); + + int status = getRestTestHelper().submitRequest("groupprovider/" + TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE, "DELETE"); + assertEquals("ACL was not deleted", 200, status); + + List> providers = getRestTestHelper().getJsonAsList("groupprovider/" + TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE); + assertEquals("Provider exists", 0, providers.size()); + } + + private void assertProvider(String name, String type, Map provider) + { + Asserts.assertAttributesPresent(provider, BrokerModel.getInstance().getTypeRegistry().getAttributeNames( + GroupProvider.class), + ConfiguredObject.TYPE, + ConfiguredObject.CREATED_BY, + ConfiguredObject.CREATED_TIME, + ConfiguredObject.LAST_UPDATED_BY, + ConfiguredObject.LAST_UPDATED_TIME, + ConfiguredObject.DESCRIPTION, + ConfiguredObject.CONTEXT, + ConfiguredObject.DESIRED_STATE); + assertEquals("Unexpected value of provider attribute " + GroupProvider.STATE, State.ACTIVE.name(), + provider.get(GroupProvider.STATE)); + assertEquals("Unexpected value of provider attribute " + GroupProvider.LIFETIME_POLICY, + LifetimePolicy.PERMANENT.name(), provider.get(GroupProvider.LIFETIME_POLICY)); + assertEquals("Unexpected value of provider attribute " + GroupProvider.DURABLE, Boolean.TRUE, + provider.get(GroupProvider.DURABLE)); + assertEquals("Unexpected value of provider attribute " + GroupProvider.TYPE, type, + provider.get(GroupProvider.TYPE)); + + assertEquals("Unexpected value of provider attribute " + GroupProvider.NAME, name, + (String) provider.get(GroupProvider.NAME)); + + @SuppressWarnings("unchecked") + List> groups = (List>) provider.get("groups"); + assertNotNull("Groups were not found", groups); + assertEquals("Unexpected number of groups", 1, groups.size()); + for (Map group : groups) + { + + final String groupName = (String) group.get(Group.NAME); + assertNotNull("Attribute " + Group.NAME, groupName); + + assertNotNull("Attribute " + Group.ID, group.get(Group.ID)); + } + } + + private File createTemporaryGroupFile() throws Exception + { + File groupFile = File.createTempFile("group", "grp"); + groupFile.deleteOnExit(); + + Properties props = new Properties(); + props.put("myGroup.users", "guest"); + + props.store(new FileOutputStream(groupFile), "test group file"); + + return groupFile; + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/GroupRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/GroupRestTest.java new file mode 100644 index 0000000000..eeb9511289 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/GroupRestTest.java @@ -0,0 +1,109 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.apache.qpid.server.model.GroupMember; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class GroupRestTest extends QpidRestTestCase +{ + private static final String GROUP_NAME = "myGroup"; + private static final String FILE_GROUP_MANAGER = TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE; + private static final String EXISTING_MEMBER = "user1"; + private static final String NEW_MEMBER = "user2"; + + private File _groupFile; + + @Override + public void setUp() throws Exception + { + _groupFile = createTemporaryGroupFile(); + + getBrokerConfiguration().addGroupFileConfiguration(_groupFile.getAbsolutePath()); + + super.setUp(); + } + + @Override + public void tearDown() throws Exception + { + super.tearDown(); + + if (_groupFile != null) + { + if (_groupFile.exists()) + { + _groupFile.delete(); + } + } + } + + public void testGet() throws Exception + { + Map group = getRestTestHelper().getJsonAsSingletonList("group/" + FILE_GROUP_MANAGER + "/myGroup"); + List> groupmembers = (List>) group.get("groupmembers"); + assertEquals(1, groupmembers.size()); + + Map member1 = groupmembers.get(0); + assertEquals(EXISTING_MEMBER, (String)member1.get(GroupMember.NAME)); + } + + public void testCreateNewMemberOfGroup() throws Exception + { + Map group = getRestTestHelper().getJsonAsSingletonList("group/" + FILE_GROUP_MANAGER + "/myGroup"); + getRestTestHelper().assertNumberOfGroupMembers(group, 1); + + getRestTestHelper().createNewGroupMember(FILE_GROUP_MANAGER, GROUP_NAME, NEW_MEMBER); + + group = getRestTestHelper().getJsonAsSingletonList("group/" + FILE_GROUP_MANAGER + "/myGroup"); + getRestTestHelper().assertNumberOfGroupMembers(group, 2); + } + + public void testRemoveMemberFromGroup() throws Exception + { + Map group = getRestTestHelper().getJsonAsSingletonList("group/" + FILE_GROUP_MANAGER + "/myGroup"); + getRestTestHelper().assertNumberOfGroupMembers(group, 1); + + getRestTestHelper().removeMemberFromGroup(FILE_GROUP_MANAGER, GROUP_NAME, EXISTING_MEMBER); + + group = getRestTestHelper().getJsonAsSingletonList("group/" + FILE_GROUP_MANAGER + "/myGroup"); + getRestTestHelper().assertNumberOfGroupMembers(group, 0); + } + + private File createTemporaryGroupFile() throws Exception + { + File groupFile = File.createTempFile("group", "grp"); + groupFile.deleteOnExit(); + + Properties props = new Properties(); + props.put(GROUP_NAME + ".users", EXISTING_MEMBER); + + props.store(new FileOutputStream(groupFile), "test group file"); + + return groupFile; + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/HttpManagementRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/HttpManagementRestTest.java new file mode 100644 index 0000000000..abafb7fcaf --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/HttpManagementRestTest.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.systest.rest; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.qpid.server.management.plugin.HttpManagement; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class HttpManagementRestTest extends QpidRestTestCase +{ + + public void testGetHttpManagement() throws Exception + { + Map details = getRestTestHelper().getJsonAsSingletonList( + "plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT); + + assertEquals("Unexpected session timeout", HttpManagement.DEFAULT_TIMEOUT_IN_SECONDS, + details.get(HttpManagement.TIME_OUT)); + assertEquals("Unexpected http basic auth enabled", true, + details.get(HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED)); + assertEquals("Unexpected https basic auth enabled", true, + details.get(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED)); + assertEquals("Unexpected http sasl auth enabled", true, + details.get(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED)); + assertEquals("Unexpected https sasl auth enabled", true, + details.get(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED)); + } + + public void testUpdateAttributes() throws Exception + { + Map attributes = new HashMap(); + attributes.put(HttpManagement.NAME, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT); + attributes.put(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED, false); + attributes.put(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED, false); + attributes.put(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED, false); + attributes.put(HttpManagement.TIME_OUT, 10000); + + getRestTestHelper().submitRequest("plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, "PUT", attributes); + + Map details = getRestTestHelper().getJsonAsSingletonList( + "plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT); + + assertEquals("Unexpected session timeout", 10000, details.get(HttpManagement.TIME_OUT)); + assertEquals("Unexpected http basic auth enabled", true, details.get(HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED)); + assertEquals("Unexpected https basic auth enabled", false, details.get(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED)); + assertEquals("Unexpected http sasl auth enabled", false, details.get(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED)); + assertEquals("Unexpected https sasl auth enabled", false, details.get(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED)); + } + + public void testUpdateAttributesWithInvalidValues() throws Exception + { + Map invalidAttributes = new HashMap(); + invalidAttributes.put(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED, 1); + invalidAttributes.put(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED, 2); + invalidAttributes.put(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED, 3); + invalidAttributes.put(HttpManagement.TIME_OUT, "undefined"); + + for (Map.Entry invalidAttribute : invalidAttributes.entrySet()) + { + Map attributes = new HashMap(); + attributes.put(invalidAttribute.getKey(), invalidAttribute.getValue()); + int response = getRestTestHelper().submitRequest("plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, "PUT", attributes); + assertEquals("Update should fail for attribute " + invalidAttribute.getKey() + " with value " + invalidAttribute.getValue() , 409, response); + } + + Map attributes = new HashMap(); + attributes.put(HttpManagement.TIME_OUT, -1l); + int response = getRestTestHelper().submitRequest("plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, "PUT", attributes); + assertEquals("Update should fail for invalid session timeout", 409, response); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/KeyStoreRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/KeyStoreRestTest.java new file mode 100644 index 0000000000..4b881d1e9f --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/KeyStoreRestTest.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.systest.rest; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.codehaus.jackson.JsonGenerationException; +import org.codehaus.jackson.JsonParseException; +import org.codehaus.jackson.map.JsonMappingException; + +import org.apache.qpid.server.model.AbstractConfiguredObject; +import org.apache.qpid.server.model.KeyStore; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Transport; +import org.apache.qpid.server.security.FileKeyStore; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.test.utils.TestSSLConstants; + +public class KeyStoreRestTest extends QpidRestTestCase +{ + @Override + public void setUp() throws Exception + { + // not calling super.setUp() to avoid broker start-up until + // after any necessary configuration + } + + public void testGet() throws Exception + { + super.setUp(); + + //verify existence of the default keystore used by the systests + List> keyStores = assertNumberOfKeyStores(1); + + Map keystore = keyStores.get(0); + assertKeyStoreAttributes(keystore, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE, + System.getProperty(QPID_HOME) + "/../" + TestSSLConstants.BROKER_KEYSTORE, null); + } + + public void testCreate() throws Exception + { + super.setUp(); + + String name = getTestName(); + String certAlias = "app2"; + + assertNumberOfKeyStores(1); + createKeyStore(name, certAlias); + assertNumberOfKeyStores(2); + + List> keyStores = getRestTestHelper().getJsonAsList("keystore/" + name); + assertNotNull("details cannot be null", keyStores); + + assertKeyStoreAttributes(keyStores.get(0), name, TestSSLConstants.KEYSTORE, certAlias); + } + + public void testDelete() throws Exception + { + super.setUp(); + + String name = getTestName(); + String certAlias = "app2"; + + assertNumberOfKeyStores(1); + createKeyStore(name, certAlias); + assertNumberOfKeyStores(2); + + int responseCode = getRestTestHelper().submitRequest("keystore/" + name , "DELETE"); + assertEquals("Unexpected response code for provider deletion", 200, responseCode); + + List> keyStore = getRestTestHelper().getJsonAsList("keystore/" + name); + assertNotNull("details should not be null", keyStore); + assertTrue("details should be empty as the keystore no longer exists", keyStore.isEmpty()); + + //check only the default systests key store remains + List> keyStores = assertNumberOfKeyStores(1); + Map keystore = keyStores.get(0); + assertKeyStoreAttributes(keystore, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE, + System.getProperty(QPID_HOME) + "/../" + TestSSLConstants.BROKER_KEYSTORE, null); + } + + public void testDeleteFailsWhenKeyStoreInUse() throws Exception + { + String name = "testDeleteFailsWhenKeyStoreInUse"; + + //add a new key store config to use + Map sslKeyStoreAttributes = new HashMap(); + sslKeyStoreAttributes.put(KeyStore.NAME, name); + sslKeyStoreAttributes.put(FileKeyStore.PATH, TestSSLConstants.BROKER_KEYSTORE); + sslKeyStoreAttributes.put(FileKeyStore.PASSWORD, TestSSLConstants.BROKER_KEYSTORE_PASSWORD); + getBrokerConfiguration().addObjectConfiguration(KeyStore.class,sslKeyStoreAttributes); + + //add the SSL port using it + Map sslPortAttributes = new HashMap(); + sslPortAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); + sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT); + sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT); + sslPortAttributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); + sslPortAttributes.put(Port.KEY_STORE, name); + getBrokerConfiguration().addObjectConfiguration(Port.class,sslPortAttributes); + + super.setUp(); + + //verify the keystore is there + assertNumberOfKeyStores(2); + + List> keyStore = getRestTestHelper().getJsonAsList("keystore/" + name); + assertNotNull("details should not be null", keyStore); + assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.BROKER_KEYSTORE, null); + + //try to delete it, which should fail as it is in use + int responseCode = getRestTestHelper().submitRequest("keystore/" + name , "DELETE"); + assertEquals("Unexpected response code for provider deletion", 409, responseCode); + + //check its still there + assertNumberOfKeyStores(2); + keyStore = getRestTestHelper().getJsonAsList("keystore/" + name); + assertNotNull("details should not be null", keyStore); + assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.BROKER_KEYSTORE, null); + } + + public void testUpdateWithGoodPathSucceeds() throws Exception + { + super.setUp(); + + String name = getTestName(); + + assertNumberOfKeyStores(1); + createKeyStore(name, null); + assertNumberOfKeyStores(2); + + Map attributes = new HashMap(); + attributes.put(KeyStore.NAME, name); + attributes.put(FileKeyStore.PATH, TestSSLConstants.UNTRUSTED_KEYSTORE); + + int responseCode = getRestTestHelper().submitRequest("keystore/" + name , "PUT", attributes); + assertEquals("Unexpected response code for keystore update", 200, responseCode); + + List> keyStore = getRestTestHelper().getJsonAsList("keystore/" + name); + assertNotNull("details should not be null", keyStore); + + assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.UNTRUSTED_KEYSTORE, null); + } + + public void testUpdateWithNonExistentPathFails() throws Exception + { + super.setUp(); + + String name = getTestName(); + + assertNumberOfKeyStores(1); + createKeyStore(name, null); + assertNumberOfKeyStores(2); + + Map attributes = new HashMap(); + attributes.put(KeyStore.NAME, name); + attributes.put(FileKeyStore.PATH, "does.not.exist"); + + int responseCode = getRestTestHelper().submitRequest("keystore/" + name , "PUT", attributes); + assertEquals("Unexpected response code for keystore update", 409, responseCode); + + List> keyStore = getRestTestHelper().getJsonAsList("keystore/" + name); + assertNotNull("details should not be null", keyStore); + + //verify the details remain unchanged + assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.KEYSTORE, null); + } + + public void testUpdateCertificateAlias() throws Exception + { + super.setUp(); + + String name = getTestName(); + + assertNumberOfKeyStores(1); + createKeyStore(name, "app1"); + assertNumberOfKeyStores(2); + + List> keyStore = getRestTestHelper().getJsonAsList("keystore/" + name); + assertNotNull("details should not be null", keyStore); + assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.KEYSTORE, "app1"); + + //Update the certAlias from app1 to app2 + Map attributes = new HashMap(); + attributes.put(KeyStore.NAME, name); + attributes.put(FileKeyStore.CERTIFICATE_ALIAS, "app2"); + + int responseCode = getRestTestHelper().submitRequest("keystore/" + name , "PUT", attributes); + assertEquals("Unexpected response code for keystore update", 200, responseCode); + + keyStore = getRestTestHelper().getJsonAsList("keystore/" + name); + assertNotNull("details should not be null", keyStore); + + assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.KEYSTORE, "app2"); + + //Update the certAlias to clear it (i.e go from from app1 to null) + attributes = new HashMap(); + attributes.put(KeyStore.NAME, name); + attributes.put(FileKeyStore.CERTIFICATE_ALIAS, null); + + responseCode = getRestTestHelper().submitRequest("keystore/" + name , "PUT", attributes); + assertEquals("Unexpected response code for keystore update", 200, responseCode); + + keyStore = getRestTestHelper().getJsonAsList("keystore/" + name); + assertNotNull("details should not be null", keyStore); + + assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.KEYSTORE, null); + } + + private List> assertNumberOfKeyStores(int numberOfKeystores) throws IOException, + JsonParseException, JsonMappingException + { + List> keyStores = getRestTestHelper().getJsonAsList("keystore"); + assertNotNull("keystores should not be null", keyStores); + assertEquals("Unexpected number of keystores", numberOfKeystores, keyStores.size()); + + return keyStores; + } + + private void createKeyStore(String name, String certAlias) throws IOException, JsonGenerationException, JsonMappingException + { + Map keyStoreAttributes = new HashMap(); + keyStoreAttributes.put(KeyStore.NAME, name); + keyStoreAttributes.put(FileKeyStore.PATH, TestSSLConstants.KEYSTORE); + keyStoreAttributes.put(FileKeyStore.PASSWORD, TestSSLConstants.KEYSTORE_PASSWORD); + keyStoreAttributes.put(FileKeyStore.CERTIFICATE_ALIAS, certAlias); + + int responseCode = getRestTestHelper().submitRequest("keystore/" + name, "PUT", keyStoreAttributes); + assertEquals("Unexpected response code", 201, responseCode); + } + + private void assertKeyStoreAttributes(Map keystore, String name, String path, String certAlias) + { + assertEquals("default systests key store is missing", + name, keystore.get(KeyStore.NAME)); + assertEquals("unexpected path to key store", + path, keystore.get(FileKeyStore.PATH)); + assertEquals("unexpected (dummy) password of default systests key store", + AbstractConfiguredObject.SECURED_STRING_VALUE, keystore.get(FileKeyStore.PASSWORD)); + assertEquals("unexpected type of default systests key store", + java.security.KeyStore.getDefaultType(), keystore.get(FileKeyStore.KEY_STORE_TYPE)); + assertEquals("unexpected certificateAlias value", + certAlias, keystore.get(FileKeyStore.CERTIFICATE_ALIAS)); + if(certAlias == null) + { + assertFalse("should not be a certificateAlias attribute", + keystore.containsKey(FileKeyStore.CERTIFICATE_ALIAS)); + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/LogRecordsRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/LogRecordsRestTest.java new file mode 100644 index 0000000000..4d06c7b624 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/LogRecordsRestTest.java @@ -0,0 +1,63 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.systest.rest; + +import java.util.List; +import java.util.Map; + +public class LogRecordsRestTest extends QpidRestTestCase +{ + public void testGet() throws Exception + { + List> logs = getRestTestHelper().getJsonAsList("/service/logrecords"); + assertNotNull("Logs data cannot be null", logs); + assertTrue("Logs are not found", logs.size() > 0); + Map record = getRestTestHelper().find("message", "[Broker] BRK-1004 : Qpid Broker Ready", logs); + + assertNotNull("BRK-1004 message is not found", record); + assertNotNull("Message id cannot be null", record.get("id")); + assertNotNull("Message timestamp cannot be null", record.get("timestamp")); + assertEquals("Unexpected log level", "INFO", record.get("level")); + assertEquals("Unexpected thread", "main", record.get("thread")); + assertEquals("Unexpected logger", "qpid.message.broker.ready", record.get("logger")); + } + + public void testGetLogsFromGivenId() throws Exception + { + List> logs = getRestTestHelper().getJsonAsList("/service/logrecords"); + assertNotNull("Logs data cannot be null", logs); + assertTrue("Logs are not found", logs.size() > 0); + + Map lastLog = logs.get(logs.size() -1); + Object lastId = lastLog.get("id"); + + //make sure that new logs are created + getConnection(); + + List> newLogs = getRestTestHelper().getJsonAsList("/service/logrecords?lastLogId=" + lastId); + assertNotNull("Logs data cannot be null", newLogs); + assertTrue("Logs are not found", newLogs.size() > 0); + + Object nextId = newLogs.get(0).get("id"); + + assertEquals("Unexpected next log id", ((Number)lastId).longValue() + 1, ((Number)nextId).longValue()); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/LogViewerTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/LogViewerTest.java new file mode 100644 index 0000000000..f2fb2581f7 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/LogViewerTest.java @@ -0,0 +1,105 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.util.List; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import org.apache.qpid.server.BrokerOptions; + +public class LogViewerTest extends QpidRestTestCase +{ + public static final String DEFAULT_FILE_APPENDER_NAME = "FileAppender"; + private String _expectedLogFileName; + + public void setUp() throws Exception + { + setSystemProperty("logsuffix", "-" + getTestQueueName()); + _expectedLogFileName = System.getProperty("logprefix", "") + "qpid" + System.getProperty("logsuffix", "") + ".log"; + + // use real broker log file + File brokerLogFile = new File(System.getProperty(QPID_HOME), BrokerOptions.DEFAULT_LOG_CONFIG_FILE); + setBrokerCommandLog4JFile(brokerLogFile); + + super.setUp(); + } + + public void testGetLogFiles() throws Exception + { + List> logFiles = getRestTestHelper().getJsonAsList("/service/logfilenames"); + assertNotNull("Log files data cannot be null", logFiles); + + // 1 file appender is configured in QPID default log4j xml: + assertTrue("Unexpected number of log files", logFiles.size() > 0); + + Map logFileDetails = logFiles.get(0); + assertEquals("Unexpected log file name", _expectedLogFileName, logFileDetails.get("name")); + assertEquals("Unexpected log file mime type", "text/plain", logFileDetails.get("mimeType")); + assertEquals("Unexpected log file appender",DEFAULT_FILE_APPENDER_NAME, logFileDetails.get("appenderName")); + assertTrue("Unexpected log file size", ((Number)logFileDetails.get("size")).longValue()>0); + assertTrue("Unexpected log file modification time", ((Number)logFileDetails.get("lastModified")).longValue()>0); + } + + public void testDownloadExistingLogFiles() throws Exception + { + byte[] bytes = getRestTestHelper().getBytes("/service/logfile?l=" + DEFAULT_FILE_APPENDER_NAME + "%2F" + _expectedLogFileName); + + ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(bytes)); + try + { + ZipEntry entry = zis.getNextEntry(); + assertEquals("Unexpected broker log file name", DEFAULT_FILE_APPENDER_NAME + "/" + _expectedLogFileName, entry.getName()); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int len; + while ((len = zis.read(buffer)) > 0) + { + baos.write(buffer, 0, len); + } + baos.close(); + assertTrue("Unexpected broker log file content", new String(baos.toByteArray()).contains("BRK-1004")); + assertNull("Unexpepected log file entry", zis.getNextEntry()); + } + finally + { + zis.close(); + } + } + + public void testDownloadNonExistingLogFiles() throws Exception + { + int responseCode = getRestTestHelper().submitRequest("/service/logfile?l=" + DEFAULT_FILE_APPENDER_NAME + "%2F" + + _expectedLogFileName + "_" + System.currentTimeMillis(), "GET"); + + assertEquals("Unexpected response code", 404, responseCode); + } + + public void testDownloadNonLogFiles() throws Exception + { + int responseCode = getRestTestHelper().submitRequest("/service/logfile?l=config.json", "GET"); + assertEquals("Unexpected response code", 400, responseCode); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/MessagesRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/MessagesRestTest.java new file mode 100644 index 0000000000..efa4776afd --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/MessagesRestTest.java @@ -0,0 +1,355 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.servlet.http.HttpServletResponse; + +import org.codehaus.jackson.map.JsonMappingException; + +public class MessagesRestTest extends QpidRestTestCase +{ + + /** + * Message number to publish into queue + */ + private static final int MESSAGE_NUMBER = 12; + + private Connection _connection; + private Session _session; + private MessageProducer _producer; + private long _startTime; + private long _ttl; + + public void setUp() throws Exception + { + super.setUp(); + _startTime = System.currentTimeMillis(); + _connection = getConnection(); + _session = _connection.createSession(true, Session.SESSION_TRANSACTED); + String queueName = getTestQueueName(); + Destination queue = _session.createQueue(queueName); + _session.createConsumer(queue).close(); + _producer = _session.createProducer(queue); + + _ttl = TimeUnit.DAYS.toMillis(1); + for (int i = 0; i < MESSAGE_NUMBER; i++) + { + Message m = _session.createTextMessage("Test-" + i); + m.setIntProperty("index", i); + if (i % 2 == 0) + { + _producer.send(m); + } + else + { + _producer.send(m, DeliveryMode.NON_PERSISTENT, 5, _ttl); + } + } + _session.commit(); + } + + public void testGet() throws Exception + { + String queueName = getTestQueueName(); + List> messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName); + assertNotNull("Messages are not found", messages); + assertEquals("Unexpected number of messages", MESSAGE_NUMBER, messages.size()); + int position = 0; + for (Map message : messages) + { + assertMessage(position, message); + position++; + } + } + + public void testGetMessageContent() throws Exception + { + String queueName = getTestQueueName(); + + // add bytes message + BytesMessage byteMessage = _session.createBytesMessage(); + byte[] messageBytes = "Test".getBytes(); + byteMessage.writeBytes(messageBytes); + byteMessage.setStringProperty("test", "value"); + _producer.send(byteMessage); + _session.commit(); + + // get message IDs + List ids = getMesssageIds(queueName); + + Map message = getRestTestHelper().getJsonAsMap("/service/message/test/" + queueName + "/" + ids.get(0)); + assertMessageAttributes(message); + assertMessageAttributeValues(message, true); + + @SuppressWarnings("unchecked") + Map headers = (Map) message.get("headers"); + assertNotNull("Message headers are not found", headers); + assertEquals("Unexpected message header", 0, headers.get("index")); + + Long lastMessageId = ids.get(ids.size() - 1); + message = getRestTestHelper().getJsonAsMap("/service/message/test/" + queueName + "/" + lastMessageId); + assertMessageAttributes(message); + assertEquals("Unexpected message attribute mimeType", "application/octet-stream", message.get("mimeType")); + assertEquals("Unexpected message attribute size", 4, message.get("size")); + + @SuppressWarnings("unchecked") + Map bytesMessageHeader = (Map) message.get("headers"); + assertNotNull("Message headers are not found", bytesMessageHeader); + assertEquals("Unexpected message header", "value", bytesMessageHeader.get("test")); + + // get content + byte[] data = getRestTestHelper().getBytes("/service/message-content/test/" + queueName + "/" + lastMessageId); + assertTrue("Unexpected message", Arrays.equals(messageBytes, data)); + + } + + public void testPostMoveMessages() throws Exception + { + String queueName = getTestQueueName(); + String queueName2 = queueName + "_2"; + Destination queue2 = _session.createQueue(queueName2); + _session.createConsumer(queue2); + + // get message IDs + List ids = getMesssageIds(queueName); + + // move half of the messages + int movedNumber = ids.size() / 2; + List movedMessageIds = new ArrayList(); + for (int i = 0; i < movedNumber; i++) + { + movedMessageIds.add(ids.remove(i)); + } + + // move messages + + Map messagesData = new HashMap(); + messagesData.put("messages", movedMessageIds); + messagesData.put("destinationQueue", queueName2); + messagesData.put("move", Boolean.TRUE); + + getRestTestHelper().submitRequest("/service/message/test/" + queueName, "POST", messagesData, HttpServletResponse.SC_OK); + + // check messages on target queue + List> messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName2); + assertNotNull("Messages are not found", messages); + assertEquals("Unexpected number of messages", movedMessageIds.size(), messages.size()); + for (Long id : movedMessageIds) + { + Map message = getRestTestHelper().find("id", id.intValue(), messages); + assertMessageAttributes(message); + } + + // check messages on original queue + messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName); + assertNotNull("Messages are not found", messages); + assertEquals("Unexpected number of messages", ids.size(), messages.size()); + for (Long id : ids) + { + Map message = getRestTestHelper().find("id", id.intValue(), messages); + assertMessageAttributes(message); + } + for (Long id : movedMessageIds) + { + Map message = getRestTestHelper().find("id", id.intValue(), messages); + assertNull("Moved message " + id + " is found on original queue", message); + } + } + + public void testPostCopyMessages() throws Exception + { + String queueName = getTestQueueName(); + String queueName2 = queueName + "_2"; + Destination queue2 = _session.createQueue(queueName2); + _session.createConsumer(queue2); + + // get message IDs + List ids = getMesssageIds(queueName); + + // copy half of the messages + int copyNumber = ids.size() / 2; + List copyMessageIds = new ArrayList(); + for (int i = 0; i < copyNumber; i++) + { + copyMessageIds.add(ids.remove(i)); + } + + // copy messages + Map messagesData = new HashMap(); + messagesData.put("messages", copyMessageIds); + messagesData.put("destinationQueue", queueName2); + + getRestTestHelper().submitRequest("/service/message/test/" + queueName, "POST", messagesData, HttpServletResponse.SC_OK); + + // check messages on target queue + List> messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName2); + assertNotNull("Messages are not found", messages); + assertEquals("Unexpected number of messages", copyMessageIds.size(), messages.size()); + for (Long id : copyMessageIds) + { + Map message = getRestTestHelper().find("id", id.intValue(), messages); + assertMessageAttributes(message); + } + + // check messages on original queue + messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName); + assertNotNull("Messages are not found", messages); + assertEquals("Unexpected number of messages", MESSAGE_NUMBER, messages.size()); + for (Long id : ids) + { + Map message = getRestTestHelper().find("id", id.intValue(), messages); + assertMessageAttributes(message); + } + for (Long id : copyMessageIds) + { + Map message = getRestTestHelper().find("id", id.intValue(), messages); + assertMessageAttributes(message); + } + } + + public void testDeleteMessages() throws Exception + { + String queueName = getTestQueueName(); + + // get message IDs + List ids = getMesssageIds(queueName); + + // delete half of the messages + int deleteNumber = ids.size() / 2; + StringBuilder queryString = new StringBuilder(); + List deleteMessageIds = new ArrayList<>(); + for (int i = 0; i < deleteNumber; i++) + { + Long id = ids.remove(i); + deleteMessageIds.add(id); + if (queryString.length() > 0) + { + queryString.append("&"); + } + queryString.append("id=").append(id); + } + + // delete messages + getRestTestHelper().submitRequest("/service/message/test/" + queueName + "?" + queryString.toString(), "DELETE", HttpServletResponse.SC_OK); + + // check messages on queue + List> messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName); + assertNotNull("Messages are not found", messages); + assertEquals("Unexpected number of messages", ids.size(), messages.size()); + for (Long id : ids) + { + Map message = getRestTestHelper().find("id", id.intValue(), messages); + assertMessageAttributes(message); + } + for (Long id : deleteMessageIds) + { + Map message = getRestTestHelper().find("id", id.intValue(), messages); + assertNull("Message with id " + id + " was not deleted", message); + } + } + + public void testClearQueue() throws Exception + { + String queueName = getTestQueueName(); + + // clear queue + getRestTestHelper().submitRequest("/service/message/test/" + queueName + "?clear=true", "DELETE", HttpServletResponse.SC_OK); + + // check messages on queue + List> messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName); + assertNotNull("Messages are not found", messages); + assertEquals("Unexpected number of messages", 0, messages.size()); + } + + + private List getMesssageIds(String queueName) throws IOException, JsonMappingException + { + List> messages = getRestTestHelper().getJsonAsList("/service/message/test/" + queueName); + List ids = new ArrayList(); + for (Map message : messages) + { + ids.add(((Number) message.get("id")).longValue()); + } + return ids; + } + + private void assertMessage(int position, Map message) + { + assertMessageAttributes(message); + + assertEquals("Unexpected message attribute position", position, message.get("position")); + assertEquals("Unexpected message attribute size", position < 10 ? 6 : 7, message.get("size")); + boolean even = position % 2 == 0; + assertMessageAttributeValues(message, even); + } + + private void assertMessageAttributeValues(Map message, boolean even) + { + if (even) + { + assertNull("Unexpected message attribute expirationTime", message.get("expirationTime")); + assertEquals("Unexpected message attribute priority", 4, message.get("priority")); + assertEquals("Unexpected message attribute persistent", Boolean.TRUE, message.get("persistent")); + } + else + { + assertEquals("Unexpected message attribute expirationTime", ((Number) message.get("timestamp")).longValue() + + _ttl, message.get("expirationTime")); + assertEquals("Unexpected message attribute priority", 5, message.get("priority")); + assertEquals("Unexpected message attribute persistent", Boolean.FALSE, message.get("persistent")); + } + assertEquals("Unexpected message attribute mimeType", "text/plain", message.get("mimeType")); + assertEquals("Unexpected message attribute userId", "guest", message.get("userId")); + assertEquals("Unexpected message attribute deliveryCount", 0, message.get("deliveryCount")); + assertEquals("Unexpected message attribute state", "Available", message.get("state")); + } + + private void assertMessageAttributes(Map message) + { + assertNotNull("Message map cannot be null", message); + assertNotNull("Unexpected message attribute deliveryCount", message.get("deliveryCount")); + assertNotNull("Unexpected message attribute state", message.get("state")); + assertNotNull("Unexpected message attribute id", message.get("id")); + assertNotNull("Message arrivalTime cannot be null", message.get("arrivalTime")); + assertNotNull("Message timestamp cannot be null", message.get("timestamp")); + assertTrue("Message arrivalTime cannot be null", ((Number) message.get("arrivalTime")).longValue() > _startTime); + assertNotNull("Message messageId cannot be null", message.get("messageId")); + assertNotNull("Unexpected message attribute mimeType", message.get("mimeType")); + assertNotNull("Unexpected message attribute userId", message.get("userId")); + assertNotNull("Message priority cannot be null", message.get("priority")); + assertNotNull("Message persistent cannot be null", message.get("persistent")); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java new file mode 100644 index 0000000000..8b86163aa6 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PortRestTest.java @@ -0,0 +1,366 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest; + +import java.net.ServerSocket; +import java.net.URLDecoder; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import org.apache.qpid.server.BrokerOptions; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.Transport; +import org.apache.qpid.server.model.port.JmxPort; +import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager; +import org.apache.qpid.test.utils.PortHelper; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class PortRestTest extends QpidRestTestCase +{ + + public void testGet() throws Exception + { + List> ports = getRestTestHelper().getJsonAsList("port/"); + assertNotNull("Port data cannot be null", ports); + assertEquals("Unexpected number of ports", 2, ports.size()); + + String httpPortName = TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT; + Map portData = getRestTestHelper().find(Port.NAME, httpPortName, ports); + assertNotNull("Http port " + httpPortName + " is not found", portData); + Asserts.assertPortAttributes(portData); + + String amqpPortName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; + Map amqpPortData = getRestTestHelper().find(Port.NAME, amqpPortName, ports); + assertNotNull("Amqp port " + amqpPortName + " is not found", amqpPortData); + Asserts.assertPortAttributes(amqpPortData); + } + + public void testGetPort() throws Exception + { + List> ports = getRestTestHelper().getJsonAsList("port/"); + assertNotNull("Ports data cannot be null", ports); + assertEquals("Unexpected number of ports", 2, ports.size()); + for (Map portMap : ports) + { + String portName = (String) portMap.get(Port.NAME); + assertNotNull("Port name attribute is not found", portName); + Map portData = getRestTestHelper().getJsonAsSingletonList("port/" + URLDecoder.decode(portName, "UTF-8")); + assertNotNull("Port " + portName + " is not found", portData); + Asserts.assertPortAttributes(portData); + } + } + + public void testPutAmqpPortWithMinimumAttributes() throws Exception + { + String portName = "test-port"; + Map attributes = new HashMap(); + attributes.put(Port.NAME, portName); + attributes.put(Port.PORT, findFreePort()); + attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); + + int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); + assertEquals("Unexpected response code", 201, responseCode); + + List> portDetails = getRestTestHelper().getJsonAsList("port/" + portName); + assertNotNull("Port details cannot be null", portDetails); + assertEquals("Unexpected number of ports with name " + portName, 1, portDetails.size()); + Map port = portDetails.get(0); + Asserts.assertPortAttributes(port); + + // make sure that port is there after broker restart + restartBroker(); + + portDetails = getRestTestHelper().getJsonAsList("port/" + portName); + assertNotNull("Port details cannot be null", portDetails); + assertEquals("Unexpected number of ports with name " + portName, 1, portDetails.size()); + } + + public void testPutRmiPortWithMinimumAttributes() throws Exception + { + String portNameRMI = "test-port-rmi"; + Map attributes = new HashMap(); + attributes.put(Port.NAME, portNameRMI); + int rmiPort = findFreePort(); + attributes.put(Port.PORT, rmiPort); + attributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.RMI)); + + int responseCode = getRestTestHelper().submitRequest("port/" + portNameRMI, "PUT", attributes); + assertEquals("Unexpected response code", 201, responseCode); + + + List> portDetails = getRestTestHelper().getJsonAsList("port/" + portNameRMI); + assertNotNull("Port details cannot be null", portDetails); + assertEquals("Unexpected number of ports with name " + portNameRMI, 1, portDetails.size()); + Map port = portDetails.get(0); + Asserts.assertPortAttributes(port, State.QUIESCED); + + String portNameJMX = "test-port-jmx"; + attributes = new HashMap(); + attributes.put(Port.NAME, portNameJMX); + int jmxPort = getNextAvailable(rmiPort + 1); + attributes.put(Port.PORT, jmxPort); + attributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.JMX_RMI)); + attributes.put(JmxPort.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); + + responseCode = getRestTestHelper().submitRequest("port/" + portNameJMX, "PUT", attributes); + assertEquals("Unexpected response code", 201, responseCode); + + + portDetails = getRestTestHelper().getJsonAsList("port/" + portNameJMX); + assertNotNull("Port details cannot be null", portDetails); + assertEquals("Unexpected number of ports with name " + portNameRMI, 1, portDetails.size()); + port = portDetails.get(0); + Asserts.assertPortAttributes(port, State.QUIESCED); + + + attributes.put(Plugin.TYPE, "MANAGEMENT-JMX"); + attributes.put(Plugin.NAME, "JmxPlugin"); + responseCode = getRestTestHelper().submitRequest("plugin/JmxPlugin", "PUT", attributes); + assertEquals("Unexpected response code", 201, responseCode); + + + // make sure that port is there after broker restart + stopBroker(); + + // We shouldn't need to await the ports to be free, but it seems sometimes an RMI TCP Accept + // thread is seen to close the socket *after* the broker has finished stopping. + new PortHelper().waitUntilPortsAreFree(new HashSet(Arrays.asList(jmxPort, rmiPort))); + + startBroker(); + + portDetails = getRestTestHelper().getJsonAsList("port/" + portNameRMI); + assertNotNull("Port details cannot be null", portDetails); + assertEquals("Unexpected number of ports with name " + portNameRMI, 1, portDetails.size()); + port = portDetails.get(0); + Asserts.assertPortAttributes(port, State.ACTIVE); + + // try to add a second RMI port + portNameRMI = portNameRMI + "2"; + attributes = new HashMap(); + attributes.put(Port.NAME, portNameRMI); + attributes.put(Port.PORT, findFreePort()); + attributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.RMI)); + + responseCode = getRestTestHelper().submitRequest("port/" + portNameRMI, "PUT", attributes); + assertEquals("Adding of a second RMI port should fail", 409, responseCode); + } + + public void testPutCreateAndUpdateAmqpPort() throws Exception + { + String portName = "test-port"; + Map attributes = new HashMap(); + attributes.put(Port.NAME, portName); + attributes.put(Port.PORT, findFreePort()); + attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); + + int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); + assertEquals("Unexpected response code for port creation", 201, responseCode); + + List> portDetails = getRestTestHelper().getJsonAsList("port/" + portName); + assertNotNull("Port details cannot be null", portDetails); + assertEquals("Unexpected number of ports with name " + portName, 1, portDetails.size()); + Map port = portDetails.get(0); + Asserts.assertPortAttributes(port); + + Map authProviderAttributes = new HashMap(); + authProviderAttributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); + authProviderAttributes.put(AuthenticationProvider.NAME, TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER); + + responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER, "PUT", authProviderAttributes); + assertEquals("Unexpected response code for authentication provider creation", 201, responseCode); + + attributes = new HashMap(port); + attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER); + attributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.AMQP_0_9_1)); + + responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); + assertEquals("Unexpected response code for port update", 200, responseCode); + } + + public void testUpdatePortTransportFromTCPToSSLWhenKeystoreIsConfigured() throws Exception + { + String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; + Map attributes = new HashMap(); + attributes.put(Port.NAME, portName); + attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); + attributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); + + int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); + assertEquals("Transport has not been changed to SSL " , 200, responseCode); + + Map port = getRestTestHelper().getJsonAsSingletonList("port/" + portName); + + @SuppressWarnings("unchecked") + Collection transports = (Collection) port.get(Port.TRANSPORTS); + assertEquals("Unexpected auth provider", new HashSet(Arrays.asList(Transport.SSL.name())), + new HashSet(transports)); + + String keyStore = (String) port.get(Port.KEY_STORE); + assertEquals("Unexpected auth provider", TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE, keyStore); + } + + public void testUpdateTransportFromTCPToSSLWithoutKeystoreConfiguredFails() throws Exception + { + String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; + Map attributes = new HashMap(); + attributes.put(Port.NAME, portName); + attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); + + int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); + assertEquals("Creation of SSL port without keystore should fail", 409, responseCode); + } + + public void testUpdateWantNeedClientAuth() throws Exception + { + String portName = TestBrokerConfiguration.ENTRY_NAME_SSL_PORT; + Map attributes = new HashMap(); + attributes.put(Port.NAME, portName); + attributes.put(Port.PORT, DEFAULT_SSL_PORT); + attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); + attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); + attributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); + attributes.put(Port.TRUST_STORES, Collections.singleton(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE)); + + int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); + assertEquals("SSL port was not added", 201, responseCode); + + attributes.put(Port.NEED_CLIENT_AUTH, true); + attributes.put(Port.WANT_CLIENT_AUTH, true); + + responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); + assertEquals("Attributes for need/want client auth are not set", 200, responseCode); + + Map port = getRestTestHelper().getJsonAsSingletonList("port/" + portName); + assertEquals("Unexpected " + Port.NEED_CLIENT_AUTH, true, port.get(Port.NEED_CLIENT_AUTH)); + assertEquals("Unexpected " + Port.WANT_CLIENT_AUTH, true, port.get(Port.WANT_CLIENT_AUTH)); + assertEquals("Unexpected " + Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE, port.get(Port.KEY_STORE)); + @SuppressWarnings("unchecked") + Collection trustStores = (Collection) port.get(Port.TRUST_STORES); + assertEquals("Unexpected auth provider", new HashSet(Arrays.asList(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE)), + new HashSet(trustStores)); + + attributes = new HashMap(); + attributes.put(Port.NAME, portName); + attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.TCP)); + + responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); + assertEquals("Should not be able to change transport to TCP without reseting of attributes for need/want client auth", 409, responseCode); + + attributes = new HashMap(); + attributes.put(Port.NAME, portName); + attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.TCP)); + attributes.put(Port.NEED_CLIENT_AUTH, false); + attributes.put(Port.WANT_CLIENT_AUTH, false); + + responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); + assertEquals("Should be able to change transport to TCP ", 200, responseCode); + + port = getRestTestHelper().getJsonAsSingletonList("port/" + portName); + assertEquals("Unexpected " + Port.NEED_CLIENT_AUTH, false, port.get(Port.NEED_CLIENT_AUTH)); + assertEquals("Unexpected " + Port.WANT_CLIENT_AUTH, false, port.get(Port.WANT_CLIENT_AUTH)); + + @SuppressWarnings("unchecked") + Collection transports = (Collection) port.get(Port.TRANSPORTS); + assertEquals("Unexpected auth provider", new HashSet(Arrays.asList(Transport.TCP.name())), + new HashSet(transports)); + } + + public void testUpdateSettingWantNeedCertificateFailsForNonSSLPort() throws Exception + { + String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; + Map attributes = new HashMap(); + attributes.put(Port.NAME, portName); + attributes.put(Port.NEED_CLIENT_AUTH, true); + int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); + assertEquals("Unexpected response when trying to set 'needClientAuth' on non-SSL port", 409, responseCode); + + attributes = new HashMap(); + attributes.put(Port.NAME, portName); + attributes.put(Port.WANT_CLIENT_AUTH, true); + responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); + assertEquals("Unexpected response when trying to set 'wantClientAuth' on non-SSL port", 409, responseCode); + } + + public void testUpdatePortAuthenticationProvider() throws Exception + { + String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; + Map attributes = new HashMap(); + attributes.put(Port.NAME, portName); + attributes.put(Port.AUTHENTICATION_PROVIDER, "non-existing"); + int responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); + assertEquals("Unexpected response when trying to change auth provider to non-existing one", 409, responseCode); + + attributes = new HashMap(); + attributes.put(Port.NAME, portName); + attributes.put(Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER); + responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); + assertEquals("Unexpected response when trying to change auth provider to existing one", 200, responseCode); + + Map port = getRestTestHelper().getJsonAsSingletonList("port/" + portName); + assertEquals("Unexpected auth provider", ANONYMOUS_AUTHENTICATION_PROVIDER, port.get(Port.AUTHENTICATION_PROVIDER)); + } + + public void testDefaultAmqpPortIsQuiescedWhenInManagementMode() throws Exception + { + // restart Broker in management port + stopBroker(); + startBroker(0, true); + getRestTestHelper().setUsernameAndPassword(BrokerOptions.MANAGEMENT_MODE_USER_NAME, MANAGEMENT_MODE_PASSWORD); + + String ampqPortName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; + Map portData = getRestTestHelper().getJsonAsSingletonList("port/" + URLDecoder.decode(ampqPortName, "UTF-8")); + Asserts.assertPortAttributes(portData, State.QUIESCED); + } + + public void testNewPortErroredIfPortNumberInUse() throws Exception + { + String ampqPortName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; + Map portData = getRestTestHelper().getJsonAsSingletonList("port/" + URLDecoder.decode(ampqPortName, "UTF-8")); + int amqpPort = (Integer)portData.get(Port.PORT); + + ServerSocket socket = new ServerSocket(0); + int occupiedPort = socket.getLocalPort(); + + int deleteResponseCode = getRestTestHelper().submitRequest("port/" + ampqPortName, "DELETE"); + assertEquals("Port deletion should be allowed", 200, deleteResponseCode); + + String newPortName = "reused-port"; + Map attributes = new HashMap(); + attributes.put(Port.NAME, newPortName); + attributes.put(Port.PORT, occupiedPort); // port in use + attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); + + int responseCode = getRestTestHelper().submitRequest("port/" + newPortName, "PUT", attributes); + assertEquals("Unexpected response code for port creation", 201, responseCode); + + portData = getRestTestHelper().getJsonAsSingletonList("port/" + URLDecoder.decode(newPortName, "UTF-8")); + Asserts.assertPortAttributes(portData, State.ERRORED); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PreferencesProviderRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PreferencesProviderRestTest.java new file mode 100644 index 0000000000..6db204b9ca --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PreferencesProviderRestTest.java @@ -0,0 +1,199 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.systest.rest; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.BrokerModel; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.ExternalFileBasedAuthenticationManager; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.PreferencesProvider; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.adapter.FileSystemPreferencesProvider; +import org.apache.qpid.server.security.auth.manager.PlainPasswordDatabaseAuthenticationManager; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.test.utils.TestFileUtils; + +public class PreferencesProviderRestTest extends QpidRestTestCase +{ + private Map _preferencesProviderFiles; + private File _authenticationProviderFile; + + public void setUp() throws Exception + { + _authenticationProviderFile = TestFileUtils.createTempFile(this, ".test.prefs.txt", "test:test"); + _preferencesProviderFiles = new HashMap(); + super.setUp(); + } + + public void tearDown() throws Exception + { + try + { + super.tearDown(); + } + finally + { + if (_authenticationProviderFile != null) + { + _authenticationProviderFile.delete(); + } + for (File file : _preferencesProviderFiles.values()) + { + file.delete(); + } + } + } + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + Map anonymousAuthProviderAttributes = new HashMap(); + anonymousAuthProviderAttributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE); + anonymousAuthProviderAttributes.put(AuthenticationProvider.NAME, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "-2"); + anonymousAuthProviderAttributes.put(ExternalFileBasedAuthenticationManager.PATH, _authenticationProviderFile.getAbsolutePath()); + getBrokerConfiguration().addObjectConfiguration(AuthenticationProvider.class,anonymousAuthProviderAttributes); + } + + public void testCreateAndGetProvider() throws Exception + { + List> providerDetails = getRestTestHelper().getJsonAsList("preferencesprovider"); + assertEquals("Unexpected number of providers", 0, providerDetails.size()); + + createPreferencesProvider(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, "test1"); + createPreferencesProvider(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "-2", "test2"); + + providerDetails = getRestTestHelper().getJsonAsList("preferencesprovider"); + assertEquals("Unexpected number of providers", 2, providerDetails.size()); + + for (Map provider : providerDetails) + { + assertProvider(provider); + } + + Map provider = getRestTestHelper().getJsonAsSingletonList( + "preferencesprovider/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/test1"); + assertProvider(provider); + assertEquals("Unexpected provider name ", "test1", provider.get(PreferencesProvider.NAME)); + + Map provider2 = getRestTestHelper().getJsonAsSingletonList( + "preferencesprovider/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "-2/test2"); + assertProvider(provider); + assertEquals("Unexpected provider name ", "test2", provider2.get(PreferencesProvider.NAME)); + } + + public void testDeleteProvider() throws Exception + { + createPreferencesProvider(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, "test1"); + String providerUrl = "preferencesprovider/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/test1"; + Map provider = getRestTestHelper().getJsonAsSingletonList(providerUrl); + assertProvider(provider); + assertEquals("Unexpected provider name ", "test1", provider.get(PreferencesProvider.NAME)); + + int responseCode = getRestTestHelper().submitRequest(providerUrl, "DELETE"); + assertEquals("Failed to delete preferences provider", 200, responseCode); + + List> providerDetails = getRestTestHelper().getJsonAsList(providerUrl); + assertEquals("Unexpected number of providers", 0, providerDetails.size()); + } + + public void testUpdateProvider() throws Exception + { + createPreferencesProvider(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, "test1"); + String providerUrl = "preferencesprovider/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/test1"; + Map provider = getRestTestHelper().getJsonAsSingletonList(providerUrl); + assertProvider(provider); + assertEquals("Unexpected provider name ", "test1", provider.get(PreferencesProvider.NAME)); + + File file = TestFileUtils.createTempFile(this, ".prefs.json", "{\"admin\":{\"something\": \"somethingValue\"}}"); + _preferencesProviderFiles.put("new-test1", file); + Map newAttributes = new HashMap(); + newAttributes.put(FileSystemPreferencesProvider.PATH, file.getAbsolutePath()); + + int responseCode = getRestTestHelper().submitRequest(providerUrl, "PUT", newAttributes); + assertEquals("Failed to update preferences provider", 200, responseCode); + + List> providerDetails = getRestTestHelper().getJsonAsList(providerUrl); + assertEquals("Unexpected number of providers", 1, providerDetails.size()); + + provider = providerDetails.get(0); + assertProviderCommonAttributes(provider); + String name = (String) provider.get(PreferencesProvider.NAME); + assertEquals("Unexpected name", "test1", name); + assertEquals("Unexpected path for provider " + name, (String) provider.get(FileSystemPreferencesProvider.PATH), + file.getAbsolutePath()); + } + + private void assertProvider(Map provider) + { + assertProviderCommonAttributes(provider); + + String name = (String) provider.get(PreferencesProvider.NAME); + assertNotNull("Name cannot be null", name); + assertEquals("Unexpected path for provider " + name, (String) provider.get(FileSystemPreferencesProvider.PATH), + _preferencesProviderFiles.get(name).getAbsolutePath()); + } + + public void assertProviderCommonAttributes(Map provider) + { + Asserts.assertAttributesPresent(provider, + BrokerModel.getInstance().getTypeRegistry().getAttributeNames( + PreferencesProvider.class), + ConfiguredObject.CREATED_BY, + ConfiguredObject.CREATED_TIME, + ConfiguredObject.LAST_UPDATED_BY, + ConfiguredObject.LAST_UPDATED_TIME, + ConfiguredObject.DESCRIPTION, + ConfiguredObject.CONTEXT, + ConfiguredObject.DESIRED_STATE); + assertEquals("Unexpected value of provider attribute " + PreferencesProvider.STATE, State.ACTIVE.name(), + provider.get(PreferencesProvider.STATE)); + assertEquals("Unexpected value of provider attribute " + PreferencesProvider.LIFETIME_POLICY, + LifetimePolicy.PERMANENT.name(), provider.get(PreferencesProvider.LIFETIME_POLICY)); + assertEquals("Unexpected value of provider attribute " + PreferencesProvider.DURABLE, Boolean.TRUE, + provider.get(PreferencesProvider.DURABLE)); + assertEquals("Unexpected value of provider attribute " + PreferencesProvider.TYPE, + FileSystemPreferencesProvider.PROVIDER_TYPE, provider.get(PreferencesProvider.TYPE)); + } + + private void createPreferencesProvider(String authenticationProvider, String providerName) throws Exception + { + Map attributes = new HashMap(); + attributes.put(PreferencesProvider.NAME, providerName); + attributes.put(PreferencesProvider.TYPE, FileSystemPreferencesProvider.PROVIDER_TYPE); + File file = TestFileUtils.createTempFile(this, ".prefs.json", "{\"admin\":{\"language\": \"en\"}}"); + _preferencesProviderFiles.put(providerName, file); + attributes.put(FileSystemPreferencesProvider.PATH, file.getAbsolutePath()); + + int responseCode = getRestTestHelper().submitRequest( + "preferencesprovider/" + authenticationProvider + "/" + providerName, "PUT", attributes); + assertEquals("Unexpected response code", 201, responseCode); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PreferencesRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PreferencesRestTest.java new file mode 100644 index 0000000000..bd72391522 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/PreferencesRestTest.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.systest.rest; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.qpid.server.model.PreferencesProvider; +import org.apache.qpid.server.model.adapter.FileSystemPreferencesProvider; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.test.utils.TestFileUtils; + +public class PreferencesRestTest extends QpidRestTestCase +{ + private File _preferencesProviderFile; + + public void setUp() throws Exception + { + _preferencesProviderFile = TestFileUtils.createTempFile(this, ".prefs.json", + "{\"webadmin\":{\"language\": \"en\", \"saveTabs\":true}}"); + super.setUp(); + } + + public void tearDown() throws Exception + { + try + { + super.tearDown(); + } + finally + { + if (_preferencesProviderFile != null) + { + _preferencesProviderFile.delete(); + } + } + } + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + + TestBrokerConfiguration brokerConfiguration = getBrokerConfiguration(); + Map attributes = new HashMap(); + attributes.put(PreferencesProvider.NAME, "test"); + attributes.put(PreferencesProvider.TYPE, FileSystemPreferencesProvider.PROVIDER_TYPE); + attributes.put(FileSystemPreferencesProvider.PATH, _preferencesProviderFile.getAbsolutePath()); + brokerConfiguration.addPreferencesProviderConfiguration(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, + attributes); + + } + + public void testGetPreferences() throws Exception + { + Map preferences = getRestTestHelper().getJsonAsMap("/service/preferences"); + assertEquals("Unexpected number of preferences", 2, preferences.size()); + assertEquals("Unexpected language preference", "en", preferences.get("language")); + assertEquals("Unexpected saveTabs preference", true, preferences.get("saveTabs")); + } + + public void testUpdatePreferences() throws Exception + { + Map additionalPreferences = new HashMap(); + additionalPreferences.put("timezone", "Europe/London"); + additionalPreferences.put("test", 1); + + int status = getRestTestHelper().submitRequest("/service/preferences", "POST", additionalPreferences); + assertEquals("Unexpected response code", 200, status); + + Map preferences = getRestTestHelper().getJsonAsMap("/service/preferences"); + assertEquals("Unexpected number of preferences", 4, preferences.size()); + assertEquals("Unexpected language preference", "en", preferences.get("language")); + assertEquals("Unexpected saveTabs preference", true, preferences.get("saveTabs")); + assertEquals("Unexpected timezone preference", "Europe/London", preferences.get("timezone")); + assertEquals("Unexpected test preference", 1, preferences.get("test")); + } + + public void testReplacePreferences() throws Exception + { + Map additionalPreferences = new HashMap(); + additionalPreferences.put("timezone", "Europe/London"); + additionalPreferences.put("test", 1); + + int status = getRestTestHelper().submitRequest("/service/preferences", "PUT", additionalPreferences); + assertEquals("Unexpected response code", 200, status); + + Map preferences = getRestTestHelper().getJsonAsMap("/service/preferences"); + assertEquals("Unexpected number of preferences", 2, preferences.size()); + assertEquals("Unexpected timezone preference", "Europe/London", preferences.get("timezone")); + assertEquals("Unexpected test preference", 1, preferences.get("test")); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/QueueRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/QueueRestTest.java new file mode 100644 index 0000000000..baebc9a28e --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/QueueRestTest.java @@ -0,0 +1,262 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest; + +import java.io.IOException; +import java.net.URLDecoder; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +import org.apache.qpid.server.model.Binding; +import org.apache.qpid.server.model.BrokerModel; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.Consumer; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Queue; + +public class QueueRestTest extends QpidRestTestCase +{ + private static final String QUEUE_ATTRIBUTE_CONSUMERS = "consumers"; + private static final String QUEUE_ATTRIBUTE_BINDINGS = "bindings"; + + /** + * Message number to publish into queue + */ + private static final int MESSAGE_NUMBER = 2; + private static final int MESSAGE_PAYLOAD_SIZE = 6; + private static final int ENQUEUED_MESSAGES = 1; + private static final int DEQUEUED_MESSAGES = 1; + private static final int ENQUEUED_BYTES = MESSAGE_PAYLOAD_SIZE; + private static final int DEQUEUED_BYTES = MESSAGE_PAYLOAD_SIZE; + + private Connection _connection; + + public void setUp() throws Exception + { + super.setUp(); + _connection = getConnection(); + Session session = _connection.createSession(true, Session.SESSION_TRANSACTED); + String queueName = getTestQueueName(); + Destination queue = session.createQueue(queueName); + MessageConsumer consumer = session.createConsumer(queue); + MessageProducer producer = session.createProducer(queue); + + for (int i = 0; i < MESSAGE_NUMBER; i++) + { + producer.send(session.createTextMessage("Test-" + i)); + } + session.commit(); + _connection.start(); + Message m = consumer.receive(1000l); + assertNotNull("Message is not received", m); + session.commit(); + } + + public void testGetVirtualHostQueues() throws Exception + { + String queueName = getTestQueueName(); + List> queues = getRestTestHelper().getJsonAsList("queue/test"); + assertEquals("Unexpected number of queues", 1, queues.size()); + String[] expectedQueues = new String[]{queueName}; + + for (String name : expectedQueues) + { + Map queueDetails = getRestTestHelper().find(Queue.NAME, name, queues); + Asserts.assertQueue(name, "standard", queueDetails); + + @SuppressWarnings("unchecked") + List> bindings = (List>) queueDetails.get(QUEUE_ATTRIBUTE_BINDINGS); + assertNotNull("Queue bindings are not found", bindings); + assertEquals("Unexpected number of bindings", 1, bindings.size()); + + Map directExchangeBinding = getRestTestHelper().find(Binding.EXCHANGE, "amq.direct", bindings); + Asserts.assertBinding(name, "amq.direct", directExchangeBinding); + } + } + + public void testGetByName() throws Exception + { + String queueName = getTestQueueName(); + Map queueDetails = getRestTestHelper().getJsonAsSingletonList("queue/test/test/" + queueName); + Asserts.assertQueue(queueName, "standard", queueDetails); + assertStatistics(queueDetails); + + @SuppressWarnings("unchecked") + List> bindings = (List>) queueDetails.get(QUEUE_ATTRIBUTE_BINDINGS); + assertNotNull("Queue bindings are not found", bindings); + assertEquals("Unexpected number of bindings", 1, bindings.size()); + + Map directExchangeBinding = getRestTestHelper().find(Binding.EXCHANGE, "amq.direct", bindings); + Asserts.assertBinding(queueName, "amq.direct", directExchangeBinding); + + @SuppressWarnings("unchecked") + List> consumers = (List>) queueDetails.get(QUEUE_ATTRIBUTE_CONSUMERS); + assertNotNull("Queue consumers are not found", consumers); + assertEquals("Unexpected number of consumers", 1, consumers.size()); + assertConsumer(consumers.get(0)); + } + + public void testUpdateQueue() throws Exception + { + String queueName = getTestName(); + + Map attributes = new HashMap(); + attributes.put(Queue.NAME, queueName); + + String queueUrl = "queue/test/test/" + queueName; + int responseCode = getRestTestHelper().submitRequest(queueUrl, "PUT", attributes); + assertEquals("Queue was not created", 201, responseCode); + + Map queueDetails = getRestTestHelper().getJsonAsSingletonList(queueUrl); + Asserts.assertQueue(queueName, "standard", queueDetails); + + attributes = new HashMap(); + attributes.put(Queue.NAME, queueName); + attributes.put(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 100000); + attributes.put(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 80000); + attributes.put(Queue.ALERT_REPEAT_GAP, 10000); + attributes.put(Queue.ALERT_THRESHOLD_MESSAGE_AGE, 20000); + attributes.put(Queue.ALERT_THRESHOLD_MESSAGE_SIZE, 30000); + attributes.put(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_BYTES, 40000); + attributes.put(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, 50000); + attributes.put(Queue.MAXIMUM_DELIVERY_ATTEMPTS, 10); + + responseCode = getRestTestHelper().submitRequest(queueUrl, "PUT", attributes); + assertEquals("Setting of queue attributes should be allowed", 200, responseCode); + + Map queueData = getRestTestHelper().getJsonAsSingletonList(queueUrl); + assertEquals("Unexpected " + Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 100000, queueData.get(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES) ); + assertEquals("Unexpected " + Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 80000, queueData.get(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES) ); + assertEquals("Unexpected " + Queue.ALERT_REPEAT_GAP, 10000, queueData.get(Queue.ALERT_REPEAT_GAP) ); + assertEquals("Unexpected " + Queue.ALERT_THRESHOLD_MESSAGE_AGE, 20000, queueData.get(Queue.ALERT_THRESHOLD_MESSAGE_AGE) ); + assertEquals("Unexpected " + Queue.ALERT_THRESHOLD_MESSAGE_SIZE, 30000, queueData.get(Queue.ALERT_THRESHOLD_MESSAGE_SIZE) ); + assertEquals("Unexpected " + Queue.ALERT_THRESHOLD_QUEUE_DEPTH_BYTES, 40000, queueData.get(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_BYTES) ); + assertEquals("Unexpected " + Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, 50000, queueData.get(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES) ); + } + + public void testPutCreateBinding() throws Exception + { + String queueName = getTestQueueName(); + String bindingName = queueName + 2; + String[] exchanges = { "amq.direct", "amq.fanout", "amq.topic", "amq.match" }; + + for (int i = 0; i < exchanges.length; i++) + { + createBinding(bindingName, exchanges[i], queueName); + } + + Map queueDetails = getRestTestHelper().getJsonAsSingletonList("queue/test/test/" + queueName); + Asserts.assertQueue(queueName, "standard", queueDetails); + + @SuppressWarnings("unchecked") + List> bindings = (List>) queueDetails.get(QUEUE_ATTRIBUTE_BINDINGS); + assertNotNull("Queue bindings are not found", bindings); + assertEquals("Unexpected number of bindings", exchanges.length + 1, bindings.size()); + + Map searchAttributes = new HashMap(); + searchAttributes.put(Binding.NAME, bindingName); + + for (int i = 0; i < exchanges.length; i++) + { + searchAttributes.put(Binding.EXCHANGE, exchanges[i]); + Map binding = getRestTestHelper().find(searchAttributes, bindings); + Asserts.assertBinding(bindingName, queueName, exchanges[i], binding); + } + } + + private void createBinding(String bindingName, String exchangeName, String queueName) throws IOException + { + Map bindingData = new HashMap(); + bindingData.put(Binding.NAME, bindingName); + bindingData.put(Binding.EXCHANGE, exchangeName); + bindingData.put(Binding.QUEUE, queueName); + + String url = "binding/test/test/" + URLDecoder.decode(exchangeName, "UTF-8") + "/" + queueName + "/" + bindingName; + int responseCode = getRestTestHelper().submitRequest(url, "PUT", bindingData); + assertEquals("Unexpected response code", 201, responseCode); + } + + private void assertConsumer(Map consumer) + { + assertNotNull("Consumer map should not be null", consumer); + Asserts.assertAttributesPresent(consumer, + BrokerModel.getInstance().getTypeRegistry().getAttributeNames(Consumer.class), Consumer.STATE, + Consumer.SETTLEMENT_MODE, Consumer.EXCLUSIVE, Consumer.SELECTOR, + Consumer.NO_LOCAL, + ConfiguredObject.TYPE, + ConfiguredObject.CREATED_BY, + ConfiguredObject.CREATED_TIME, + ConfiguredObject.LAST_UPDATED_BY, + ConfiguredObject.LAST_UPDATED_TIME, + ConfiguredObject.DESCRIPTION, + ConfiguredObject.CONTEXT, + ConfiguredObject.DESIRED_STATE); + + assertEquals("Unexpected binding attribute " + Consumer.NAME, "1", consumer.get(Consumer.NAME)); + assertEquals("Unexpected binding attribute " + Consumer.DURABLE, Boolean.FALSE, consumer.get(Consumer.DURABLE)); + assertEquals("Unexpected binding attribute " + Consumer.LIFETIME_POLICY, LifetimePolicy.DELETE_ON_SESSION_END.name(), + consumer.get(Consumer.LIFETIME_POLICY)); + assertEquals("Unexpected binding attribute " + Consumer.DISTRIBUTION_MODE, "MOVE", + consumer.get(Consumer.DISTRIBUTION_MODE)); + + @SuppressWarnings("unchecked") + Map statistics = (Map) consumer.get(Asserts.STATISTICS_ATTRIBUTE); + assertNotNull("Consumer statistics is not present", statistics); + Asserts.assertAttributesPresent(statistics, "bytesOut", "messagesOut", "unacknowledgedBytes", "unacknowledgedMessages"); + } + + private void assertStatistics(Map queueDetails) + { + @SuppressWarnings("unchecked") + Map statistics = (Map) queueDetails.get(Asserts.STATISTICS_ATTRIBUTE); + assertEquals("Unexpected queue statistics attribute " + "persistentDequeuedMessages", DEQUEUED_MESSAGES, + statistics.get("persistentDequeuedMessages")); + assertEquals("Unexpected queue statistics attribute " + "queueDepthMessages", ENQUEUED_MESSAGES, + statistics.get("queueDepthMessages")); + assertEquals("Unexpected queue statistics attribute " + "consumerCount", 1, + statistics.get("consumerCount")); + assertEquals("Unexpected queue statistics attribute " + "consumerCountWithCredit", 1, + statistics.get("consumerCountWithCredit")); + assertEquals("Unexpected queue statistics attribute " + "bindingCount", 1, statistics.get("bindingCount")); + assertEquals("Unexpected queue statistics attribute " + "persistentDequeuedMessages", DEQUEUED_MESSAGES, + statistics.get("persistentDequeuedMessages")); + assertEquals("Unexpected queue statistics attribute " + "totalDequeuedMessages", DEQUEUED_MESSAGES, + statistics.get("totalDequeuedMessages")); + assertEquals("Unexpected queue statistics attribute " + "totalDequeuedBytes", DEQUEUED_BYTES, + statistics.get("totalDequeuedBytes")); + assertEquals("Unexpected queue statistics attribute " + "persistentDequeuedBytes", DEQUEUED_BYTES, + statistics.get("totalDequeuedBytes")); + assertEquals("Unexpected queue statistics attribute " + "persistentEnqueuedBytes", ENQUEUED_BYTES + + DEQUEUED_BYTES, statistics.get("persistentEnqueuedBytes")); + assertEquals("Unexpected queue statistics attribute " + "totalEnqueuedBytes", ENQUEUED_BYTES + DEQUEUED_BYTES, + statistics.get("totalEnqueuedBytes")); + assertEquals("Unexpected queue statistics attribute " + "queueDepthBytes", ENQUEUED_BYTES, + statistics.get("queueDepthBytes")); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/SaslRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/SaslRestTest.java new file mode 100644 index 0000000000..547b7b1b00 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/SaslRestTest.java @@ -0,0 +1,384 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.systest.rest; + +import static org.apache.qpid.server.security.auth.sasl.SaslUtil.generateCramMD5ClientResponse; +import static org.apache.qpid.server.security.auth.sasl.SaslUtil.generateCramMD5HexClientResponse; +import static org.apache.qpid.server.security.auth.sasl.SaslUtil.generatePlainClientResponse; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.codec.binary.Base64; +import org.codehaus.jackson.JsonParseException; +import org.codehaus.jackson.map.JsonMappingException; + +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.security.auth.manager.Base64MD5PasswordDatabaseAuthenticationManager; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.tools.security.Passwd; + +public class SaslRestTest extends QpidRestTestCase +{ + @Override + public void startBroker() + { + // prevent broker from starting in setUp + } + + public void startBrokerNow() throws Exception + { + super.startBroker(); + + getRestTestHelper().setUsernameAndPassword(null,null); + } + + public void testGetMechanismsWithBrokerPlainPasswordPrincipalDatabase() throws Exception + { + startBrokerNow(); + + Map saslData = getRestTestHelper().getJsonAsMap("/service/sasl"); + assertNotNull("mechanisms attribute is not found", saslData.get("mechanisms")); + + @SuppressWarnings("unchecked") + List mechanisms = (List) saslData.get("mechanisms"); + String[] expectedMechanisms = { "CRAM-MD5" }; + for (String mechanism : expectedMechanisms) + { + assertTrue("Mechanism " + mechanism + " is not found", mechanisms.contains(mechanism)); + } + assertNull("Unexpected user was returned: " + saslData.get("user"), saslData.get("user")); + } + + public void testGetMechanismsWithBrokerBase64MD5FilePrincipalDatabase() throws Exception + { + configureBase64MD5FilePrincipalDatabase(); + startBrokerNow(); + + Map saslData = getRestTestHelper().getJsonAsMap("/service/sasl"); + assertNotNull("mechanisms attribute is not found", saslData.get("mechanisms")); + + @SuppressWarnings("unchecked") + List mechanisms = (List) saslData.get("mechanisms"); + String[] expectedMechanisms = { "CRAM-MD5-HEX", "CRAM-MD5-HASHED" }; + for (String mechanism : expectedMechanisms) + { + assertTrue("Mechanism " + mechanism + " is not found", mechanisms.contains(mechanism)); + } + + assertNull("Unexpected user was returned: " + saslData.get("user"), saslData.get("user")); + } + + public void testPlainSaslAuthenticationForValidCredentials() throws Exception + { + startBrokerNow(); + + byte[] responseBytes = generatePlainClientResponse("admin", "admin"); + String responseData = Base64.encodeBase64String(responseBytes); + String parameters= "mechanism=PLAIN&response=" + responseData; + + HttpURLConnection connection = getRestTestHelper().openManagementConnection("/service/sasl", "POST"); + OutputStream os = connection.getOutputStream(); + os.write(parameters.getBytes()); + os.flush(); + + int code = getRestTestHelper().submitRequest("/service/sasl", "POST", parameters.getBytes()); + assertEquals("Unexpected response code", 200, code); + + List cookies = connection.getHeaderFields().get("Set-Cookie"); + + // request authenticated user details + connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET"); + applyCookiesToConnection(cookies, connection); + Map response2 = getRestTestHelper().readJsonResponseAsMap(connection); + assertEquals("Unexpected user", "admin", response2.get("user")); + } + + public void testPlainSaslAuthenticationForIncorrectPassword() throws Exception + { + startBrokerNow(); + + byte[] responseBytes = generatePlainClientResponse("admin", "incorrect"); + String responseData = Base64.encodeBase64String(responseBytes); + String parameters= "mechanism=PLAIN&response=" + responseData; + + HttpURLConnection connection = getRestTestHelper().openManagementConnection("/service/sasl", "POST"); + OutputStream os = connection.getOutputStream(); + os.write(parameters.getBytes()); + os.flush(); + + int code = connection.getResponseCode(); + assertEquals("Unexpected response code", 401, code); + + List cookies = connection.getHeaderFields().get("Set-Cookie"); + + // request authenticated user details + connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET"); + applyCookiesToConnection(cookies, connection); + Map response2 = getRestTestHelper().readJsonResponseAsMap(connection); + assertNull("Unexpected user", response2.get("user")); + } + + public void testPlainSaslAuthenticationForNonExistingUser() throws Exception + { + startBrokerNow(); + + byte[] responseBytes = generatePlainClientResponse("nonexisting", "admin"); + String responseData = Base64.encodeBase64String(responseBytes); + String parameters= "mechanism=PLAIN&response=" + responseData; + + HttpURLConnection connection = getRestTestHelper().openManagementConnection("/service/sasl", "POST"); + OutputStream os = connection.getOutputStream(); + os.write(parameters.getBytes()); + os.flush(); + + int code = connection.getResponseCode(); + assertEquals("Unexpected response code", 401, code); + + List cookies = connection.getHeaderFields().get("Set-Cookie"); + + // request authenticated user details + connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET"); + applyCookiesToConnection(cookies, connection); + Map response2 = getRestTestHelper().readJsonResponseAsMap(connection); + assertNull("Unexpected user", response2.get("user")); + } + + public void testCramMD5SaslAuthenticationForValidCredentials() throws Exception + { + startBrokerNow(); + + // request the challenge for CRAM-MD5 + HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5"); + List cookies = connection.getHeaderFields().get("Set-Cookie"); + + // authenticate user with correct credentials + int code = authenticateUser(connection, "admin", "admin", "CRAM-MD5"); + assertEquals("Unexpected response code", 200, code); + + // request authenticated user details + connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET"); + applyCookiesToConnection(cookies, connection); + Map response2 = getRestTestHelper().readJsonResponseAsMap(connection); + assertEquals("Unexpected user", "admin", response2.get("user")); + } + + public void testCramMD5SaslAuthenticationForIncorrectPassword() throws Exception + { + startBrokerNow(); + + // request the challenge for CRAM-MD5 + HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5"); + List cookies = connection.getHeaderFields().get("Set-Cookie"); + + // authenticate user with correct credentials + int code = authenticateUser(connection, "admin", "incorrect", "CRAM-MD5"); + assertEquals("Unexpected response code", 401, code); + + // request authenticated user details + connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET"); + applyCookiesToConnection(cookies, connection); + Map response2 = getRestTestHelper().readJsonResponseAsMap(connection); + assertNull("Unexpected user", response2.get("user")); + } + + public void testCramMD5SaslAuthenticationForNonExistingUser() throws Exception + { + startBrokerNow(); + + // request the challenge for CRAM-MD5 + HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5"); + List cookies = connection.getHeaderFields().get("Set-Cookie"); + + // authenticate user with correct credentials + int code = authenticateUser(connection, "nonexisting", "admin", "CRAM-MD5"); + assertEquals("Unexpected response code", 401, code); + + // request authenticated user details + connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET"); + applyCookiesToConnection(cookies, connection); + Map response2 = getRestTestHelper().readJsonResponseAsMap(connection); + assertNull("Unexpected user", response2.get("user")); + } + + public void testCramMD5HexSaslAuthenticationForValidCredentials() throws Exception + { + configureBase64MD5FilePrincipalDatabase(); + startBrokerNow(); + + // request the challenge for CRAM-MD5-HEX + HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5-HEX"); + List cookies = connection.getHeaderFields().get("Set-Cookie"); + + // authenticate user with correct credentials + int code = authenticateUser(connection, "admin", "admin", "CRAM-MD5-HEX"); + assertEquals("Unexpected response code", 200, code); + + // request authenticated user details + connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET"); + applyCookiesToConnection(cookies, connection); + Map response2 = getRestTestHelper().readJsonResponseAsMap(connection); + assertEquals("Unexpected user", "admin", response2.get("user")); + } + + public void testCramMD5HexSaslAuthenticationForIncorrectPassword() throws Exception + { + configureBase64MD5FilePrincipalDatabase(); + startBrokerNow(); + + HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5-HEX"); + List cookies = connection.getHeaderFields().get("Set-Cookie"); + + // try to authenticate user with incorrect passowrd + int code = authenticateUser(connection, "admin", "incorrect", "CRAM-MD5-HEX"); + assertEquals("Unexpected response code", 401, code); + + // request authenticated user details + connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET"); + applyCookiesToConnection(cookies, connection); + Map response2 = getRestTestHelper().readJsonResponseAsMap(connection); + assertNull("Unexpected user", response2.get("user")); + } + + public void testCramMD5HexSaslAuthenticationForNonExistingUser() throws Exception + { + configureBase64MD5FilePrincipalDatabase(); + startBrokerNow(); + + HttpURLConnection connection = requestSasServerChallenge("CRAM-MD5-HEX"); + List cookies = connection.getHeaderFields().get("Set-Cookie"); + + // try to authenticate non-existing user + int code = authenticateUser(connection, "nonexisting", "admin", "CRAM-MD5-HEX"); + assertEquals("Unexpected response code", 401, code); + + // request authenticated user details + connection = getRestTestHelper().openManagementConnection("/service/sasl", "GET"); + applyCookiesToConnection(cookies, connection); + Map response2 = getRestTestHelper().readJsonResponseAsMap(connection); + assertNull("Unexpected user", response2.get("user")); + } + + private HttpURLConnection requestSasServerChallenge(String mechanism) throws IOException + { + HttpURLConnection connection = getRestTestHelper().openManagementConnection("/service/sasl", "POST"); + OutputStream os = connection.getOutputStream(); + os.write(("mechanism=" + mechanism).getBytes()); + os.flush(); + return connection; + } + + public int authenticateUser(HttpURLConnection requestChallengeConnection, String userName, String userPassword, String mechanism) + throws IOException, JsonParseException, JsonMappingException, Exception + { + // get the response + Map response = getRestTestHelper().readJsonResponseAsMap(requestChallengeConnection); + String challenge = (String) response.get("challenge"); + assertNotNull("Challenge is not found", challenge); + + // preserve cookies to have the same server session + List cookies = requestChallengeConnection.getHeaderFields().get("Set-Cookie"); + + // generate the authentication response for the challenge received + byte[] challengeBytes = Base64.decodeBase64(challenge); + byte[] responseBytes = generateClientResponse(mechanism, userName, userPassword, challengeBytes); + String responseData = Base64.encodeBase64String(responseBytes); + String requestParameters = ("id=" + response.get("id") + "&response=" + responseData); + + // re-open connection + HttpURLConnection authenticateConnection = getRestTestHelper().openManagementConnection("/service/sasl", "POST"); + + // set cookies to use the same server session + applyCookiesToConnection(cookies, authenticateConnection); + OutputStream os = authenticateConnection.getOutputStream(); + os.write(requestParameters.getBytes()); + os.flush(); + return authenticateConnection.getResponseCode(); + } + + private byte[] generateClientResponse(String mechanism, String userName, String userPassword, byte[] challengeBytes) throws Exception + { + byte[] responseBytes = null; + if ("CRAM-MD5-HEX".equalsIgnoreCase(mechanism)) + { + responseBytes = generateCramMD5HexClientResponse(userName, userPassword, challengeBytes); + } + else if ("CRAM-MD5".equalsIgnoreCase(mechanism)) + { + responseBytes = generateCramMD5ClientResponse(userName, userPassword, challengeBytes); + } + else + { + throw new RuntimeException("Not implemented test mechanism " + mechanism); + } + return responseBytes; + } + + private void applyCookiesToConnection(List cookies, HttpURLConnection connection) + { + for (String cookie : cookies) + { + connection.addRequestProperty("Cookie", cookie.split(";", 2)[0]); + } + } + + private void configureBase64MD5FilePrincipalDatabase() throws IOException + { + // generate user password entry + String passwordFileEntry; + try + { + passwordFileEntry = new Passwd().getOutput("admin", "admin"); + } + catch (NoSuchAlgorithmException e) + { + throw new RuntimeException(e); + } + + // store the entry in the file + File passwordFile = File.createTempFile("passwd", "pwd"); + passwordFile.deleteOnExit(); + + FileWriter writer = null; + try + { + writer = new FileWriter(passwordFile); + writer.write(passwordFileEntry); + } + finally + { + writer.close(); + } + + // configure broker to use Base64MD5PasswordFilePrincipalDatabase + Map newAttributes = new HashMap(); + newAttributes.put("path", passwordFile.getAbsolutePath()); + newAttributes.put(AuthenticationProvider.TYPE, Base64MD5PasswordDatabaseAuthenticationManager.PROVIDER_TYPE); + getBrokerConfiguration().setObjectAttributes(AuthenticationProvider.class,TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, newAttributes); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/StructureRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/StructureRestTest.java new file mode 100644 index 0000000000..daefc05e2a --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/StructureRestTest.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.systest.rest; + +import java.util.List; +import java.util.Map; + +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class StructureRestTest extends QpidRestTestCase +{ + + @Override + public void setUp() throws Exception + { + super.setUp(); + getRestTestHelper().createTestQueues(); + } + + public void testGet() throws Exception + { + Map structure = getRestTestHelper().getJsonAsMap("/service/structure"); + assertNotNull("Structure data cannot be null", structure); + assertNode(structure, "Broker"); + + @SuppressWarnings("unchecked") + List> virtualhostnodes = (List>) structure.get("virtualhostnodes"); + assertEquals("Unexpected number of virtual hosts", 3, virtualhostnodes.size()); + + @SuppressWarnings("unchecked") + List> ports = (List>) structure.get("ports"); + assertEquals("Unexpected number of ports", 2, ports.size()); + + @SuppressWarnings("unchecked") + List> providers = (List>) structure.get("authenticationproviders"); + assertEquals("Unexpected number of authentication providers", 2, providers.size()); + + for (String nodeName : EXPECTED_VIRTUALHOSTS) + { + Map node = getRestTestHelper().find("name", nodeName, virtualhostnodes); + assertNotNull("Node " + nodeName + " is not found ", node); + assertNode(node, nodeName); + } + + String hostName = "test"; + Map node = getRestTestHelper().find("name", hostName, virtualhostnodes); + + @SuppressWarnings("unchecked") + List> virtualhosts = (List>) node.get("virtualhosts"); + + Map host = getRestTestHelper().find("name", hostName, virtualhosts); + @SuppressWarnings("unchecked") + List> queues = (List>) host.get("queues"); + assertNotNull("Host " + hostName + " queues are not found ", queues); + for (String queueName : RestTestHelper.EXPECTED_QUEUES) + { + Map queue = getRestTestHelper().find("name", queueName, queues); + assertNotNull(hostName + " queue " + queueName + " is not found ", queue); + assertNode(queue, queueName); + + @SuppressWarnings("unchecked") + List> bindings = (List>) queue.get("bindings"); + assertNotNull(hostName + " queue " + queueName + " bindings are not found ", queues); + for (Map binding : bindings) + { + assertNode(binding, queueName); + } + } + + @SuppressWarnings("unchecked") + List> exchanges = (List>) host.get("exchanges"); + assertNotNull("Host " + hostName + " exchanges are not found ", exchanges); + for (String exchangeName : EXPECTED_EXCHANGES) + { + Map exchange = getRestTestHelper().find("name", exchangeName, exchanges); + assertNotNull("Exchange " + exchangeName + " is not found ", exchange); + assertNode(exchange, exchangeName); + if (ExchangeDefaults.DIRECT_EXCHANGE_NAME.equalsIgnoreCase(exchangeName) || + ExchangeDefaults.DEFAULT_EXCHANGE_NAME.equalsIgnoreCase(exchangeName)) + { + @SuppressWarnings("unchecked") + List> bindings = (List>) exchange.get("bindings"); + assertNotNull(hostName + " exchange " + exchangeName + " bindings are not found ", bindings); + for (String queueName : RestTestHelper.EXPECTED_QUEUES) + { + Map binding = getRestTestHelper().find("name", queueName, bindings); + assertNotNull(hostName + " exchange " + exchangeName + " binding " + queueName + " is not found", binding); + assertNode(binding, queueName); + } + } + } + + String httpPortName = TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT; + Map portData = getRestTestHelper().find(Port.NAME, httpPortName, ports); + assertNotNull("Http Port " + httpPortName + " is not found", portData); + assertNode(portData, httpPortName); + + String amqpPortName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; + Map amqpPortData = getRestTestHelper().find(Port.NAME, amqpPortName, ports); + assertNotNull("Amqp port " + amqpPortName + " is not found", amqpPortData); + assertNode(amqpPortData, amqpPortName); + } + + private void assertNode(Map node, String name) + { + assertEquals("Unexpected name", name, node.get("name")); + assertNotNull("Unexpected id", node.get("id")); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/TrustStoreRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/TrustStoreRestTest.java new file mode 100644 index 0000000000..5d2e9de3fa --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/TrustStoreRestTest.java @@ -0,0 +1,263 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.codehaus.jackson.JsonGenerationException; +import org.codehaus.jackson.JsonParseException; +import org.codehaus.jackson.map.JsonMappingException; + +import org.apache.qpid.server.model.AbstractConfiguredObject; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Transport; +import org.apache.qpid.server.model.TrustStore; +import org.apache.qpid.server.security.FileTrustStore; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.test.utils.TestSSLConstants; + +public class TrustStoreRestTest extends QpidRestTestCase +{ + @Override + public void setUp() throws Exception + { + // not calling super.setUp() to avoid broker start-up until + // after any necessary configuration + } + + public void testGet() throws Exception + { + super.setUp(); + + //verify existence of the default trust store used by the systests + List> trustStores = assertNumberOfTrustStores(1); + + Map truststore = trustStores.get(0); + assertTrustStoreAttributes(truststore, TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE, + System.getProperty(QPID_HOME) + "/../" + TestSSLConstants.BROKER_TRUSTSTORE, false); + } + + public void testCreate() throws Exception + { + super.setUp(); + + String name = getTestName(); + + assertNumberOfTrustStores(1); + createTrustStore(name, true); + assertNumberOfTrustStores(2); + + List> trustStores = getRestTestHelper().getJsonAsList("truststore/" + name); + assertNotNull("details cannot be null", trustStores); + + assertTrustStoreAttributes(trustStores.get(0), name, TestSSLConstants.TRUSTSTORE, true); + } + + public void testDelete() throws Exception + { + super.setUp(); + + String name = getTestName(); + + assertNumberOfTrustStores(1); + createTrustStore(name, false); + assertNumberOfTrustStores(2); + + int responseCode = getRestTestHelper().submitRequest("truststore/" + name , "DELETE"); + assertEquals("Unexpected response code for provider deletion", 200, responseCode); + + List> trustStore = getRestTestHelper().getJsonAsList("truststore/" + name); + assertNotNull("details should not be null", trustStore); + assertTrue("details should be empty as the truststore no longer exists", trustStore.isEmpty()); + + //check only the default systests trust store remains + List> trustStores = assertNumberOfTrustStores(1); + Map truststore = trustStores.get(0); + assertTrustStoreAttributes(truststore, TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE, + System.getProperty(QPID_HOME) + "/../" + TestSSLConstants.BROKER_TRUSTSTORE, false); + } + + public void testDeleteFailsWhenTrustStoreInUse() throws Exception + { + String name = "testDeleteFailsWhenTrustStoreInUse"; + + //add a new trust store config to use + Map sslTrustStoreAttributes = new HashMap(); + sslTrustStoreAttributes.put(TrustStore.NAME, name); + sslTrustStoreAttributes.put(FileTrustStore.PATH, TestSSLConstants.TRUSTSTORE); + sslTrustStoreAttributes.put(FileTrustStore.PASSWORD, TestSSLConstants.TRUSTSTORE_PASSWORD); + getBrokerConfiguration().addObjectConfiguration(TrustStore.class,sslTrustStoreAttributes); + + //add the SSL port using it + Map sslPortAttributes = new HashMap(); + sslPortAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); + sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT); + sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT); + sslPortAttributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); + sslPortAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE); + sslPortAttributes.put(Port.TRUST_STORES, Collections.singleton(name)); + getBrokerConfiguration().addObjectConfiguration(Port.class, sslPortAttributes); + + super.setUp(); + + //verify the truststore is there + assertNumberOfTrustStores(2); + + List> trustStore = getRestTestHelper().getJsonAsList("truststore/" + name); + assertNotNull("details should not be null", trustStore); + assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false); + + //try to delete it, which should fail as it is in use + int responseCode = getRestTestHelper().submitRequest("truststore/" + name , "DELETE"); + assertEquals("Unexpected response code for provider deletion", 409, responseCode); + + //check its still there + assertNumberOfTrustStores(2); + trustStore = getRestTestHelper().getJsonAsList("truststore/" + name); + assertNotNull("details should not be null", trustStore); + assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false); + } + + public void testUpdateWithGoodPathSucceeds() throws Exception + { + super.setUp(); + + String name = getTestName(); + + assertNumberOfTrustStores(1); + createTrustStore(name, false); + assertNumberOfTrustStores(2); + + Map attributes = new HashMap(); + attributes.put(TrustStore.NAME, name); + attributes.put(FileTrustStore.PATH, TestSSLConstants.TRUSTSTORE); + + int responseCode = getRestTestHelper().submitRequest("truststore/" + name , "PUT", attributes); + assertEquals("Unexpected response code for truststore update", 200, responseCode); + + List> trustStore = getRestTestHelper().getJsonAsList("truststore/" + name); + assertNotNull("details should not be null", trustStore); + + assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false); + } + + public void testUpdateWithNonExistentPathFails() throws Exception + { + super.setUp(); + + String name = getTestName(); + + assertNumberOfTrustStores(1); + createTrustStore(name, false); + assertNumberOfTrustStores(2); + + Map attributes = new HashMap(); + attributes.put(TrustStore.NAME, name); + attributes.put(FileTrustStore.PATH, "does.not.exist"); + + int responseCode = getRestTestHelper().submitRequest("truststore/" + name , "PUT", attributes); + assertEquals("Unexpected response code for trust store update", 409, responseCode); + + List> trustStore = getRestTestHelper().getJsonAsList("truststore/" + name); + assertNotNull("details should not be null", trustStore); + + //verify the details remain unchanged + assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false); + } + + public void testUpdatePeersOnly() throws Exception + { + super.setUp(); + + String name = getTestName(); + + assertNumberOfTrustStores(1); + createTrustStore(name, false); + assertNumberOfTrustStores(2); + + //update the peersOnly attribute from false to true + Map attributes = new HashMap(); + attributes.put(TrustStore.NAME, name); + attributes.put(FileTrustStore.PEERS_ONLY, true); + + int responseCode = getRestTestHelper().submitRequest("truststore/" + name , "PUT", attributes); + assertEquals("Unexpected response code for trust store update", 200, responseCode); + + List> trustStore = getRestTestHelper().getJsonAsList("truststore/" + name); + assertNotNull("details should not be null", trustStore); + + assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, true); + + //Update peersOnly to clear it (i.e go from from true to null, which will default to false) + attributes = new HashMap(); + attributes.put(TrustStore.NAME, name); + attributes.put(FileTrustStore.PEERS_ONLY, null); + + responseCode = getRestTestHelper().submitRequest("truststore/" + name , "PUT", attributes); + assertEquals("Unexpected response code for trust store update", 200, responseCode); + + trustStore = getRestTestHelper().getJsonAsList("truststore/" + name); + assertNotNull("details should not be null", trustStore); + + assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false); + } + + private List> assertNumberOfTrustStores(int numberOfTrustStores) throws IOException, + JsonParseException, JsonMappingException + { + List> trustStores = getRestTestHelper().getJsonAsList("truststore"); + assertNotNull("trust stores should not be null", trustStores); + assertEquals("Unexpected number of trust stores", numberOfTrustStores, trustStores.size()); + + return trustStores; + } + + private void createTrustStore(String name, boolean peersOnly) throws IOException, JsonGenerationException, JsonMappingException + { + Map trustStoreAttributes = new HashMap(); + trustStoreAttributes.put(TrustStore.NAME, name); + //deliberately using the client trust store to differentiate from the one we are already for broker + trustStoreAttributes.put(FileTrustStore.PATH, TestSSLConstants.TRUSTSTORE); + trustStoreAttributes.put(FileTrustStore.PASSWORD, TestSSLConstants.TRUSTSTORE_PASSWORD); + trustStoreAttributes.put(FileTrustStore.PEERS_ONLY, peersOnly); + + int responseCode = getRestTestHelper().submitRequest("truststore/" + name, "PUT", trustStoreAttributes); + assertEquals("Unexpected response code", 201, responseCode); + } + + private void assertTrustStoreAttributes(Map truststore, String name, String path, boolean peersOnly) + { + assertEquals("default systests trust store is missing", + name, truststore.get(TrustStore.NAME)); + assertEquals("unexpected path to trust store", + path, truststore.get(FileTrustStore.PATH)); + assertEquals("unexpected (dummy) password of default systests trust store", + AbstractConfiguredObject.SECURED_STRING_VALUE, truststore.get(FileTrustStore.PASSWORD)); + assertEquals("unexpected type of default systests trust store", + java.security.KeyStore.getDefaultType(), truststore.get(FileTrustStore.TRUST_STORE_TYPE)); + assertEquals("unexpected peersOnly value", + peersOnly, truststore.get(FileTrustStore.PEERS_ONLY)); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/UserPreferencesRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/UserPreferencesRestTest.java new file mode 100644 index 0000000000..a0902912ce --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/UserPreferencesRestTest.java @@ -0,0 +1,150 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest; + +import java.io.File; +import java.io.IOException; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.qpid.server.model.PreferencesProvider; +import org.apache.qpid.server.model.User; +import org.apache.qpid.server.model.adapter.FileSystemPreferencesProvider; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.test.utils.TestFileUtils; + +public class UserPreferencesRestTest extends QpidRestTestCase +{ + private File _preferencesProviderFile; + + public void setUp() throws Exception + { + _preferencesProviderFile = TestFileUtils.createTempFile(this, ".prefs.json", + "{\"webadmin\":{\"language\": \"en\", \"saveTabs\":true}," + + " \"admin\":{\"language\": \"fr\", \"saveTabs\":false}" + "}"); + super.setUp(); + } + + public void tearDown() throws Exception + { + try + { + super.tearDown(); + } + finally + { + if (_preferencesProviderFile != null) + { + _preferencesProviderFile.delete(); + } + } + } + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + + TestBrokerConfiguration brokerConfiguration = getBrokerConfiguration(); + Map attributes = new HashMap(); + attributes.put(PreferencesProvider.NAME, "test"); + attributes.put(PreferencesProvider.TYPE, FileSystemPreferencesProvider.PROVIDER_TYPE); + attributes.put(FileSystemPreferencesProvider.PATH, _preferencesProviderFile.getAbsolutePath()); + brokerConfiguration.addPreferencesProviderConfiguration(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, + attributes); + + } + + public void testGetUserPreferences() throws Exception + { + Map preferences = getRestTestHelper().getJsonAsMap( + "/service/userpreferences/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/webadmin"); + assertEquals("Unexpected number of preferences", 2, preferences.size()); + assertEquals("Unexpected language preference", "en", preferences.get("language")); + assertEquals("Unexpected saveTabs preference", true, preferences.get("saveTabs")); + } + + public void testGetUserListForAuthenticationProvider() throws Exception + { + List> users = getRestTestHelper().getJsonAsList( + "/service/userpreferences/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); + assertEquals("Unexpected number of users", 2, users.size()); + String[] expectedUsers = { "webadmin", "admin" }; + for (int i = 0; i < expectedUsers.length; i++) + { + Map user = findUser(expectedUsers[i], users); + assertNotNull(String.format("User %s is not found", expectedUsers[i]), user); + } + } + + public void testGetUserList() throws Exception + { + List> users = getRestTestHelper().getJsonAsList("/service/userpreferences"); + assertEquals("Unexpected number of users", 2, users.size()); + String[] expectedUsers = { "webadmin", "admin" }; + for (int i = 0; i < expectedUsers.length; i++) + { + Map user = findUser(expectedUsers[i], users); + assertNotNull(String.format("User %s is not found", expectedUsers[i]), user); + } + } + + public void testDeleteUser() throws Exception + { + int status = getRestTestHelper().submitRequest( + "/service/userpreferences?user=" + + URLEncoder.encode(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/webadmin", + "UTF-8"), "DELETE"); + assertEquals("Unexpected status ", 200, status); + List> users = getRestTestHelper().getJsonAsList("/service/userpreferences"); + assertEquals("Unexpected number of users", 1, users.size()); + Map user = findUser("admin", users); + assertNotNull("User admin is not found", user); + assertNull("User webadmin is found", findUser("webadmin", users)); + } + + public void testDeleteMultipleUser() throws Exception + { + int status = getRestTestHelper().submitRequest("/service/userpreferences?user=" + + URLEncoder.encode(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/webadmin", "UTF-8") + + "&user=" + URLEncoder.encode(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/admin", "UTF-8"), + "DELETE"); + assertEquals("Unexpected status ", 200, status); + List> users = getRestTestHelper().getJsonAsList("/service/userpreferences"); + assertEquals("Unexpected number of users", 0, users.size()); + } + + private Map findUser(String userName, List> users) + { + for (Map map : users) + { + if (userName.equals(map.get(User.NAME))) + { + return map; + } + } + return null; + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/UserRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/UserRestTest.java new file mode 100644 index 0000000000..5df8a4ed9a --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/UserRestTest.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.systest.rest; + +import java.util.List; +import java.util.Map; + +import org.apache.qpid.server.model.User; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class UserRestTest extends QpidRestTestCase +{ + @Override + public void setUp() throws Exception + { + getRestTestHelper().configureTemporaryPasswordFile(this, "user1", "user2"); + + super.setUp(); // do this last because it starts the broker, using the modified config + getRestTestHelper().setUsernameAndPassword("user1", "user1"); + } + + public void testGet() throws Exception + { + List> users = getRestTestHelper().getJsonAsList("user"); + assertNotNull("Users cannot be null", users); + assertTrue("Unexpected number of users", users.size() > 1); + for (Map user : users) + { + assertUser(user); + } + } + + public void testGetUserByName() throws Exception + { + List> users = getRestTestHelper().getJsonAsList("user"); + assertNotNull("Users cannot be null", users); + assertTrue("Unexpected number of users", users.size() > 1); + for (Map user : users) + { + assertNotNull("Attribute " + User.ID, user.get(User.ID)); + String userName = (String) user.get(User.NAME); + assertNotNull("Attribute " + User.NAME, userName); + Map userDetails = getRestTestHelper().getJsonAsSingletonList("user/" + + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + userName); + assertUser(userDetails); + assertEquals("Unexpected user name", userName, userDetails.get(User.NAME)); + } + } + + public void testPut() throws Exception + { + String userName = getTestName(); + getRestTestHelper().createOrUpdateUser(userName, "newPassword"); + + Map userDetails = getRestTestHelper().getJsonAsSingletonList("user/" + + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + userName); + assertUser(userDetails); + assertEquals("Unexpected user name", userName, userDetails.get(User.NAME)); + } + + public void testDelete() throws Exception + { + String userName = getTestName(); + getRestTestHelper().createOrUpdateUser(userName, "newPassword"); + + Map userDetails = getRestTestHelper().getJsonAsSingletonList("user/" + + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + userName); + String id = (String) userDetails.get(User.ID); + + getRestTestHelper().removeUserById(id); + + List> users = getRestTestHelper().getJsonAsList("user/" + + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + userName); + assertEquals("User should be deleted", 0, users.size()); + } + + private void assertUser(Map user) + { + assertNotNull("Attribute " + User.ID, user.get(User.ID)); + assertNotNull("Attribute " + User.NAME, user.get(User.NAME)); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/VirtualHostNodeRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/VirtualHostNodeRestTest.java new file mode 100644 index 0000000000..9569b90251 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/VirtualHostNodeRestTest.java @@ -0,0 +1,191 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest; + + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.VirtualHostNode; +import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNode; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +/** + * + * TODO: Add test to test the mutation of the storePath. If the store path is mutated + * whilst active then the store should be deleted next time we stop or close. + */ +public class VirtualHostNodeRestTest extends QpidRestTestCase +{ + public void testGet() throws Exception + { + List> virtualhostNodes = getRestTestHelper().getJsonAsList("virtualhostnode"); + assertNotNull("Virtualhostnodes data cannot be null", virtualhostNodes); + assertEquals("Unexpected number of hosts", EXPECTED_VIRTUALHOSTS.length, virtualhostNodes.size()); + for (String nodeName : EXPECTED_VIRTUALHOSTS) + { + Map node = getRestTestHelper().find("name", nodeName, virtualhostNodes); + Asserts.assertVirtualHostNode(nodeName, node); + } + } + + public void testCreateAndDeleteVirtualHostNode() throws Exception + { + String virtualhostNodeType = getTestProfileVirtualHostNodeType(); + String nodeName = "virtualhostnode-" + getTestName(); + File storePathAsFile = new File(getStoreLocation(nodeName)); + + createAndDeleteVirtualHostNode(virtualhostNodeType, nodeName, storePathAsFile); + assertFalse("Store should not exist after deletion", storePathAsFile.exists()); + } + + public void testCreateVirtualHostNodeWithDefaultStorePath() throws Exception + { + String virtualhostNodeType = getTestProfileVirtualHostNodeType(); + String nodeName = "virtualhostnode-" + getTestName(); + + createVirtualHostNode(nodeName, virtualhostNodeType); + + String restUrl = "virtualhostnode/" + nodeName; + Map virtualhostNode = getRestTestHelper().getJsonAsSingletonList(restUrl); + Asserts.assertVirtualHostNode(nodeName, virtualhostNode); + assertNull("Virtualhostnode should not automatically get a virtualhost child", + virtualhostNode.get("virtualhosts")); + + getRestTestHelper().submitRequest(restUrl, "DELETE", HttpServletResponse.SC_OK); + + List> virtualHostNodes = getRestTestHelper().getJsonAsList(restUrl); + assertEquals("Host should be deleted", 0, virtualHostNodes.size()); + } + + public void testRecoverVirtualHostNodeWithDesiredStateStopped() throws Exception + { + stopBroker(); + + TestBrokerConfiguration config = getBrokerConfiguration(); + config.setObjectAttribute(VirtualHostNode.class, TEST3_VIRTUALHOST, ConfiguredObject.DESIRED_STATE, "STOPPED"); + config.setSaved(false); + + startBroker(); + + String restUrl = "virtualhostnode/" + TEST3_VIRTUALHOST; + assertActualAndDesireStates(restUrl, "STOPPED", "STOPPED"); + } + + public void testMutateState() throws Exception + { + String restUrl = "virtualhostnode/" + TEST3_VIRTUALHOST; + + assertActualAndDesireStates(restUrl, "ACTIVE", "ACTIVE"); + + mutateVirtualHostNodeDesiredState(restUrl, "STOPPED"); + assertActualAndDesireStates(restUrl, "STOPPED", "STOPPED"); + + mutateVirtualHostNodeDesiredState(restUrl, "ACTIVE"); + assertActualAndDesireStates(restUrl, "ACTIVE", "ACTIVE"); + } + + public void testMutateAttributes() throws Exception + { + String restUrl = "virtualhostnode/" + TEST3_VIRTUALHOST; + + Map virtualhostNode = getRestTestHelper().getJsonAsSingletonList(restUrl); + assertNull(virtualhostNode.get(VirtualHostNode.DESCRIPTION)); + + String newDescription = "My virtualhost node"; + Map newAttributes = new HashMap(); + newAttributes.put(VirtualHostNode.DESCRIPTION, newDescription); + + getRestTestHelper().submitRequest(restUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); + + virtualhostNode = getRestTestHelper().getJsonAsSingletonList(restUrl); + assertEquals(newDescription, virtualhostNode.get(VirtualHostNode.DESCRIPTION)); + } + + private void createAndDeleteVirtualHostNode(final String virtualhostNodeType, + final String nodeName, + final File storePathAsFile) throws Exception + { + assertFalse("Store should not exist", storePathAsFile.exists()); + + createVirtualHostNode(nodeName, storePathAsFile.getAbsolutePath(), virtualhostNodeType); + assertTrue("Store should exist after creation of node", storePathAsFile.exists()); + + String restUrl = "virtualhostnode/" + nodeName; + Map virtualhostNode = getRestTestHelper().getJsonAsSingletonList(restUrl); + Asserts.assertVirtualHostNode(nodeName, virtualhostNode); + assertNull("Virtualhostnode should not automatically get a virtualhost child", + virtualhostNode.get("virtualhosts")); + + getRestTestHelper().submitRequest(restUrl, "DELETE", HttpServletResponse.SC_OK); + + List> virtualHostNodes = getRestTestHelper().getJsonAsList(restUrl); + assertEquals("Host should be deleted", 0, virtualHostNodes.size()); + } + + private void assertActualAndDesireStates(final String restUrl, + final String expectedDesiredState, + final String expectedActualState) throws IOException + { + Map virtualhostNode = getRestTestHelper().getJsonAsSingletonList(restUrl); + Asserts.assertActualAndDesiredState(expectedDesiredState, expectedActualState, virtualhostNode); + } + + private void mutateVirtualHostNodeDesiredState(final String restUrl, final String newState) throws IOException + { + Map newAttributes = new HashMap(); + newAttributes.put(VirtualHostNode.DESIRED_STATE, newState); + + getRestTestHelper().submitRequest(restUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); + } + + private void createVirtualHostNode(String nodeName, String configStorePath, final String storeType) throws Exception + { + Map nodeData = new HashMap(); + nodeData.put(VirtualHostNode.NAME, nodeName); + nodeData.put(VirtualHostNode.TYPE, storeType); + if (configStorePath != null) + { + nodeData.put(JsonVirtualHostNode.STORE_PATH, configStorePath); + } + + getRestTestHelper().submitRequest("virtualhostnode/" + nodeName, + "PUT", + nodeData, + HttpServletResponse.SC_CREATED); + } + + private void createVirtualHostNode(String nodeName, final String storeType) throws Exception + { + createVirtualHostNode(nodeName, null, storeType); + } + + private String getStoreLocation(String hostName) + { + return new File(TMP_FOLDER, "store-" + hostName + "-" + System.currentTimeMillis()).getAbsolutePath(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java new file mode 100644 index 0000000000..45cbee205d --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java @@ -0,0 +1,631 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Session; +import javax.servlet.http.HttpServletResponse; + +import org.apache.qpid.server.virtualhost.ProvidedStoreVirtualHostImpl; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.server.model.Exchange; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.queue.LastValueQueue; +import org.apache.qpid.server.queue.PriorityQueue; +import org.apache.qpid.server.queue.SortedQueue; +import org.apache.qpid.server.virtualhost.AbstractVirtualHost; + +import org.apache.qpid.server.virtualhost.derby.DerbyVirtualHostImpl; +import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNodeImpl; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class VirtualHostRestTest extends QpidRestTestCase +{ + private static final String VIRTUALHOST_EXCHANGES_ATTRIBUTE = "exchanges"; + public static final String VIRTUALHOST_QUEUES_ATTRIBUTE = "queues"; + public static final String VIRTUALHOST_CONNECTIONS_ATTRIBUTE = "connections"; + + public static final String EMPTY_VIRTUALHOSTNODE_NAME = "emptyVHN"; + + private AMQConnection _connection; + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + + TestBrokerConfiguration config = getBrokerConfiguration(); + createTestVirtualHostNode(0, EMPTY_VIRTUALHOSTNODE_NAME, false); + } + + public void testGet() throws Exception + { + List> hosts = getRestTestHelper().getJsonAsList("virtualhost"); + assertNotNull("Hosts data cannot be null", hosts); + assertEquals("Unexpected number of hosts", EXPECTED_VIRTUALHOSTS.length, hosts.size()); + for (String hostName : EXPECTED_VIRTUALHOSTS) + { + Map host = getRestTestHelper().find("name", hostName, hosts); + Asserts.assertVirtualHost(hostName, host); + } + } + + public void testGetHost() throws Exception + { + // create AMQP connection to get connection JSON details + _connection = (AMQConnection) getConnection(); + Session session = _connection.createSession(true, Session.SESSION_TRANSACTED); + session.createConsumer(getTestQueue()); + + Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); + Asserts.assertVirtualHost("test", hostDetails); + + @SuppressWarnings("unchecked") + Map statistics = (Map) hostDetails.get(Asserts.STATISTICS_ATTRIBUTE); + + assertEquals("Unexpected number of exchanges in statistics", EXPECTED_EXCHANGES.length, statistics.get( + "exchangeCount")); + assertEquals("Unexpected number of queues in statistics", 1, statistics.get("queueCount")); + assertEquals("Unexpected number of connections in statistics", 1, statistics.get("connectionCount")); + + @SuppressWarnings("unchecked") + List> exchanges = (List>) hostDetails.get(VIRTUALHOST_EXCHANGES_ATTRIBUTE); + assertEquals("Unexpected number of exchanges", EXPECTED_EXCHANGES.length, exchanges.size()); + Asserts.assertDurableExchange("amq.fanout", "fanout", getRestTestHelper().find(Exchange.NAME, "amq.fanout", exchanges)); + Asserts.assertDurableExchange("amq.topic", "topic", getRestTestHelper().find(Exchange.NAME, "amq.topic", exchanges)); + Asserts.assertDurableExchange("amq.direct", "direct", getRestTestHelper().find(Exchange.NAME, "amq.direct", exchanges)); + Asserts.assertDurableExchange("amq.match", "headers", getRestTestHelper().find(Exchange.NAME, "amq.match", exchanges)); + + @SuppressWarnings("unchecked") + List> queues = (List>) hostDetails.get(VIRTUALHOST_QUEUES_ATTRIBUTE); + assertEquals("Unexpected number of queues", 1, queues.size()); + Map queue = getRestTestHelper().find(Queue.NAME, getTestQueueName(), queues); + Asserts.assertQueue(getTestQueueName(), "standard", queue); + assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, queue.get(Queue.DURABLE)); + + @SuppressWarnings("unchecked") + List> connections = (List>) hostDetails + .get(VIRTUALHOST_CONNECTIONS_ATTRIBUTE); + assertEquals("Unexpected number of connections", 1, connections.size()); + Asserts.assertConnection(connections.get(0), _connection); + } + + public void testPutCreateProvidedVirtualHost() throws Exception + { + String hostName = getTestName(); + createVirtualHost(hostName, ProvidedStoreVirtualHostImpl.VIRTUAL_HOST_TYPE); + + Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/" + EMPTY_VIRTUALHOSTNODE_NAME + "/" + hostName); + Asserts.assertVirtualHost(hostName, hostDetails); + + assertNewVirtualHost(hostDetails); + } + + public void testPutCreateVirtualHost() throws Exception + { + String hostName = getTestName(); + String vhnType = getTestProfileVirtualHostNodeType(); + if (JsonVirtualHostNodeImpl.VIRTUAL_HOST_NODE_TYPE.equals(vhnType)) + { + vhnType = DerbyVirtualHostImpl.VIRTUAL_HOST_TYPE; + } + createVirtualHost(hostName, vhnType); + Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/" + EMPTY_VIRTUALHOSTNODE_NAME + "/" + hostName); + Asserts.assertVirtualHost(hostName, hostDetails); + + assertNewVirtualHost(hostDetails); + } + + public void testDeleteHost() throws Exception + { + getRestTestHelper().submitRequest("virtualhost/" + TEST3_VIRTUALHOST + "/" + TEST3_VIRTUALHOST, + "DELETE", + HttpServletResponse.SC_OK); + + List> hosts = getRestTestHelper().getJsonAsList("virtualhost/" + TEST3_VIRTUALHOST); + assertEquals("Host should be deleted", 0, hosts.size()); + } + + public void testDeleteDefaultHostFails() throws Exception + { + getRestTestHelper().submitRequest("virtualhost/" + TEST1_VIRTUALHOST, "DELETE", HttpServletResponse.SC_CONFLICT); + } + + public void testMutateAttributes() throws Exception + { + String hostToUpdate = TEST3_VIRTUALHOST; + String restHostUrl = "virtualhost/" + hostToUpdate + "/" + hostToUpdate; + + Map hostDetails = getRestTestHelper().getJsonAsSingletonList(restHostUrl); + Asserts.assertVirtualHost(hostToUpdate, hostDetails); + + Map newAttributes = Collections.singletonMap(VirtualHost.DESCRIPTION, "This is a virtual host"); + getRestTestHelper().submitRequest(restHostUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); + + Map rereadHostDetails = getRestTestHelper().getJsonAsSingletonList(restHostUrl); + Asserts.assertVirtualHost(hostToUpdate, rereadHostDetails); + assertEquals("This is a virtual host", rereadHostDetails.get(VirtualHost.DESCRIPTION)); + } + + public void testMutateState() throws Exception + { + String restHostUrl = "virtualhost/" + TEST1_VIRTUALHOST + "/" + TEST1_VIRTUALHOST; + + waitForAttributeChanged(restHostUrl, VirtualHost.STATE, "ACTIVE"); + assertActualAndDesireStates(restHostUrl, "ACTIVE", "ACTIVE"); + + Map newAttributes = Collections.singletonMap(VirtualHost.DESIRED_STATE, "STOPPED"); + getRestTestHelper().submitRequest(restHostUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); + + waitForAttributeChanged(restHostUrl, VirtualHost.STATE, "STOPPED"); + assertActualAndDesireStates(restHostUrl, "STOPPED", "STOPPED"); + + newAttributes = Collections.singletonMap(VirtualHost.DESIRED_STATE, "ACTIVE"); + getRestTestHelper().submitRequest(restHostUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); + + waitForAttributeChanged(restHostUrl, VirtualHost.STATE, "ACTIVE"); + + assertActualAndDesireStates(restHostUrl, "ACTIVE", "ACTIVE"); + } + + public void testMutateStateOfVirtualHostWithQueuesAndMessages() throws Exception + { + String testQueueName = getTestQueueName(); + String restHostUrl = "virtualhost/" + TEST1_VIRTUALHOST + "/" + TEST1_VIRTUALHOST; + String restQueueUrl = "queue/" + TEST1_VIRTUALHOST + "/" + TEST1_VIRTUALHOST + "/" + testQueueName; + + waitForAttributeChanged(restHostUrl, VirtualHost.STATE, "ACTIVE"); + assertActualAndDesireStates(restHostUrl, "ACTIVE", "ACTIVE"); + + Connection connection = getConnection(); + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Destination dest = session.createQueue(testQueueName); + session.createConsumer(dest).close(); + session.createProducer(dest).send(session.createTextMessage("My test message")); + session.commit(); + connection.close(); + + assertQueueDepth(restQueueUrl, "Unexpected number of messages before stopped", 1); + + Map newAttributes = Collections.singletonMap(VirtualHost.DESIRED_STATE, "STOPPED"); + getRestTestHelper().submitRequest(restHostUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); + + waitForAttributeChanged(restHostUrl, VirtualHost.STATE, "STOPPED"); + assertActualAndDesireStates(restHostUrl, "STOPPED", "STOPPED"); + + newAttributes = Collections.singletonMap(VirtualHost.DESIRED_STATE, "ACTIVE"); + getRestTestHelper().submitRequest(restHostUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); + + waitForAttributeChanged(restHostUrl, VirtualHost.STATE, "ACTIVE"); + + assertActualAndDesireStates(restHostUrl, "ACTIVE", "ACTIVE"); + + assertQueueDepth(restQueueUrl, "Unexpected number of messages after restart", 1); + } + + public void testRecoverVirtualHostInDesiredStateStoppedWithDescription() throws Exception + { + String hostToUpdate = TEST3_VIRTUALHOST; + String restUrl = "virtualhost/" + hostToUpdate + "/" + hostToUpdate; + + assertActualAndDesireStates(restUrl, "ACTIVE", "ACTIVE"); + + Map newAttributes = new HashMap<>(); + newAttributes.put(VirtualHost.DESIRED_STATE, "STOPPED"); + newAttributes.put(VirtualHost.DESCRIPTION, "My description"); + + getRestTestHelper().submitRequest(restUrl, "PUT", newAttributes, HttpServletResponse.SC_OK); + + assertActualAndDesireStates(restUrl, "STOPPED", "STOPPED"); + + restartBroker(); + + Map rereadVirtualhost = getRestTestHelper().getJsonAsSingletonList(restUrl); + Asserts.assertActualAndDesiredState("STOPPED", "STOPPED", rereadVirtualhost); + + assertEquals("Unexpected description after restart", "My description", rereadVirtualhost.get(VirtualHost.DESCRIPTION)); + } + + public void testPutCreateQueue() throws Exception + { + String queueName = getTestQueueName(); + + createQueue(queueName + "-standard", "standard", null); + + Map sortedQueueAttributes = new HashMap(); + sortedQueueAttributes.put(SortedQueue.SORT_KEY, "sortme"); + createQueue(queueName + "-sorted", "sorted", sortedQueueAttributes); + + Map priorityQueueAttributes = new HashMap(); + priorityQueueAttributes.put(PriorityQueue.PRIORITIES, 10); + createQueue(queueName + "-priority", "priority", priorityQueueAttributes); + + Map lvqQueueAttributes = new HashMap(); + lvqQueueAttributes.put(LastValueQueue.LVQ_KEY, "LVQ"); + createQueue(queueName + "-lvq", "lvq", lvqQueueAttributes); + + Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); + + @SuppressWarnings("unchecked") + List> queues = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE); + Map standardQueue = getRestTestHelper().find(Queue.NAME, queueName + "-standard" , queues); + Map sortedQueue = getRestTestHelper().find(Queue.NAME, queueName + "-sorted" , queues); + Map priorityQueue = getRestTestHelper().find(Queue.NAME, queueName + "-priority" , queues); + Map lvqQueue = getRestTestHelper().find(Queue.NAME, queueName + "-lvq" , queues); + + Asserts.assertQueue(queueName + "-standard", "standard", standardQueue); + Asserts.assertQueue(queueName + "-sorted", "sorted", sortedQueue); + Asserts.assertQueue(queueName + "-priority", "priority", priorityQueue); + Asserts.assertQueue(queueName + "-lvq", "lvq", lvqQueue); + + assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, standardQueue.get(Queue.DURABLE)); + assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, sortedQueue.get(Queue.DURABLE)); + assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, priorityQueue.get(Queue.DURABLE)); + assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, lvqQueue.get(Queue.DURABLE)); + + assertEquals("Unexpected sorted key attribute", "sortme", sortedQueue.get(SortedQueue.SORT_KEY)); + assertEquals("Unexpected lvq key attribute", "LVQ", lvqQueue.get(LastValueQueue.LVQ_KEY)); + assertEquals("Unexpected priorities key attribute", 10, priorityQueue.get(PriorityQueue.PRIORITIES)); + } + + public void testPutCreateExchange() throws Exception + { + String exchangeName = getTestName(); + + createExchange(exchangeName + "-direct", "direct"); + createExchange(exchangeName + "-topic", "topic"); + createExchange(exchangeName + "-headers", "headers"); + createExchange(exchangeName + "-fanout", "fanout"); + + Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); + + @SuppressWarnings("unchecked") + List> exchanges = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_EXCHANGES_ATTRIBUTE); + Map directExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-direct" , exchanges); + Map topicExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-topic" , exchanges); + Map headersExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-headers" , exchanges); + Map fanoutExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-fanout" , exchanges); + + Asserts.assertDurableExchange(exchangeName + "-direct", "direct", directExchange); + Asserts.assertDurableExchange(exchangeName + "-topic", "topic", topicExchange); + Asserts.assertDurableExchange(exchangeName + "-headers", "headers", headersExchange); + Asserts.assertDurableExchange(exchangeName + "-fanout", "fanout", fanoutExchange); + + assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, directExchange.get(Queue.DURABLE)); + assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, topicExchange.get(Queue.DURABLE)); + assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, headersExchange.get(Queue.DURABLE)); + assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, fanoutExchange.get(Queue.DURABLE)); + + } + + public void testPutCreateLVQWithoutKey() throws Exception + { + String queueName = getTestQueueName()+ "-lvq"; + createQueue(queueName, "lvq", null); + + Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); + + @SuppressWarnings("unchecked") + List> queues = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE); + Map lvqQueue = getRestTestHelper().find(Queue.NAME, queueName , queues); + + Asserts.assertQueue(queueName , "lvq", lvqQueue); + assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, lvqQueue.get(Queue.DURABLE)); + assertEquals("Unexpected lvq key attribute", LastValueQueue.DEFAULT_LVQ_KEY, lvqQueue.get(LastValueQueue.LVQ_KEY)); + } + + public void testPutCreateSortedQueueWithoutKey() throws Exception + { + String queueName = getTestQueueName() + "-sorted"; + int responseCode = tryCreateQueue(queueName, "sorted", null); + assertEquals("Unexpected response code", HttpServletResponse.SC_CONFLICT, responseCode); + + Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); + + @SuppressWarnings("unchecked") + List> queues = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE); + Map testQueue = getRestTestHelper().find(Queue.NAME, queueName , queues); + + assertNull("Sorted queue without a key was created ", testQueue); + } + + public void testPutCreatePriorityQueueWithoutKey() throws Exception + { + String queueName = getTestQueueName()+ "-priority"; + createQueue(queueName, "priority", null); + + Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); + + @SuppressWarnings("unchecked") + List> queues = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE); + Map priorityQueue = getRestTestHelper().find(Queue.NAME, queueName , queues); + + Asserts.assertQueue(queueName , "priority", priorityQueue); + assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, priorityQueue.get(Queue.DURABLE)); + assertEquals("Unexpected number of priorities", 10, priorityQueue.get(PriorityQueue.PRIORITIES)); + } + + public void testPutCreateStandardQueueWithoutType() throws Exception + { + String queueName = getTestQueueName(); + createQueue(queueName, null, null); + + Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); + + @SuppressWarnings("unchecked") + List> queues = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE); + Map queue = getRestTestHelper().find(Queue.NAME, queueName , queues); + + Asserts.assertQueue(queueName , "standard", queue); + } + + public void testPutCreateQueueOfUnsupportedType() throws Exception + { + String queueName = getTestQueueName(); + int responseCode = tryCreateQueue(queueName, "unsupported", null); + assertEquals("Unexpected response code", HttpServletResponse.SC_CONFLICT, responseCode); + + Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); + + @SuppressWarnings("unchecked") + List> queues = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE); + Map queue = getRestTestHelper().find(Queue.NAME, queueName , queues); + + assertNull("Queue of unsupported type was created", queue); + } + + public void testDeleteQueue() throws Exception + { + String queueName = getTestQueueName(); + createQueue(queueName, null, null); + + String queueUrl = "queue/test/test/" + queueName; + List> queues = getRestTestHelper().getJsonAsList(queueUrl); + assertEquals("Queue should exist", 1, queues.size()); + + int statusCode = getRestTestHelper().submitRequest(queueUrl, "DELETE"); + assertEquals("Unexpected response code", 200, statusCode); + queues = getRestTestHelper().getJsonAsList(queueUrl); + assertEquals("Queue should be deleted", 0, queues.size()); + } + + public void testDeleteQueueById() throws Exception + { + String queueName = getTestQueueName(); + createQueue(queueName, null, null); + Map queueDetails = getRestTestHelper().getJsonAsSingletonList("queue/test/test/" + queueName); + int statusCode = getRestTestHelper().submitRequest("queue/test/test?id=" + queueDetails.get(Queue.ID), "DELETE"); + assertEquals("Unexpected response code", 200, statusCode); + List> queues = getRestTestHelper().getJsonAsList("queue/test/test/" + queueName); + assertEquals("Queue should be deleted", 0, queues.size()); + } + + public void testDeleteExchange() throws Exception + { + String exchangeName = getTestName(); + createExchange(exchangeName, "direct"); + + int statusCode = getRestTestHelper().submitRequest("exchange/test/test/" + exchangeName, "DELETE"); + + assertEquals("Unexpected response code", 200, statusCode); + List> queues = getRestTestHelper().getJsonAsList("exchange/test/test/" + exchangeName); + assertEquals("Exchange should be deleted", 0, queues.size()); + } + + public void testDeleteExchangeById() throws Exception + { + String exchangeName = getTestName(); + createExchange(exchangeName, "direct"); + Map echangeDetails = getRestTestHelper().getJsonAsSingletonList("exchange/test/test/" + exchangeName); + + int statusCode = getRestTestHelper().submitRequest("exchange/test/test?id=" + echangeDetails.get(Exchange.ID), "DELETE"); + + assertEquals("Unexpected response code", 200, statusCode); + List> queues = getRestTestHelper().getJsonAsList("exchange/test/test/" + exchangeName); + assertEquals("Exchange should be deleted", 0, queues.size()); + } + + public void testPutCreateQueueWithAttributes() throws Exception + { + String queueName = getTestQueueName(); + + Map attributes = new HashMap(); + attributes.put(Queue.ALERT_REPEAT_GAP, 1000); + attributes.put(Queue.ALERT_THRESHOLD_MESSAGE_AGE, 3600000); + attributes.put(Queue.ALERT_THRESHOLD_MESSAGE_SIZE, 1000000000); + attributes.put(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, 800); + attributes.put(Queue.MAXIMUM_DELIVERY_ATTEMPTS, 15); + attributes.put(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 2000000000); + attributes.put(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 1500000000); + + createQueue(queueName + "-standard", "standard", attributes); + + Map sortedQueueAttributes = new HashMap(); + sortedQueueAttributes.putAll(attributes); + sortedQueueAttributes.put(SortedQueue.SORT_KEY, "sortme"); + createQueue(queueName + "-sorted", "sorted", sortedQueueAttributes); + + Map priorityQueueAttributes = new HashMap(); + priorityQueueAttributes.putAll(attributes); + priorityQueueAttributes.put(PriorityQueue.PRIORITIES, 10); + createQueue(queueName + "-priority", "priority", priorityQueueAttributes); + + Map lvqQueueAttributes = new HashMap(); + lvqQueueAttributes.putAll(attributes); + lvqQueueAttributes.put(LastValueQueue.LVQ_KEY, "LVQ"); + createQueue(queueName + "-lvq", "lvq", lvqQueueAttributes); + + Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); + + @SuppressWarnings("unchecked") + List> queues = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE); + Map standardQueue = getRestTestHelper().find(Queue.NAME, queueName + "-standard" , queues); + Map sortedQueue = getRestTestHelper().find(Queue.NAME, queueName + "-sorted" , queues); + Map priorityQueue = getRestTestHelper().find(Queue.NAME, queueName + "-priority" , queues); + Map lvqQueue = getRestTestHelper().find(Queue.NAME, queueName + "-lvq" , queues); + + attributes.put(Queue.DURABLE, Boolean.TRUE); + Asserts.assertQueue(queueName + "-standard", "standard", standardQueue, attributes); + Asserts.assertQueue(queueName + "-sorted", "sorted", sortedQueue, attributes); + Asserts.assertQueue(queueName + "-priority", "priority", priorityQueue, attributes); + Asserts.assertQueue(queueName + "-lvq", "lvq", lvqQueue, attributes); + + assertEquals("Unexpected sorted key attribute", "sortme", sortedQueue.get(SortedQueue.SORT_KEY)); + assertEquals("Unexpected lvq key attribute", "LVQ", lvqQueue.get(LastValueQueue.LVQ_KEY)); + assertEquals("Unexpected priorities key attribute", 10, priorityQueue.get(PriorityQueue.PRIORITIES)); + } + + @SuppressWarnings("unchecked") + public void testCreateQueueWithDLQEnabled() throws Exception + { + String queueName = getTestQueueName(); + + Map attributes = new HashMap(); + attributes.put(AbstractVirtualHost.CREATE_DLQ_ON_CREATION, true); + + //verify the starting state + Map hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); + List> queues = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE); + List> exchanges = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_EXCHANGES_ATTRIBUTE); + + assertNull("queue "+ queueName + " should not have already been present", getRestTestHelper().find(Queue.NAME, queueName , queues)); + assertNull("queue "+ queueName + "_DLQ should not have already been present", getRestTestHelper().find(Queue.NAME, queueName + "_DLQ" , queues)); + assertNull("exchange should not have already been present", getRestTestHelper().find(Exchange.NAME, queueName + "_DLE" , exchanges)); + + //create the queue + createQueue(queueName, "standard", attributes); + + //verify the new queue, as well as the DLQueue and DLExchange have been created + hostDetails = getRestTestHelper().getJsonAsSingletonList("virtualhost/test"); + queues = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE); + exchanges = (List>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_EXCHANGES_ATTRIBUTE); + + Map queue = getRestTestHelper().find(Queue.NAME, queueName , queues); + Map dlqQueue = getRestTestHelper().find(Queue.NAME, queueName + "_DLQ" , queues); + Map dlExchange = getRestTestHelper().find(Exchange.NAME, queueName + "_DLE" , exchanges); + assertNotNull("queue should have been present", queue); + assertNotNull("queue should have been present", dlqQueue); + assertNotNull("exchange should have been present", dlExchange); + + //verify that the alternate exchange is set as expected on the new queue + Map queueAttributes = new HashMap(); + queueAttributes.put(Queue.ALTERNATE_EXCHANGE, queueName + "_DLE"); + + Asserts.assertQueue(queueName, "standard", queue, queueAttributes); + Asserts.assertQueue(queueName, "standard", queue, null); + } + + private void createExchange(String exchangeName, String exchangeType) throws IOException + { + Map queueData = new HashMap(); + queueData.put(Exchange.NAME, exchangeName); + queueData.put(Exchange.DURABLE, Boolean.TRUE); + queueData.put(Exchange.TYPE, exchangeType); + + int statusCode = getRestTestHelper().submitRequest("exchange/test/test/" + exchangeName, "PUT", queueData); + assertEquals("Unexpected response code", 201, statusCode); + } + + private void createQueue(String queueName, String queueType, Map attributes) throws Exception + { + int responseCode = tryCreateQueue(queueName, queueType, attributes); + assertEquals("Unexpected response code", 201, responseCode); + } + + private int tryCreateQueue(String queueName, String queueType, Map attributes) throws Exception + { + Map queueData = new HashMap(); + queueData.put(Queue.NAME, queueName); + queueData.put(Queue.DURABLE, Boolean.TRUE); + if (queueType != null) + { + queueData.put(Queue.TYPE, queueType); + } + if (attributes != null) + { + queueData.putAll(attributes); + } + + return getRestTestHelper().submitRequest("queue/test/test/" + queueName, "PUT", queueData); + } + + private void createVirtualHost(final String virtualHostName, + final String virtualHostType) throws IOException + { + Map virtualhostData = new HashMap<>(); + virtualhostData.put(VirtualHost.NAME, virtualHostName); + virtualhostData.put(VirtualHost.TYPE, virtualHostType); + + getRestTestHelper().submitRequest("virtualhost/" + EMPTY_VIRTUALHOSTNODE_NAME + "/" + virtualHostName, + "PUT", + virtualhostData, + HttpServletResponse.SC_CREATED); + } + + private void assertNewVirtualHost(Map hostDetails) + { + @SuppressWarnings("unchecked") + Map statistics = (Map) hostDetails.get(Asserts.STATISTICS_ATTRIBUTE); + assertEquals("Unexpected number of exchanges in statistics", EXPECTED_EXCHANGES.length, + statistics.get("exchangeCount")); + assertEquals("Unexpected number of queues in statistics", 0, statistics.get("queueCount")); + assertEquals("Unexpected number of connections in statistics", 0, statistics.get("connectionCount")); + + @SuppressWarnings("unchecked") + List> exchanges = (List>) hostDetails.get(VIRTUALHOST_EXCHANGES_ATTRIBUTE); + assertEquals("Unexpected number of exchanges", EXPECTED_EXCHANGES.length, exchanges.size()); + RestTestHelper restTestHelper = getRestTestHelper(); + Asserts.assertDurableExchange("amq.fanout", "fanout", restTestHelper.find(Exchange.NAME, "amq.fanout", exchanges)); + Asserts.assertDurableExchange("amq.topic", "topic", restTestHelper.find(Exchange.NAME, "amq.topic", exchanges)); + Asserts.assertDurableExchange("amq.direct", "direct", restTestHelper.find(Exchange.NAME, "amq.direct", exchanges)); + Asserts.assertDurableExchange("amq.match", "headers", restTestHelper.find(Exchange.NAME, "amq.match", exchanges)); + + assertNull("Unexpected queues", hostDetails.get(VIRTUALHOST_QUEUES_ATTRIBUTE)); + assertNull("Unexpected connections", hostDetails.get(VIRTUALHOST_CONNECTIONS_ATTRIBUTE)); + } + + private void assertActualAndDesireStates(final String restUrl, + final String expectedDesiredState, + final String expectedActualState) throws IOException + { + Map virtualhost = getRestTestHelper().getJsonAsSingletonList(restUrl); + Asserts.assertActualAndDesiredState(expectedDesiredState, expectedActualState, virtualhost); + } + + private void assertQueueDepth(String restQueueUrl, String message, int expectedDepth) throws IOException + { + Map queueDetails = getRestTestHelper().getJsonAsSingletonList(restQueueUrl); + assertNotNull(queueDetails); + Map statistics = (Map) queueDetails.get(Asserts.STATISTICS_ATTRIBUTE); + assertNotNull(statistics); + + assertEquals(message, expectedDepth, statistics.get("queueDepthMessages")); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java new file mode 100644 index 0000000000..8c4effd685 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/BrokerACLTest.java @@ -0,0 +1,1009 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest.acl; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.codehaus.jackson.JsonGenerationException; +import org.codehaus.jackson.map.JsonMappingException; +import org.apache.qpid.server.management.plugin.HttpManagement; +import org.apache.qpid.server.model.AccessControlProvider; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ExternalFileBasedAuthenticationManager; +import org.apache.qpid.server.model.GroupProvider; +import org.apache.qpid.server.model.KeyStore; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.model.TrustStore; +import org.apache.qpid.server.model.adapter.FileBasedGroupProvider; +import org.apache.qpid.server.model.adapter.FileBasedGroupProviderImpl; +import org.apache.qpid.server.security.FileKeyStore; +import org.apache.qpid.server.security.FileTrustStore; +import org.apache.qpid.server.security.access.FileAccessControlProviderConstants; +import org.apache.qpid.server.security.acl.AbstractACLTestCase; +import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager; +import org.apache.qpid.server.security.auth.manager.PlainPasswordDatabaseAuthenticationManager; +import org.apache.qpid.systest.rest.QpidRestTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.test.utils.TestFileUtils; +import org.apache.qpid.test.utils.TestSSLConstants; + +public class BrokerACLTest extends QpidRestTestCase +{ + private static final String ALLOWED_USER = "user1"; + private static final String DENIED_USER = "user2"; + private String _secondaryAclFileContent = ""; + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER); + + AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", + "ACL ALLOW-LOG " + ALLOWED_USER + " CONFIGURE BROKER", + "ACL DENY-LOG " + DENIED_USER + " CONFIGURE BROKER", + "ACL DENY-LOG ALL ALL"); + + _secondaryAclFileContent = + "ACL ALLOW-LOG ALL ACCESS MANAGEMENT\n" + + "ACL ALLOW-LOG " + ALLOWED_USER + " CONFIGURE BROKER\n" + + "ACL DENY-LOG " + DENIED_USER + " CONFIGURE BROKER\n" + + "ACL DENY-LOG ALL ALL"; + + getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, + HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); + } + + /* === AuthenticationProvider === */ + + public void testCreateAuthenticationProviderAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String authenticationProviderName = getTestName(); + + int responseCode = createAuthenticationProvider(authenticationProviderName); + assertEquals("Provider creation should be allowed", 201, responseCode); + + assertAuthenticationProviderExists(authenticationProviderName); + } + + public void testCreateAuthenticationProviderDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + String authenticationProviderName = getTestName(); + + int responseCode = createAuthenticationProvider(authenticationProviderName); + assertEquals("Provider creation should be denied", 403, responseCode); + + assertAuthenticationProviderDoesNotExist(authenticationProviderName); + } + + public void testDeleteAuthenticationProviderAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String providerName = getTestName(); + + int responseCode = createAuthenticationProvider(providerName); + assertEquals("Provider creation should be allowed", 201, responseCode); + + assertAuthenticationProviderExists(providerName); + + responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "DELETE"); + assertEquals("Provider deletion should be allowed", 200, responseCode); + + assertAuthenticationProviderDoesNotExist(TEST2_VIRTUALHOST); + } + + public void testDeleteAuthenticationProviderDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String providerName = getTestName(); + + int responseCode = createAuthenticationProvider(providerName); + assertEquals("Provider creation should be allowed", 201, responseCode); + + assertAuthenticationProviderExists(providerName); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "DELETE"); + assertEquals("Provider deletion should be denied", 403, responseCode); + + assertAuthenticationProviderExists(providerName); + } + + public void testSetAuthenticationProviderAttributesAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String providerName = TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER; + + assertAuthenticationProviderExists(providerName); + + File file = TestFileUtils.createTempFile(this, ".users", "guest:guest\n" + ALLOWED_USER + ":" + ALLOWED_USER + "\n" + + DENIED_USER + ":" + DENIED_USER); + + Map attributes = new HashMap(); + attributes.put(AuthenticationProvider.NAME, providerName); + attributes.put(AuthenticationProvider.TYPE, PlainPasswordDatabaseAuthenticationManager.PROVIDER_TYPE); + attributes.put(ExternalFileBasedAuthenticationManager.PATH, file.getAbsolutePath()); + + int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); + assertEquals("Setting of provider attribites should be allowed", 200, responseCode); + } + + public void testSetAuthenticationProviderAttributesDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String providerName = TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER; + + Map providerData = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + providerName); + + File file = TestFileUtils.createTempFile(this, ".users", "guest:guest\n" + ALLOWED_USER + ":" + ALLOWED_USER + "\n" + + DENIED_USER + ":" + DENIED_USER); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + Map attributes = new HashMap(); + attributes.put(AuthenticationProvider.NAME, providerName); + attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); + attributes.put(ExternalFileBasedAuthenticationManager.PATH, file.getAbsolutePath()); + + int responseCode = getRestTestHelper().submitRequest("authenticationprovider/" + providerName, "PUT", attributes); + assertEquals("Setting of provider attribites should be allowed", 403, responseCode); + + Map provider = getRestTestHelper().getJsonAsSingletonList("authenticationprovider/" + providerName); + assertEquals("Unexpected PATH attribute value", + providerData.get(ExternalFileBasedAuthenticationManager.PATH), + provider.get(ExternalFileBasedAuthenticationManager.PATH)); + } + + /* === Port === */ + + public void testCreatePortAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String portName = getTestName(); + + int responseCode = createPort(portName); + assertEquals("Port creation should be allowed", 201, responseCode); + + assertPortExists(portName); + } + + public void testCreatePortDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + String portName = getTestName(); + + int responseCode = createPort(portName); + assertEquals("Port creation should be denied", 403, responseCode); + + assertPortDoesNotExist(portName); + } + + public void testDeletePortDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; + assertPortExists(portName); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + int responseCode = getRestTestHelper().submitRequest("port/" + portName, "DELETE"); + assertEquals("Port deletion should be denied", 403, responseCode); + + assertPortExists(portName); + } + + public void testDeletePortAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; + assertPortExists(portName); + + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + int responseCode = getRestTestHelper().submitRequest("port/" + portName, "DELETE"); + assertEquals("Port deletion should be allowed", 200, responseCode); + + assertPortDoesNotExist(portName); + } + + // TODO: test disabled until allowing the updating of active ports outside management mode + public void DISABLED_testSetPortAttributesAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String portName = getTestName(); + + int responseCode = createPort(portName); + assertEquals("Port creation should be allowed", 201, responseCode); + + assertPortExists(portName); + + + Map attributes = new HashMap(); + attributes.put(Port.NAME, portName); + attributes.put(Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER); + responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); + assertEquals("Setting of port attribites should be allowed", 200, responseCode); + + Map port = getRestTestHelper().getJsonAsSingletonList("port/" + portName); + assertEquals("Unexpected authentication provider attribute value", ANONYMOUS_AUTHENTICATION_PROVIDER, + port.get(Port.AUTHENTICATION_PROVIDER)); + } + + public void testSetPortAttributesDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String portName = getTestName(); + + int responseCode = createPort(portName); + assertEquals("Port creation should be allowed", 201, responseCode); + + assertPortExists(portName); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + Map attributes = new HashMap(); + attributes.put(Port.NAME, portName); + attributes.put(Port.PROTOCOLS, Arrays.asList(Protocol.AMQP_0_9)); + attributes.put(Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER); + responseCode = getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); + assertEquals("Setting of port attribites should be denied", 403, responseCode); + + Map port = getRestTestHelper().getJsonAsSingletonList("port/" + portName); + assertEquals("Unexpected authentication provider attribute value", + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, port.get(Port.AUTHENTICATION_PROVIDER)); + } + + /* === KeyStore === */ + + public void testCreateKeyStoreAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String keyStoreName = getTestName(); + + assertKeyStoreExistence(keyStoreName, false); + + int responseCode = createKeyStore(keyStoreName, "app1"); + assertEquals("keyStore creation should be allowed", 201, responseCode); + + assertKeyStoreExistence(keyStoreName, true); + } + + public void testCreateKeyStoreDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + String keyStoreName = getTestName(); + + assertKeyStoreExistence(keyStoreName, false); + + int responseCode = createKeyStore(keyStoreName, "app1"); + assertEquals("keyStore creation should be allowed", 403, responseCode); + + assertKeyStoreExistence(keyStoreName, false); + } + + public void testDeleteKeyStoreDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String keyStoreName = getTestName(); + + assertKeyStoreExistence(keyStoreName, false); + + int responseCode = createKeyStore(keyStoreName, "app1"); + assertEquals("keyStore creation should be allowed", 201, responseCode); + + assertKeyStoreExistence(keyStoreName, true); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + responseCode = getRestTestHelper().submitRequest("keystore/" + keyStoreName, "DELETE"); + assertEquals("keystore deletion should be denied", 403, responseCode); + + assertKeyStoreExistence(keyStoreName, true); + } + + public void testDeleteKeyStoreAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String keyStoreName = getTestName(); + + assertKeyStoreExistence(keyStoreName, false); + + int responseCode = createKeyStore(keyStoreName, "app1"); + assertEquals("keyStore creation should be allowed", 201, responseCode); + + assertKeyStoreExistence(keyStoreName, true); + + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + responseCode = getRestTestHelper().submitRequest("keystore/" + keyStoreName, "DELETE"); + assertEquals("keystore deletion should be allowed", 200, responseCode); + + assertKeyStoreExistence(keyStoreName, false); + } + + public void testSetKeyStoreAttributesAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String keyStoreName = getTestName(); + String initialCertAlias = "app1"; + String updatedCertAlias = "app2"; + + assertKeyStoreExistence(keyStoreName, false); + + int responseCode = createKeyStore(keyStoreName, initialCertAlias); + assertEquals("keyStore creation should be allowed", 201, responseCode); + + assertKeyStoreExistence(keyStoreName, true); + Map keyStore = getRestTestHelper().getJsonAsSingletonList("keystore/" + keyStoreName); + assertEquals("Unexpected certificateAlias attribute value", initialCertAlias, keyStore.get(FileKeyStore.CERTIFICATE_ALIAS)); + + Map attributes = new HashMap(); + attributes.put(KeyStore.NAME, keyStoreName); + attributes.put(FileKeyStore.CERTIFICATE_ALIAS, updatedCertAlias); + responseCode = getRestTestHelper().submitRequest("keystore/" + keyStoreName, "PUT", attributes); + assertEquals("Setting of keystore attributes should be allowed", 200, responseCode); + + keyStore = getRestTestHelper().getJsonAsSingletonList("keystore/" + keyStoreName); + assertEquals("Unexpected certificateAlias attribute value", updatedCertAlias, keyStore.get(FileKeyStore.CERTIFICATE_ALIAS)); + } + + public void testSetKeyStoreAttributesDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String keyStoreName = getTestName(); + String initialCertAlias = "app1"; + String updatedCertAlias = "app2"; + + assertKeyStoreExistence(keyStoreName, false); + + int responseCode = createKeyStore(keyStoreName, initialCertAlias); + assertEquals("keyStore creation should be allowed", 201, responseCode); + + assertKeyStoreExistence(keyStoreName, true); + Map keyStore = getRestTestHelper().getJsonAsSingletonList("keystore/" + keyStoreName); + assertEquals("Unexpected certificateAlias attribute value", initialCertAlias, keyStore.get(FileKeyStore.CERTIFICATE_ALIAS)); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + Map attributes = new HashMap(); + attributes.put(KeyStore.NAME, keyStoreName); + attributes.put(FileKeyStore.CERTIFICATE_ALIAS, updatedCertAlias); + responseCode = getRestTestHelper().submitRequest("keystore/" + keyStoreName, "PUT", attributes); + assertEquals("Setting of keystore attributes should be denied", 403, responseCode); + + keyStore = getRestTestHelper().getJsonAsSingletonList("keystore/" + keyStoreName); + assertEquals("Unexpected certificateAlias attribute value", initialCertAlias, keyStore.get(FileKeyStore.CERTIFICATE_ALIAS)); + } + + /* === TrustStore === */ + + public void testCreateTrustStoreAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String trustStoreName = getTestName(); + + assertTrustStoreExistence(trustStoreName, false); + + int responseCode = createTrustStore(trustStoreName, false); + assertEquals("trustStore creation should be allowed", 201, responseCode); + + assertTrustStoreExistence(trustStoreName, true); + } + + public void testCreateTrustStoreDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + String trustStoreName = getTestName(); + + assertTrustStoreExistence(trustStoreName, false); + + int responseCode = createTrustStore(trustStoreName, false); + assertEquals("trustStore creation should be allowed", 403, responseCode); + + assertTrustStoreExistence(trustStoreName, false); + } + + public void testDeleteTrustStoreDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String trustStoreName = getTestName(); + + assertTrustStoreExistence(trustStoreName, false); + + int responseCode = createTrustStore(trustStoreName, false); + assertEquals("trustStore creation should be allowed", 201, responseCode); + + assertTrustStoreExistence(trustStoreName, true); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + responseCode = getRestTestHelper().submitRequest("truststore/" + trustStoreName, "DELETE"); + assertEquals("truststore deletion should be denied", 403, responseCode); + + assertTrustStoreExistence(trustStoreName, true); + } + + public void testDeleteTrustStoreAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String trustStoreName = getTestName(); + + assertTrustStoreExistence(trustStoreName, false); + + int responseCode = createTrustStore(trustStoreName, false); + assertEquals("trustStore creation should be allowed", 201, responseCode); + + assertTrustStoreExistence(trustStoreName, true); + + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + responseCode = getRestTestHelper().submitRequest("truststore/" + trustStoreName, "DELETE"); + assertEquals("truststore deletion should be allowed", 200, responseCode); + + assertTrustStoreExistence(trustStoreName, false); + } + + public void testSetTrustStoreAttributesAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String trustStoreName = getTestName(); + boolean initialPeersOnly = false; + boolean updatedPeersOnly = true; + + assertTrustStoreExistence(trustStoreName, false); + + int responseCode = createTrustStore(trustStoreName, initialPeersOnly); + assertEquals("trustStore creation should be allowed", 201, responseCode); + + assertTrustStoreExistence(trustStoreName, true); + Map trustStore = getRestTestHelper().getJsonAsSingletonList("truststore/" + trustStoreName); + assertEquals("Unexpected peersOnly attribute value", initialPeersOnly, trustStore.get(FileTrustStore.PEERS_ONLY)); + + Map attributes = new HashMap(); + attributes.put(TrustStore.NAME, trustStoreName); + attributes.put(FileTrustStore.PEERS_ONLY, updatedPeersOnly); + responseCode = getRestTestHelper().submitRequest("truststore/" + trustStoreName, "PUT", attributes); + assertEquals("Setting of truststore attributes should be allowed", 200, responseCode); + + trustStore = getRestTestHelper().getJsonAsSingletonList("truststore/" + trustStoreName); + assertEquals("Unexpected peersOnly attribute value", updatedPeersOnly, trustStore.get(FileTrustStore.PEERS_ONLY)); + } + + public void testSetTrustStoreAttributesDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String trustStoreName = getTestName(); + boolean initialPeersOnly = false; + boolean updatedPeersOnly = true; + + assertTrustStoreExistence(trustStoreName, false); + + int responseCode = createTrustStore(trustStoreName, initialPeersOnly); + assertEquals("trustStore creation should be allowed", 201, responseCode); + + assertTrustStoreExistence(trustStoreName, true); + Map trustStore = getRestTestHelper().getJsonAsSingletonList("truststore/" + trustStoreName); + assertEquals("Unexpected peersOnly attribute value", initialPeersOnly, trustStore.get(FileTrustStore.PEERS_ONLY)); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + Map attributes = new HashMap(); + attributes.put(TrustStore.NAME, trustStoreName); + attributes.put(FileTrustStore.PEERS_ONLY, updatedPeersOnly); + responseCode = getRestTestHelper().submitRequest("truststore/" + trustStoreName, "PUT", attributes); + assertEquals("Setting of truststore attributes should be denied", 403, responseCode); + + trustStore = getRestTestHelper().getJsonAsSingletonList("truststore/" + trustStoreName); + assertEquals("Unexpected peersOnly attribute value", initialPeersOnly, trustStore.get(FileTrustStore.PEERS_ONLY)); + } + + /* === Broker === */ + + public void testSetBrokerAttributesAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + int initialSessionCountLimit = 256; + int updatedSessionCountLimit = 299; + + Map brokerAttributes = getRestTestHelper().getJsonAsSingletonList("broker"); + assertEquals("Unexpected alert repeat gap", initialSessionCountLimit, + brokerAttributes.get(Broker.CONNECTION_SESSION_COUNT_LIMIT)); + + Map newAttributes = new HashMap(); + newAttributes.put(Broker.CONNECTION_SESSION_COUNT_LIMIT, updatedSessionCountLimit); + + int responseCode = getRestTestHelper().submitRequest("broker", "PUT", newAttributes); + assertEquals("Setting of port attribites should be allowed", 200, responseCode); + + brokerAttributes = getRestTestHelper().getJsonAsSingletonList("broker"); + assertEquals("Unexpected default alert repeat gap", updatedSessionCountLimit, + brokerAttributes.get(Broker.CONNECTION_SESSION_COUNT_LIMIT)); + } + + public void testSetBrokerAttributesDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + int initialSessionCountLimit = 256; + int updatedSessionCountLimit = 299; + + Map brokerAttributes = getRestTestHelper().getJsonAsSingletonList("broker"); + assertEquals("Unexpected alert repeat gap", initialSessionCountLimit, + brokerAttributes.get(Broker.CONNECTION_SESSION_COUNT_LIMIT)); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + Map newAttributes = new HashMap(); + newAttributes.put(Broker.CONNECTION_SESSION_COUNT_LIMIT, updatedSessionCountLimit); + + int responseCode = getRestTestHelper().submitRequest("broker", "PUT", newAttributes); + assertEquals("Setting of port attribites should be allowed", 403, responseCode); + + brokerAttributes = getRestTestHelper().getJsonAsSingletonList("broker"); + assertEquals("Unexpected default alert repeat gap", initialSessionCountLimit, + brokerAttributes.get(Broker.CONNECTION_SESSION_COUNT_LIMIT)); + } + + /* === GroupProvider === */ + + public void testCreateGroupProviderAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String groupProviderName = getTestName(); + + assertGroupProviderExistence(groupProviderName, false); + + int responseCode = createGroupProvider(groupProviderName); + assertEquals("Group provider creation should be allowed", 201, responseCode); + + assertGroupProviderExistence(groupProviderName, true); + } + + public void testCreateGroupProviderDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + String groupProviderName = getTestName(); + + assertGroupProviderExistence(groupProviderName, false); + + int responseCode = createGroupProvider(groupProviderName); + assertEquals("Group provider creation should be denied", 403, responseCode); + + assertGroupProviderExistence(groupProviderName, false); + } + + public void testDeleteGroupProviderDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String groupProviderName = getTestName(); + + assertGroupProviderExistence(groupProviderName, false); + + int responseCode = createGroupProvider(groupProviderName); + assertEquals("Group provider creation should be allowed", 201, responseCode); + + assertGroupProviderExistence(groupProviderName, true); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + responseCode = getRestTestHelper().submitRequest("groupprovider/" + groupProviderName, "DELETE"); + assertEquals("Group provider deletion should be denied", 403, responseCode); + + assertGroupProviderExistence(groupProviderName, true); + } + + public void testDeleteGroupProviderAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String groupProviderName = getTestName(); + + assertGroupProviderExistence(groupProviderName, false); + + int responseCode = createGroupProvider(groupProviderName); + assertEquals("Group provider creation should be allowed", 201, responseCode); + + assertGroupProviderExistence(groupProviderName, true); + + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + responseCode = getRestTestHelper().submitRequest("groupprovider/" + groupProviderName, "DELETE"); + assertEquals("Group provider deletion should be allowed", 200, responseCode); + + assertGroupProviderExistence(groupProviderName, false); + } + + public void testSetGroupProviderAttributesAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String groupProviderName = getTestName(); + + assertGroupProviderExistence(groupProviderName, false); + + int responseCode = createGroupProvider(groupProviderName); + assertEquals("Group provider creation should be allowed", 201, responseCode); + + assertGroupProviderExistence(groupProviderName, true); + + Map attributes = new HashMap(); + attributes.put(GroupProvider.NAME, groupProviderName); + attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); + attributes.put(FileBasedGroupProvider.PATH, "/path/to/file"); + responseCode = getRestTestHelper().submitRequest("groupprovider/" + groupProviderName, "PUT", attributes); + assertEquals("Setting of group provider attributes should be allowed but not supported", 409, responseCode); + } + + public void testSetGroupProviderAttributesDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String groupProviderName = getTestName(); + + assertGroupProviderExistence(groupProviderName, false); + + int responseCode = createGroupProvider(groupProviderName); + assertEquals("Group provider creation should be allowed", 201, responseCode); + + assertGroupProviderExistence(groupProviderName, true); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + Map attributes = new HashMap(); + attributes.put(GroupProvider.NAME, groupProviderName); + attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); + attributes.put(FileBasedGroupProvider.PATH, "/path/to/file"); + responseCode = getRestTestHelper().submitRequest("groupprovider/" + groupProviderName, "PUT", attributes); + assertEquals("Setting of group provider attributes should be denied", 403, responseCode); + } + + /* === AccessControlProvider === */ + + public void testCreateAccessControlProviderAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String accessControlProviderName = getTestName(); + + assertAccessControlProviderExistence(accessControlProviderName, false); + + int responseCode = createAccessControlProvider(accessControlProviderName); + assertEquals("Access control provider creation should be allowed", 201, responseCode); + + assertAccessControlProviderExistence(accessControlProviderName, true); + } + + public void testCreateAccessControlProviderDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + String accessControlProviderName = getTestName(); + + assertAccessControlProviderExistence(accessControlProviderName, false); + + int responseCode = createAccessControlProvider(accessControlProviderName); + assertEquals("Access control provider creation should be denied", 403, responseCode); + + assertAccessControlProviderExistence(accessControlProviderName, false); + } + + public void testDeleteAccessControlProviderDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String accessControlProviderName = getTestName(); + + assertAccessControlProviderExistence(accessControlProviderName, false); + + int responseCode = createAccessControlProvider(accessControlProviderName); + assertEquals("Access control provider creation should be allowed", 201, responseCode); + + assertAccessControlProviderExistence(accessControlProviderName, true); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "DELETE"); + assertEquals("Access control provider deletion should be denied", 403, responseCode); + + assertAccessControlProviderExistence(accessControlProviderName, true); + } + + public void testDeleteAccessControlProviderAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String accessControlProviderName = getTestName(); + + assertAccessControlProviderExistence(accessControlProviderName, false); + + int responseCode = createAccessControlProvider(accessControlProviderName); + assertEquals("Access control provider creation should be allowed", 201, responseCode); + + assertAccessControlProviderExistence(accessControlProviderName, true); + + responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "DELETE"); + assertEquals("Access control provider deletion should be allowed", 200, responseCode); + + assertAccessControlProviderExistence(accessControlProviderName, false); + } + + public void testSetAccessControlProviderAttributesAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String accessControlProviderName = getTestName(); + + assertAccessControlProviderExistence(accessControlProviderName, false); + + int responseCode = createAccessControlProvider(accessControlProviderName); + assertEquals("Access control provider creation should be allowed", 201, responseCode); + + assertAccessControlProviderExistence(accessControlProviderName, true); + + Map attributes = new HashMap(); + attributes.put(GroupProvider.NAME, accessControlProviderName); + attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); + attributes.put(FileBasedGroupProvider.PATH, "/path/to/file"); + responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "PUT", attributes); + assertEquals("Setting of access control provider attributes should be allowed", 200, responseCode); + } + + public void testSetAccessControlProviderAttributesDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String accessControlProviderName = getTestName(); + + assertAccessControlProviderExistence(accessControlProviderName, false); + + int responseCode = createAccessControlProvider(accessControlProviderName); + assertEquals("Access control provider creation should be allowed", 201, responseCode); + + assertAccessControlProviderExistence(accessControlProviderName, true); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + Map attributes = new HashMap(); + attributes.put(GroupProvider.NAME, accessControlProviderName); + attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); + attributes.put(FileBasedGroupProvider.PATH, "/path/to/file"); + responseCode = getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "PUT", attributes); + assertEquals("Setting of access control provider attributes should be denied", 403, responseCode); + } + + /* === HTTP management === */ + + public void testSetHttpManagementAttributesAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + Map attributes = new HashMap(); + attributes.put(HttpManagement.NAME, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT); + attributes.put(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED, false); + attributes.put(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED, false); + attributes.put(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED, false); + attributes.put(HttpManagement.TIME_OUT, 10000); + + int responseCode = getRestTestHelper().submitRequest( + "plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, "PUT", attributes); + assertEquals("Setting of http management should be allowed", 200, responseCode); + + Map details = getRestTestHelper().getJsonAsSingletonList( + "plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT); + + assertEquals("Unexpected session timeout", 10000, details.get(HttpManagement.TIME_OUT)); + assertEquals("Unexpected http basic auth enabled", true, details.get(HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED)); + assertEquals("Unexpected https basic auth enabled", false, details.get(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED)); + assertEquals("Unexpected http sasl auth enabled", false, details.get(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED)); + assertEquals("Unexpected https sasl auth enabled", false, details.get(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED)); + } + + public void testSetHttpManagementAttributesDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + Map attributes = new HashMap(); + attributes.put(HttpManagement.NAME, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT); + attributes.put(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED, false); + attributes.put(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED, false); + attributes.put(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED, false); + attributes.put(HttpManagement.TIME_OUT, 10000); + + int responseCode = getRestTestHelper().submitRequest( + "plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, "PUT", attributes); + assertEquals("Setting of http management should be denied", 403, responseCode); + + Map details = getRestTestHelper().getJsonAsSingletonList( + "plugin/" + TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT); + + assertEquals("Unexpected session timeout", HttpManagement.DEFAULT_TIMEOUT_IN_SECONDS, + details.get(HttpManagement.TIME_OUT)); + assertEquals("Unexpected http basic auth enabled", true, + details.get(HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED)); + assertEquals("Unexpected https basic auth enabled", true, + details.get(HttpManagement.HTTPS_BASIC_AUTHENTICATION_ENABLED)); + assertEquals("Unexpected http sasl auth enabled", true, + details.get(HttpManagement.HTTP_SASL_AUTHENTICATION_ENABLED)); + assertEquals("Unexpected https sasl auth enabled", true, + details.get(HttpManagement.HTTPS_SASL_AUTHENTICATION_ENABLED)); + } + + /* === Utility Methods === */ + + private int createPort(String portName) throws Exception + { + Map attributes = new HashMap(); + attributes.put(Port.NAME, portName); + attributes.put(Port.PORT, findFreePort()); + attributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER); + + return getRestTestHelper().submitRequest("port/" + portName, "PUT", attributes); + } + + private void assertPortExists(String portName) throws Exception + { + assertPortExistence(portName, true); + } + + private void assertPortDoesNotExist(String portName) throws Exception + { + assertPortExistence(portName, false); + } + + private void assertPortExistence(String portName, boolean exists) throws Exception + { + List> hosts = getRestTestHelper().getJsonAsList("port/" + portName); + assertEquals("Unexpected result", exists, !hosts.isEmpty()); + } + + private void assertKeyStoreExistence(String keyStoreName, boolean exists) throws Exception + { + List> keyStores = getRestTestHelper().getJsonAsList("keystore/" + keyStoreName); + assertEquals("Unexpected result", exists, !keyStores.isEmpty()); + } + + private void assertTrustStoreExistence(String trustStoreName, boolean exists) throws Exception + { + List> trustStores = getRestTestHelper().getJsonAsList("truststore/" + trustStoreName); + assertEquals("Unexpected result", exists, !trustStores.isEmpty()); + } + + private int createAuthenticationProvider(String authenticationProviderName) throws Exception + { + Map attributes = new HashMap(); + attributes.put(AuthenticationProvider.NAME, authenticationProviderName); + attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManager.PROVIDER_TYPE); + + return getRestTestHelper().submitRequest("authenticationprovider/" + authenticationProviderName, "PUT", attributes); + } + + private void assertAuthenticationProviderDoesNotExist(String authenticationProviderName) throws Exception + { + assertAuthenticationProviderExistence(authenticationProviderName, false); + } + + private void assertAuthenticationProviderExists(String authenticationProviderName) throws Exception + { + assertAuthenticationProviderExistence(authenticationProviderName, true); + } + + private void assertAuthenticationProviderExistence(String authenticationProviderName, boolean exists) throws Exception + { + String path = "authenticationprovider/" + authenticationProviderName; + List> providers = getRestTestHelper().getJsonAsList(path); + assertEquals("Unexpected result", exists, !providers.isEmpty()); + } + + private int createKeyStore(String name, String certAlias) throws IOException, JsonGenerationException, JsonMappingException + { + Map keyStoreAttributes = new HashMap(); + keyStoreAttributes.put(KeyStore.NAME, name); + keyStoreAttributes.put(FileKeyStore.PATH, TestSSLConstants.KEYSTORE); + keyStoreAttributes.put(FileKeyStore.PASSWORD, TestSSLConstants.KEYSTORE_PASSWORD); + keyStoreAttributes.put(FileKeyStore.CERTIFICATE_ALIAS, certAlias); + + return getRestTestHelper().submitRequest("keystore/" + name, "PUT", keyStoreAttributes); + } + + private int createTrustStore(String name, boolean peersOnly) throws IOException, JsonGenerationException, JsonMappingException + { + Map trustStoreAttributes = new HashMap(); + trustStoreAttributes.put(TrustStore.NAME, name); + trustStoreAttributes.put(FileTrustStore.PATH, TestSSLConstants.KEYSTORE); + trustStoreAttributes.put(FileTrustStore.PASSWORD, TestSSLConstants.KEYSTORE_PASSWORD); + trustStoreAttributes.put(FileTrustStore.PEERS_ONLY, peersOnly); + + return getRestTestHelper().submitRequest("truststore/" + name, "PUT", trustStoreAttributes); + } + + private void assertGroupProviderExistence(String groupProviderName, boolean exists) throws Exception + { + String path = "groupprovider/" + groupProviderName; + List> providers = getRestTestHelper().getJsonAsList(path); + assertEquals("Unexpected result", exists, !providers.isEmpty()); + } + + private int createGroupProvider(String groupProviderName) throws Exception + { + File file = TestFileUtils.createTempFile(this, ".groups"); + Map attributes = new HashMap(); + attributes.put(GroupProvider.NAME, groupProviderName); + attributes.put(GroupProvider.TYPE, FileBasedGroupProviderImpl.GROUP_FILE_PROVIDER_TYPE); + attributes.put(FileBasedGroupProvider.PATH, file.getAbsoluteFile()); + + return getRestTestHelper().submitRequest("groupprovider/" + groupProviderName, "PUT", attributes); + } + + private void assertAccessControlProviderExistence(String accessControlProviderName, boolean exists) throws Exception + { + String path = "accesscontrolprovider/" + accessControlProviderName; + List> providers = getRestTestHelper().getJsonAsList(path); + assertEquals("Unexpected result", exists, !providers.isEmpty()); + } + + private int createAccessControlProvider(String accessControlProviderName) throws Exception + { + File file = TestFileUtils.createTempFile(this, ".acl", _secondaryAclFileContent); + Map attributes = new HashMap(); + attributes.put(AccessControlProvider.NAME, accessControlProviderName); + attributes.put(AccessControlProvider.TYPE, FileAccessControlProviderConstants.ACL_FILE_PROVIDER_TYPE); + attributes.put(FileAccessControlProviderConstants.PATH, file.getAbsoluteFile()); + + return getRestTestHelper().submitRequest("accesscontrolprovider/" + accessControlProviderName, "PUT", attributes); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/ExchangeRestACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/ExchangeRestACLTest.java new file mode 100644 index 0000000000..b0c66cb3af --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/ExchangeRestACLTest.java @@ -0,0 +1,244 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest.acl; + +import org.apache.qpid.server.management.plugin.HttpManagement; +import org.apache.qpid.server.model.Binding; +import org.apache.qpid.server.model.Exchange; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.security.acl.AbstractACLTestCase; +import org.apache.qpid.systest.rest.QpidRestTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.codehaus.jackson.JsonGenerationException; +import org.codehaus.jackson.map.JsonMappingException; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ExchangeRestACLTest extends QpidRestTestCase +{ + private static final String ALLOWED_USER = "user1"; + private static final String DENIED_USER = "user2"; + private String _queueName; + private String _exchangeName; + private String _exchangeUrl; + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER); + + AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", + "ACL ALLOW-LOG " + ALLOWED_USER + " CREATE QUEUE", + "ACL ALLOW-LOG " + ALLOWED_USER + " CREATE EXCHANGE", + "ACL DENY-LOG " + DENIED_USER + " CREATE EXCHANGE", + "ACL ALLOW-LOG " + ALLOWED_USER + " UPDATE EXCHANGE", + "ACL DENY-LOG " + DENIED_USER + " UPDATE EXCHANGE", + "ACL ALLOW-LOG " + ALLOWED_USER + " DELETE EXCHANGE", + "ACL DENY-LOG " + DENIED_USER + " DELETE EXCHANGE", + "ACL ALLOW-LOG " + ALLOWED_USER + " BIND EXCHANGE", + "ACL DENY-LOG " + DENIED_USER + " BIND EXCHANGE", + "ACL ALLOW-LOG " + ALLOWED_USER + " UNBIND EXCHANGE", + "ACL DENY-LOG " + DENIED_USER + " UNBIND EXCHANGE", + "ACL DENY-LOG ALL ALL"); + + getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, + HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); + } + + @Override + public void setUp() throws Exception + { + super.setUp(); + _queueName = getTestQueueName(); + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + Map queueData = new HashMap(); + queueData.put(Queue.NAME, _queueName); + queueData.put(Queue.DURABLE, Boolean.TRUE); + int status = getRestTestHelper().submitRequest("queue/test/test/" + _queueName, "PUT", queueData); + assertEquals("Unexpected status", 201, status); + + _exchangeName = getTestName(); + _exchangeUrl = "exchange/test/test/" + _exchangeName; + } + + public void testCreateExchangeAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + int responseCode = createExchange(); + assertEquals("Exchange creation should be allowed", 201, responseCode); + + assertExchangeExists(); + } + + public void testCreateExchangeDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + int responseCode = createExchange(); + assertEquals("Exchange creation should be denied", 403, responseCode); + + assertExchangeDoesNotExist(); + } + + public void testDeleteExchangeAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + int responseCode = createExchange(); + assertEquals("Exchange creation should be allowed", 201, responseCode); + + assertExchangeExists(); + + + responseCode = getRestTestHelper().submitRequest(_exchangeUrl, "DELETE"); + assertEquals("Exchange deletion should be allowed", 200, responseCode); + + assertExchangeDoesNotExist(); + } + + public void testDeleteExchangeDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + int responseCode = createExchange(); + assertEquals("Exchange creation should be allowed", 201, responseCode); + + assertExchangeExists(); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + responseCode = getRestTestHelper().submitRequest(_exchangeUrl, "DELETE"); + assertEquals("Exchange deletion should be denied", 403, responseCode); + + assertExchangeExists(); + } + + public void testSetExchangeAttributesAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + int responseCode = createExchange(); + + assertExchangeExists(); + + Map attributes = new HashMap(); + attributes.put(Exchange.NAME, _exchangeName); + attributes.put(Exchange.ALTERNATE_EXCHANGE, "my-alternate-exchange"); + + responseCode = getRestTestHelper().submitRequest(_exchangeUrl, "PUT", attributes); + assertEquals("Setting of exchange attribites should be allowed but it is currently unsupported", 409, responseCode); + } + + public void testSetExchangeAttributesDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + int responseCode = createExchange(); + assertExchangeExists(); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + Map attributes = new HashMap(); + attributes.put(Exchange.NAME, _exchangeName); + attributes.put(Exchange.ALTERNATE_EXCHANGE, "my-alternate-exchange"); + + responseCode = getRestTestHelper().submitRequest(_exchangeUrl, "PUT", attributes); + assertEquals("Setting of exchange attribites should be allowed", 403, responseCode); + } + + public void testBindToExchangeAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String bindingName = getTestName(); + int responseCode = createBinding(bindingName); + assertEquals("Binding creation should be allowed", 201, responseCode); + + assertBindingExists(bindingName); + } + + public void testBindToExchangeDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + String bindingName = getTestName(); + int responseCode = createBinding(bindingName); + assertEquals("Binding creation should be denied", 403, responseCode); + + assertBindingDoesNotExist(bindingName); + } + + private int createExchange() throws Exception + { + Map attributes = new HashMap(); + attributes.put(Exchange.NAME, _exchangeName); + attributes.put(Exchange.TYPE, "direct"); + return getRestTestHelper().submitRequest(_exchangeUrl, "PUT", attributes); + } + + private void assertExchangeDoesNotExist() throws Exception + { + assertExchangeExistence(false); + } + + private void assertExchangeExists() throws Exception + { + assertExchangeExistence(true); + } + + private void assertExchangeExistence(boolean exists) throws Exception + { + List> exchanges = getRestTestHelper().getJsonAsList(_exchangeUrl); + assertEquals("Unexpected result", exists, !exchanges.isEmpty()); + } + + private int createBinding(String bindingName) throws IOException, JsonGenerationException, JsonMappingException + { + Map attributes = new HashMap(); + attributes.put(Binding.NAME, bindingName); + attributes.put(Binding.QUEUE, _queueName); + attributes.put(Binding.EXCHANGE, "amq.direct"); + + int responseCode = getRestTestHelper().submitRequest("binding/test/test/amq.direct/" + _queueName + "/" + bindingName, "PUT", attributes); + return responseCode; + } + + private void assertBindingDoesNotExist(String bindingName) throws Exception + { + assertBindingExistence(bindingName, false); + } + + private void assertBindingExists(String bindingName) throws Exception + { + assertBindingExistence(bindingName, true); + } + + private void assertBindingExistence(String bindingName, boolean exists) throws Exception + { + List> bindings = getRestTestHelper().getJsonAsList("binding/test/test/amq.direct/" + _queueName + "/" + bindingName); + assertEquals("Unexpected result", exists, !bindings.isEmpty()); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java new file mode 100644 index 0000000000..3ebfafb8da --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java @@ -0,0 +1,193 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest.acl; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Map; +import java.util.Properties; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.qpid.server.management.plugin.HttpManagement; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.security.acl.AbstractACLTestCase; +import org.apache.qpid.systest.rest.QpidRestTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class GroupRestACLTest extends QpidRestTestCase +{ + private static final String FILE_GROUP_MANAGER = TestBrokerConfiguration.ENTRY_NAME_GROUP_FILE; + + private static final String ALLOWED_GROUP = "allowedGroup"; + private static final String DENIED_GROUP = "deniedGroup"; + private static final String OTHER_GROUP = "otherGroup"; + + private static final String ALLOWED_USER = "webadmin"; + private static final String DENIED_USER = "admin"; + private static final String OTHER_USER = "admin"; + + private File _groupFile; + + @Override + public void setUp() throws Exception + { + _groupFile = createTemporaryGroupFile(); + getBrokerConfiguration().addGroupFileConfiguration(_groupFile.getAbsolutePath()); + + //DONT call super.setUp(), the tests will start the broker after configuring it + } + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); + } + + @Override + public void tearDown() throws Exception + { + super.tearDown(); + + if (_groupFile != null) + { + if (_groupFile.exists()) + { + _groupFile.delete(); + } + } + } + + private File createTemporaryGroupFile() throws Exception + { + File groupFile = File.createTempFile("group", "grp"); + groupFile.deleteOnExit(); + + Properties props = new Properties(); + props.put(ALLOWED_GROUP + ".users", ALLOWED_USER); + props.put(DENIED_GROUP + ".users", DENIED_USER); + props.put(OTHER_GROUP + ".users", OTHER_USER); + + props.store(new FileOutputStream(groupFile), "test group file"); + + return groupFile; + } + + public void testCreateGroup() throws Exception + { + AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", + "ACL ALLOW-LOG " + ALLOWED_GROUP + " CREATE GROUP", + "ACL DENY-LOG " + DENIED_GROUP + " CREATE GROUP"); + + //Start the broker with the custom config + super.setUp(); + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + Map data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); + getRestTestHelper().assertNumberOfGroups(data, 3); + + getRestTestHelper().createGroup("newGroup", FILE_GROUP_MANAGER); + + data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); + getRestTestHelper().assertNumberOfGroups(data, 4); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + getRestTestHelper().createGroup("anotherNewGroup", FILE_GROUP_MANAGER, HttpServletResponse.SC_FORBIDDEN); + + data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); + getRestTestHelper().assertNumberOfGroups(data, 4); + } + + public void testDeleteGroup() throws Exception + { + AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", + "ACL ALLOW-LOG " + ALLOWED_GROUP + " DELETE GROUP", + "ACL DENY-LOG " + DENIED_GROUP + " DELETE GROUP"); + + //Start the broker with the custom config + super.setUp(); + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + Map data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); + getRestTestHelper().assertNumberOfGroups(data, 3); + + getRestTestHelper().removeGroup(OTHER_GROUP, FILE_GROUP_MANAGER, HttpServletResponse.SC_FORBIDDEN); + + data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); + getRestTestHelper().assertNumberOfGroups(data, 3); + + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + getRestTestHelper().removeGroup(OTHER_GROUP, FILE_GROUP_MANAGER); + + data = getRestTestHelper().getJsonAsSingletonList("groupprovider/" + FILE_GROUP_MANAGER); + getRestTestHelper().assertNumberOfGroups(data, 2); + } + + public void testUpdateGroupAddMember() throws Exception + { + AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", + "ACL ALLOW-LOG " + ALLOWED_GROUP + " UPDATE GROUP", + "ACL DENY-LOG " + DENIED_GROUP + " UPDATE GROUP"); + + //Start the broker with the custom config + super.setUp(); + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + assertNumberOfGroupMembers(OTHER_GROUP, 1); + + getRestTestHelper().createNewGroupMember(FILE_GROUP_MANAGER, OTHER_GROUP, "newGroupMember", HttpServletResponse.SC_FORBIDDEN); + assertNumberOfGroupMembers(OTHER_GROUP, 1); + + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + getRestTestHelper().createNewGroupMember(FILE_GROUP_MANAGER, OTHER_GROUP, "newGroupMember"); + assertNumberOfGroupMembers(OTHER_GROUP, 2); + } + + public void testUpdateGroupDeleteMember() throws Exception + { + AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", + "ACL ALLOW-LOG " + ALLOWED_GROUP + " UPDATE GROUP", + "ACL DENY-LOG " + DENIED_GROUP + " UPDATE GROUP"); + + //Start the broker with the custom config + super.setUp(); + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + assertNumberOfGroupMembers(OTHER_GROUP, 1); + + getRestTestHelper().removeMemberFromGroup(FILE_GROUP_MANAGER, OTHER_GROUP, OTHER_USER, HttpServletResponse.SC_FORBIDDEN); + assertNumberOfGroupMembers(OTHER_GROUP, 1); + + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + getRestTestHelper().removeMemberFromGroup(FILE_GROUP_MANAGER, OTHER_GROUP, OTHER_USER); + assertNumberOfGroupMembers(OTHER_GROUP, 0); + } + + private void assertNumberOfGroupMembers(String groupName, int expectedNumberOfMembers) throws IOException + { + Map group = getRestTestHelper().getJsonAsSingletonList("group/" + FILE_GROUP_MANAGER + "/" + groupName); + getRestTestHelper().assertNumberOfGroupMembers(group, expectedNumberOfMembers); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/LogViewerACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/LogViewerACLTest.java new file mode 100644 index 0000000000..1b14e3b10e --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/LogViewerACLTest.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.systest.rest.acl; + +import java.io.IOException; + +import org.apache.qpid.server.management.plugin.HttpManagement; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.security.acl.AbstractACLTestCase; +import org.apache.qpid.systest.rest.QpidRestTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class LogViewerACLTest extends QpidRestTestCase +{ + private static final String ALLOWED_USER = "user1"; + private static final String DENIED_USER = "user2"; + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER); + + AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", + "ACL ALLOW-LOG " + ALLOWED_USER + " ACCESS_LOGS BROKER", + "ACL DENY-LOG " + DENIED_USER + " ACCESS_LOGS BROKER", + "ACL DENY-LOG ALL ALL"); + + getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, + HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); + } + + public void testGetLogRecordsAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + int responseCode = getRestTestHelper().submitRequest("/service/logrecords", "GET"); + assertEquals("Access to log records should be allowed", 200, responseCode); + } + + public void testGetLogRecordsDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + int responseCode = getRestTestHelper().submitRequest("/service/logrecords", "GET"); + assertEquals("Access to log records should be denied", 403, responseCode); + } + + public void testGetLogFilesAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + int responseCode = getRestTestHelper().submitRequest("/service/logfilenames", "GET"); + assertEquals("Access to log files should be allowed", 200, responseCode); + } + + public void testGetLogFilesDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + int responseCode = getRestTestHelper().submitRequest("/service/logfilenames", "GET"); + assertEquals("Access to log files should be denied", 403, responseCode); + } + + public void testDownloadLogFileAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + int responseCode = getRestTestHelper().submitRequest("/service/logfile?l=appender%2fqpid.log", "GET"); + assertEquals("Access to log files should be allowed", 404, responseCode); + } + + public void testDownloadLogFileDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + int responseCode = getRestTestHelper().submitRequest("/service/logfile?l=appender%2fqpid.log", "GET"); + assertEquals("Access to log files should be denied", 403, responseCode); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/QueueRestACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/QueueRestACLTest.java new file mode 100644 index 0000000000..a123de2984 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/QueueRestACLTest.java @@ -0,0 +1,188 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest.acl; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.qpid.server.management.plugin.HttpManagement; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.security.acl.AbstractACLTestCase; +import org.apache.qpid.systest.rest.QpidRestTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class QueueRestACLTest extends QpidRestTestCase +{ + private static final String ALLOWED_USER = "user1"; + private static final String DENIED_USER = "user2"; + private String _queueUrl; + private String _queueName; + + @Override + public void setUp() throws Exception + { + super.setUp(); + _queueName = getTestName(); + _queueUrl = "queue/test/test/" + _queueName; + } + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER); + + AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", + "ACL ALLOW-LOG " + ALLOWED_USER + " CREATE QUEUE", + "ACL DENY-LOG " + DENIED_USER + " CREATE QUEUE", + "ACL ALLOW-LOG " + ALLOWED_USER + " UPDATE QUEUE", + "ACL DENY-LOG " + DENIED_USER + " UPDATE QUEUE", + "ACL ALLOW-LOG " + ALLOWED_USER + " DELETE QUEUE", + "ACL DENY-LOG " + DENIED_USER + " DELETE QUEUE", + "ACL DENY-LOG ALL ALL"); + + getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, + HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); + } + + public void testCreateQueueAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + int responseCode = createQueue(); + assertEquals("Queue creation should be allowed", 201, responseCode); + + assertQueueExists(); + } + + public void testCreateQueueDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + int responseCode = createQueue(); + assertEquals("Queue creation should be denied", 403, responseCode); + + assertQueueDoesNotExist(); + } + + public void testDeleteQueueAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + int responseCode = createQueue(); + assertEquals("Queue creation should be allowed", 201, responseCode); + + assertQueueExists(); + + responseCode = getRestTestHelper().submitRequest(_queueUrl, "DELETE"); + assertEquals("Queue deletion should be allowed", 200, responseCode); + + assertQueueDoesNotExist(); + } + + public void testDeleteQueueDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + int responseCode = createQueue(); + assertEquals("Queue creation should be allowed", 201, responseCode); + + assertQueueExists(); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + responseCode = getRestTestHelper().submitRequest(_queueUrl, "DELETE"); + assertEquals("Queue deletion should be denied", 403, responseCode); + + assertQueueExists(); + } + + + + public void testSetQueueAttributesAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + int responseCode = createQueue(); + + assertQueueExists(); + + Map attributes = new HashMap(); + attributes.put(Queue.NAME, _queueName); + attributes.put(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 100000); + attributes.put(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 80000); + + responseCode = getRestTestHelper().submitRequest(_queueUrl, "PUT", attributes); + assertEquals("Setting of queue attribites should be allowed", 200, responseCode); + + Map queueData = getRestTestHelper().getJsonAsSingletonList(_queueUrl); + assertEquals("Unexpected " + Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 100000, queueData.get(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES) ); + assertEquals("Unexpected " + Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 80000, queueData.get(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES) ); + } + + public void testSetQueueAttributesDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + int responseCode = createQueue(); + assertQueueExists(); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + Map attributes = new HashMap(); + attributes.put(Queue.NAME, _queueName); + attributes.put(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 100000); + attributes.put(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 80000); + + responseCode = getRestTestHelper().submitRequest(_queueUrl, "PUT", attributes); + assertEquals("Setting of queue attribites should be allowed", 403, responseCode); + + Map queueData = getRestTestHelper().getJsonAsSingletonList(_queueUrl); + assertEquals("Unexpected " + Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 0, queueData.get(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES) ); + assertEquals("Unexpected " + Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 0, queueData.get(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES) ); + } + + private int createQueue() throws Exception + { + Map attributes = new HashMap(); + attributes.put(Queue.NAME, _queueName); + + return getRestTestHelper().submitRequest(_queueUrl, "PUT", attributes); + } + + private void assertQueueDoesNotExist() throws Exception + { + assertQueueExistence(false); + } + + private void assertQueueExists() throws Exception + { + assertQueueExistence(true); + } + + private void assertQueueExistence(boolean exists) throws Exception + { + List> queues = getRestTestHelper().getJsonAsList(_queueUrl); + assertEquals("Unexpected result", exists, !queues.isEmpty()); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/UserPreferencesRestACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/UserPreferencesRestACLTest.java new file mode 100644 index 0000000000..b626b821c8 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/UserPreferencesRestACLTest.java @@ -0,0 +1,197 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest.acl; + +import java.io.File; +import java.io.IOException; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.qpid.server.management.plugin.HttpManagement; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.model.PreferencesProvider; +import org.apache.qpid.server.model.adapter.FileSystemPreferencesProvider; +import org.apache.qpid.server.security.acl.AbstractACLTestCase; +import org.apache.qpid.systest.rest.QpidRestTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.test.utils.TestFileUtils; + +public class UserPreferencesRestACLTest extends QpidRestTestCase +{ + + private static final String REST_USER_PREFERENCES_BASE_URL = "/service/userpreferences"; + private static final String ALLOWED_USER = "webadmin"; + private static final String DENIED_USER = "admin"; + private static final String TEST_USER_PREFERENCES_GET_URL = REST_USER_PREFERENCES_BASE_URL + "/" + + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/%s"; + + private File _preferencesProviderFile; + + public void setUp() throws Exception + { + _preferencesProviderFile = TestFileUtils.createTempFile(this, ".prefs.json", + "{\"webadmin\":{\"language\": \"en\", \"saveTabs\":true}," + " \"admin\":{\"language\": \"fr\", \"saveTabs\":false}" + + "}"); + super.setUp(); + } + + public void tearDown() throws Exception + { + try + { + super.tearDown(); + } + finally + { + if (_preferencesProviderFile != null) + { + _preferencesProviderFile.delete(); + } + } + } + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER); + + AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", "ACL ALLOW-LOG " + ALLOWED_USER + + " UPDATE USER", "ACL DENY-LOG " + DENIED_USER + " UPDATE USER", "ACL DENY-LOG ALL ALL"); + + TestBrokerConfiguration brokerConfiguration = getBrokerConfiguration(); + brokerConfiguration.setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, + HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); + + Map attributes = new HashMap(); + attributes.put(PreferencesProvider.NAME, "test"); + attributes.put(PreferencesProvider.TYPE, FileSystemPreferencesProvider.PROVIDER_TYPE); + attributes.put(FileSystemPreferencesProvider.PATH, _preferencesProviderFile.getAbsolutePath()); + brokerConfiguration + .addPreferencesProviderConfiguration(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, attributes); + } + + public void testListUsersWithPreferencesAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + List> users = getRestTestHelper().getJsonAsList(REST_USER_PREFERENCES_BASE_URL); + assertUsers(users); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + users = getRestTestHelper().getJsonAsList(REST_USER_PREFERENCES_BASE_URL); + assertUsers(users); + } + + public void testViewOtherUserPreferencesAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String userPreferencesUrl = String.format(TEST_USER_PREFERENCES_GET_URL, DENIED_USER); + Map preferences = getRestTestHelper().getJsonAsMap(userPreferencesUrl); + assertEquals("Unexpected number of preferences", 2, preferences.size()); + assertEquals("Unexpected language preference", "fr", preferences.get("language")); + assertEquals("Unexpected saveTabs preference", false, preferences.get("saveTabs")); + } + + public void testViewOtherUserPreferencesDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + int responseCode = getRestTestHelper().submitRequest( + "/service/userpreferences?user=" + + URLEncoder.encode(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + ALLOWED_USER, "UTF-8"), + "DELETE"); + assertEquals("Preferences deletion should be denied", 403, responseCode); + } + + public void testDeleteOtherUserPreferencesAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String userPreferencesUrl = String.format(TEST_USER_PREFERENCES_GET_URL, DENIED_USER); + Map preferences = getRestTestHelper().getJsonAsMap(userPreferencesUrl); + assertEquals("Unexpected number of preferences", 2, preferences.size()); + assertEquals("Unexpected language preference", "fr", preferences.get("language")); + assertEquals("Unexpected saveTabs preference", false, preferences.get("saveTabs")); + + int responseCode = getRestTestHelper().submitRequest( + "/service/userpreferences?user=" + + URLEncoder.encode(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + DENIED_USER, "UTF-8"), + "DELETE"); + assertEquals("Preferences deletion should be allowed", 200, responseCode); + + preferences = getRestTestHelper().getJsonAsMap(userPreferencesUrl); + assertEquals("Unexpected number of preferences after deletion", 0, preferences.size()); + } + + public void testDeleteOtherUserPreferencesDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String userPreferencesUrl = String.format(TEST_USER_PREFERENCES_GET_URL, ALLOWED_USER); + Map preferences = getRestTestHelper().getJsonAsMap(userPreferencesUrl); + assertEquals("Unexpected number of preferences", 2, preferences.size()); + assertEquals("Unexpected language preference", "en", preferences.get("language")); + assertEquals("Unexpected saveTabs preference", true, preferences.get("saveTabs")); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + int responseCode = getRestTestHelper().submitRequest( + "/service/userpreferences?user=" + + URLEncoder.encode(TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + ALLOWED_USER, "UTF-8"), + "DELETE"); + assertEquals("Preferences deletion should be denied", 403, responseCode); + + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + preferences = getRestTestHelper().getJsonAsMap(userPreferencesUrl); + assertEquals("Unexpected number of preferences after deletion", 2, preferences.size()); + } + + + private void assertUsers(List> users) + { + assertEquals("Unexpected number of users", 2, users.size()); + Map webadmin = findUser("webadmin", users); + assertEquals("Unexpected name", "webadmin", webadmin.get("name")); + assertEquals("Unexpected authentication provider", TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, webadmin.get("authenticationProvider")); + Map admin = findUser("admin", users); + assertEquals("Unexpected name", "admin", admin.get("name")); + assertEquals("Unexpected authentication provider", TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, admin.get("authenticationProvider")); + } + + private Map findUser(String name, List> users) + { + for (Map user : users) + { + if (name.equals(user.get("name"))) + { + return user; + } + } + return null; + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java new file mode 100644 index 0000000000..d80c8e14b2 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest.acl; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import javax.servlet.http.HttpServletResponse; + +import org.codehaus.jackson.JsonParseException; +import org.codehaus.jackson.map.JsonMappingException; + +import org.apache.qpid.server.management.plugin.HttpManagement; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.security.acl.AbstractACLTestCase; +import org.apache.qpid.systest.rest.QpidRestTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class UserRestACLTest extends QpidRestTestCase +{ + private static final String ALLOWED_GROUP = "allowedGroup"; + private static final String DENIED_GROUP = "deniedGroup"; + private static final String OTHER_GROUP = "otherGroup"; + + private static final String ALLOWED_USER = "webadmin"; + private static final String DENIED_USER = "admin"; + private static final String OTHER_USER = "other"; + + private File _groupFile; + + @Override + public void setUp() throws Exception + { + _groupFile = createTemporaryGroupFile(); + getBrokerConfiguration().addGroupFileConfiguration(_groupFile.getAbsolutePath()); + + getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER, OTHER_USER); + + //DONT call super.setUp(), the tests will start the broker after configuring it + } + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); + } + + @Override + public void tearDown() throws Exception + { + super.tearDown(); + + if (_groupFile != null) + { + if (_groupFile.exists()) + { + _groupFile.delete(); + } + } + } + + private File createTemporaryGroupFile() throws Exception + { + File groupFile = File.createTempFile("group", "grp"); + groupFile.deleteOnExit(); + + Properties props = new Properties(); + props.put(ALLOWED_GROUP + ".users", ALLOWED_USER); + props.put(DENIED_GROUP + ".users", DENIED_USER); + props.put(OTHER_GROUP + ".users", OTHER_USER); + + props.store(new FileOutputStream(groupFile), "test group file"); + + return groupFile; + } + + public void testAddUser() throws Exception + { + AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", + "ACL ALLOW-LOG " + ALLOWED_GROUP + " CREATE USER", + "ACL DENY-LOG " + DENIED_GROUP + " CREATE USER"); + + //Start the broker with the custom config + super.setUp(); + + String newUser = "newUser"; + String password = "password"; + + assertUserDoesNotExist(newUser); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + getRestTestHelper().createOrUpdateUser(newUser, password, HttpServletResponse.SC_FORBIDDEN); + assertUserDoesNotExist(newUser); + + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + getRestTestHelper().createOrUpdateUser(newUser, password); + assertUserExists(newUser); + } + + public void testDeleteUser() throws Exception + { + AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", + "ACL ALLOW-LOG " + ALLOWED_GROUP + " DELETE USER", + "ACL DENY-LOG " + DENIED_GROUP + " DELETE USER"); + + //Start the broker with the custom config + super.setUp(); + + assertUserExists(OTHER_USER); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + getRestTestHelper().removeUser(OTHER_USER, HttpServletResponse.SC_FORBIDDEN); + assertUserExists(OTHER_USER); + + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + getRestTestHelper().removeUser(OTHER_USER); + assertUserDoesNotExist(OTHER_USER); + } + + public void testUpdateUser() throws Exception + { + AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", + "ACL ALLOW-LOG " + ALLOWED_GROUP + " UPDATE USER", + "ACL DENY-LOG " + DENIED_GROUP + " UPDATE USER"); + + //Start the broker with the custom config + super.setUp(); + + String newPassword = "newPassword"; + + checkPassword(OTHER_USER, OTHER_USER, true); + + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + getRestTestHelper().createOrUpdateUser(OTHER_USER, newPassword, HttpServletResponse.SC_FORBIDDEN); + + checkPassword(OTHER_USER, newPassword, false); + + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + getRestTestHelper().createOrUpdateUser(OTHER_USER, newPassword, HttpServletResponse.SC_OK); // expect SC_OK rather than the default SC_CREATED + + checkPassword(OTHER_USER, newPassword, true); + checkPassword(OTHER_USER, OTHER_USER, false); + } + + private void checkPassword(String username, String password, boolean passwordExpectedToBeCorrect) throws IOException + { + getRestTestHelper().setUsernameAndPassword(username, password); + + int responseCode = getRestTestHelper().submitRequest("user/" + + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/", "GET", (byte[])null); + boolean passwordIsCorrect = responseCode == HttpServletResponse.SC_OK; + + assertEquals(passwordExpectedToBeCorrect, passwordIsCorrect); + } + + private void assertUserDoesNotExist(String newUser) throws JsonParseException, JsonMappingException, IOException + { + String path = "user/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + newUser; + List> userDetailsList = getRestTestHelper().getJsonAsList(path); + assertTrue(userDetailsList.isEmpty()); + } + + private void assertUserExists(String username) throws IOException + { + String path = "user/" + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER + "/" + username; + Map userDetails = getRestTestHelper().getJsonAsSingletonList(path); + + assertEquals( + "User returned by " + path + " should have name=" + username + ". The returned JSON was: " + userDetails, + username, + userDetails.get("name")); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/VirtualHostACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/VirtualHostACLTest.java new file mode 100644 index 0000000000..45123325e3 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/VirtualHostACLTest.java @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest.acl; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.qpid.server.management.plugin.HttpManagement; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.model.VirtualHostNode; +import org.apache.qpid.server.security.acl.AbstractACLTestCase; +import org.apache.qpid.server.virtualhost.ProvidedStoreVirtualHostImpl; +import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNode; +import org.apache.qpid.systest.rest.QpidRestTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class VirtualHostACLTest extends QpidRestTestCase +{ + private static final String VHN_WITHOUT_VH = "myVhnWithoutVh"; + + private static final String ALLOWED_USER = "user1"; + private static final String DENIED_USER = "user2"; + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER); + + AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", + "ACL ALLOW-LOG " + ALLOWED_USER + " ALL VIRTUALHOST", + "ACL DENY-LOG " + DENIED_USER + " ALL VIRTUALHOST", + "ACL DENY-LOG ALL ALL"); + + getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, + HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); + + Map virtualHostNodeAttributes = new HashMap<>(); + virtualHostNodeAttributes.put(VirtualHostNode.NAME, VHN_WITHOUT_VH); + virtualHostNodeAttributes.put(VirtualHostNode.TYPE, getTestProfileVirtualHostNodeType()); + // TODO need better way to determine the VHN's optional attributes + virtualHostNodeAttributes.put(JsonVirtualHostNode.STORE_PATH, getStoreLocation(VHN_WITHOUT_VH)); + + getBrokerConfiguration().addObjectConfiguration(VirtualHostNode.class, virtualHostNodeAttributes); + } + + public void testCreateVirtualHostAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String hostName = getTestName(); + + int responseCode = createVirtualHost(VHN_WITHOUT_VH, hostName); + assertEquals("Virtual host creation should be allowed", HttpServletResponse.SC_CREATED, responseCode); + + assertVirtualHostExists(VHN_WITHOUT_VH, hostName); + } + + public void testCreateVirtualHostDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + String hostName = getTestName(); + + int responseCode = createVirtualHost(VHN_WITHOUT_VH, hostName); + assertEquals("Virtual host creation should be denied", HttpServletResponse.SC_FORBIDDEN, responseCode); + + assertVirtualHostDoesNotExist(VHN_WITHOUT_VH, hostName); + } + + public void testDeleteVirtualHostDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + getRestTestHelper().submitRequest("virtualhost/" + TEST2_VIRTUALHOST + "/" + TEST2_VIRTUALHOST, "DELETE", HttpServletResponse.SC_FORBIDDEN); + + assertVirtualHostExists(TEST2_VIRTUALHOST, TEST2_VIRTUALHOST); + } + + public void testUpdateVirtualHostDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + Map attributes = new HashMap<>(); + attributes.put(VirtualHost.NAME, TEST2_VIRTUALHOST); + attributes.put(VirtualHost.DESCRIPTION, "new description"); + + getRestTestHelper().submitRequest("virtualhost/" + TEST2_VIRTUALHOST + "/" + TEST2_VIRTUALHOST, "PUT", attributes, HttpServletResponse.SC_FORBIDDEN); + } + + /* === Utility Methods === */ + + private int createVirtualHost(final String testVirtualHostNode, String virtualHostName) throws Exception + { + Map data = new HashMap<>(); + data.put(VirtualHost.NAME, virtualHostName); + data.put(VirtualHost.TYPE, ProvidedStoreVirtualHostImpl.VIRTUAL_HOST_TYPE); + + return getRestTestHelper().submitRequest("virtualhost/" + testVirtualHostNode + "/" + virtualHostName, "PUT", data); + } + + private void assertVirtualHostDoesNotExist(final String virtualHostNodeName, String virtualHostName) throws Exception + { + assertVirtualHostExistence(virtualHostNodeName, virtualHostName, false); + } + + private void assertVirtualHostExists(final String virtualHostNodeName, String virtualHostName) throws Exception + { + assertVirtualHostExistence(virtualHostNodeName, virtualHostName, true); + } + + private void assertVirtualHostExistence(final String virtualHostNodeName, String virtualHostName, boolean exists) throws Exception + { + List> hosts = getRestTestHelper().getJsonAsList("virtualhost/" + virtualHostNodeName + "/" + virtualHostName); + assertEquals("Node " + virtualHostName + (exists ? " does not exist" : " exists"), exists, !hosts.isEmpty()); + } + + private String getStoreLocation(String hostName) + { + return new File(TMP_FOLDER, "store-" + hostName + "-" + System.currentTimeMillis()).getAbsolutePath(); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/VirtualHostNodeACLTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/VirtualHostNodeACLTest.java new file mode 100644 index 0000000000..4809962f24 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/systest/rest/acl/VirtualHostNodeACLTest.java @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.rest.acl; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.codehaus.jackson.JsonGenerationException; +import org.codehaus.jackson.map.JsonMappingException; + +import org.apache.qpid.server.management.plugin.HttpManagement; +import org.apache.qpid.server.model.AccessControlProvider; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ExternalFileBasedAuthenticationManager; +import org.apache.qpid.server.model.GroupProvider; +import org.apache.qpid.server.model.KeyStore; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.model.TrustStore; +import org.apache.qpid.server.model.VirtualHostNode; +import org.apache.qpid.server.model.adapter.FileBasedGroupProvider; +import org.apache.qpid.server.model.adapter.FileBasedGroupProviderImpl; +import org.apache.qpid.server.security.FileKeyStore; +import org.apache.qpid.server.security.FileTrustStore; +import org.apache.qpid.server.security.access.FileAccessControlProviderConstants; +import org.apache.qpid.server.security.acl.AbstractACLTestCase; +import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager; +import org.apache.qpid.server.security.auth.manager.PlainPasswordDatabaseAuthenticationManager; +import org.apache.qpid.server.virtualhost.memory.MemoryVirtualHost; +import org.apache.qpid.server.virtualhostnode.JsonVirtualHostNode; +import org.apache.qpid.systest.rest.QpidRestTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; +import org.apache.qpid.test.utils.TestFileUtils; +import org.apache.qpid.test.utils.TestSSLConstants; + +public class VirtualHostNodeACLTest extends QpidRestTestCase +{ + private static final String TEST_VIRTUAL_HOST_NODE = "myTestVirtualHostNode"; + private static final String ALLOWED_USER = "user1"; + private static final String DENIED_USER = "user2"; + + @Override + protected void customizeConfiguration() throws IOException + { + super.customizeConfiguration(); + getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER); + + AbstractACLTestCase.writeACLFileUtil(this, "ACL ALLOW-LOG ALL ACCESS MANAGEMENT", + "ACL ALLOW-LOG " + ALLOWED_USER + " ALL VIRTUALHOSTNODE", + "ACL DENY-LOG " + DENIED_USER + " ALL VIRTUALHOSTNODE", + "ACL DENY-LOG ALL ALL"); + + getBrokerConfiguration().setObjectAttribute(Plugin.class, TestBrokerConfiguration.ENTRY_NAME_HTTP_MANAGEMENT, + HttpManagement.HTTP_BASIC_AUTHENTICATION_ENABLED, true); + + Map virtualHostNodeAttributes = new HashMap<>(); + virtualHostNodeAttributes.put(VirtualHostNode.NAME, TEST_VIRTUAL_HOST_NODE); + virtualHostNodeAttributes.put(VirtualHostNode.TYPE, getTestProfileVirtualHostNodeType()); + // TODO need better way to determine the VHN's optional attributes + virtualHostNodeAttributes.put(JsonVirtualHostNode.STORE_PATH, getStoreLocation(TEST_VIRTUAL_HOST_NODE)); + + + getBrokerConfiguration().addObjectConfiguration(VirtualHostNode.class, virtualHostNodeAttributes); + } + + public void testCreateVirtualHostNodeAllowed() throws Exception + { + getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER); + + String hostName = getTestName(); + + int responseCode = createVirtualHostNode(hostName); + assertEquals("Virtual host node creation should be allowed", HttpServletResponse.SC_CREATED, responseCode); + + assertVirtualHostNodeExists(hostName); + } + + public void testCreateVirtualHostNodeDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + + String hostName = getTestName(); + + int responseCode = createVirtualHostNode(hostName); + assertEquals("Virtual host node creation should be denied", HttpServletResponse.SC_FORBIDDEN, responseCode); + + assertVirtualHostNodeDoesNotExist(hostName); + } + + public void testDeleteVirtualHostNodeDenied() throws Exception + { + getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER); + getRestTestHelper().submitRequest("virtualhostnode/" + TEST_VIRTUAL_HOST_NODE, "DELETE", HttpServletResponse.SC_FORBIDDEN); + + assertVirtualHostNodeExists(TEST_VIRTUAL_HOST_NODE); + } + + /* === Utility Methods === */ + + private int createVirtualHostNode(String virtualHostNodeName) throws Exception + { + Map data = new HashMap<>(); + data.put(VirtualHostNode.NAME, virtualHostNodeName); + data.put(VirtualHostNode.TYPE, getTestProfileVirtualHostNodeType()); + data.put(JsonVirtualHostNode.STORE_PATH, getStoreLocation(virtualHostNodeName)); + + return getRestTestHelper().submitRequest("virtualhostnode/" + virtualHostNodeName, "PUT", data); + } + + private void assertVirtualHostNodeDoesNotExist(String name) throws Exception + { + assertVirtualHostNodeExistence(name, false); + } + + private void assertVirtualHostNodeExists(String name) throws Exception + { + assertVirtualHostNodeExistence(name, true); + } + + private void assertVirtualHostNodeExistence(String name, boolean exists) throws Exception + { + List> hosts = getRestTestHelper().getJsonAsList("virtualhostnode/" + name); + assertEquals("Node " + name + (exists ? " does not exist" : " exists"), exists, !hosts.isEmpty()); + } + + private String getStoreLocation(String hostName) + { + return new File(TMP_FOLDER, "store-" + hostName + "-" + System.currentTimeMillis()).getAbsolutePath(); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/CloseOnNoRouteForMandatoryMessageTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/CloseOnNoRouteForMandatoryMessageTest.java new file mode 100644 index 0000000000..deb8e4f12b --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/CloseOnNoRouteForMandatoryMessageTest.java @@ -0,0 +1,241 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.test.client; + +import java.util.HashMap; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.IllegalStateException; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.naming.NamingException; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.jms.ConnectionURL; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.url.URLSyntaxException; + +/** + * Tests the broker's connection-closing behaviour when it receives an unroutable message + * on a transactional session. + * + * @see ImmediateAndMandatoryPublishingTest for more general tests of mandatory and immediate publishing + */ +public class CloseOnNoRouteForMandatoryMessageTest extends QpidBrokerTestCase +{ + private static final Logger _logger = Logger.getLogger(CloseOnNoRouteForMandatoryMessageTest.class); + + private Connection _connection; + private UnroutableMessageTestExceptionListener _testExceptionListener = new UnroutableMessageTestExceptionListener(); + + @Override + public void setUp() throws Exception + { + super.setUp(); + } + + public void testNoRoute_brokerClosesConnection() throws Exception + { + createConnectionWithCloseWhenNoRoute(true); + + Session transactedSession = _connection.createSession(true, Session.SESSION_TRANSACTED); + String testQueueName = getTestQueueName(); + MessageProducer mandatoryProducer = ((AMQSession) transactedSession).createProducer( + transactedSession.createQueue(testQueueName), + true, // mandatory + false); // immediate + + Message message = transactedSession.createMessage(); + mandatoryProducer.send(message); + try + { + transactedSession.commit(); + fail("Expected exception not thrown"); + } + catch (IllegalStateException ise) + { + _logger.debug("Caught exception", ise); + //The session was marked closed even before we had a chance to call commit on it + assertTrue("ISE did not indicate closure", ise.getMessage().contains("closed")); + } + catch(JMSException e) + { + _logger.debug("Caught exception", e); + _testExceptionListener.assertNoRoute(e, testQueueName); + } + _testExceptionListener.assertReceivedNoRoute(testQueueName); + + forgetConnection(_connection); + } + + public void testCloseOnNoRouteWhenExceptionMessageLengthIsGreater255() throws Exception + { + createConnectionWithCloseWhenNoRoute(true); + + AMQSession transactedSession = (AMQSession) _connection.createSession(true, Session.SESSION_TRANSACTED); + + StringBuilder longExchangeName = getLongExchangeName(); + + AMQShortString exchangeName = new AMQShortString(longExchangeName.toString()); + transactedSession.declareExchange(exchangeName, new AMQShortString("direct"), false); + + Destination testQueue = new AMQQueue(exchangeName, getTestQueueName()); + MessageProducer mandatoryProducer = transactedSession.createProducer( + testQueue, + true, // mandatory + false); // immediate + + Message message = transactedSession.createMessage(); + mandatoryProducer.send(message); + try + { + transactedSession.commit(); + fail("Expected exception not thrown"); + } + catch (IllegalStateException ise) + { + _logger.debug("Caught exception", ise); + //The session was marked closed even before we had a chance to call commit on it + assertTrue("ISE did not indicate closure", ise.getMessage().contains("closed")); + } + catch (JMSException e) + { + _logger.debug("Caught exception", e); + AMQException noRouteException = (AMQException) e.getLinkedException(); + assertNotNull("AMQException should be linked to JMSException", noRouteException); + + assertEquals(AMQConstant.NO_ROUTE, noRouteException.getErrorCode()); + String expectedMessage = "Error: No route for message [Exchange: " + longExchangeName.substring(0, 220) + "..."; + assertEquals("Unexpected exception message: " + noRouteException.getMessage(), expectedMessage, + noRouteException.getMessage()); + } + finally + { + forgetConnection(_connection); + } + } + + public void testNoRouteMessageReurnedWhenExceptionMessageLengthIsGreater255() throws Exception + { + createConnectionWithCloseWhenNoRoute(false); + + AMQSession transactedSession = (AMQSession) _connection.createSession(true, Session.SESSION_TRANSACTED); + + StringBuilder longExchangeName = getLongExchangeName(); + + AMQShortString exchangeName = new AMQShortString(longExchangeName.toString()); + transactedSession.declareExchange(exchangeName, new AMQShortString("direct"), false); + + AMQQueue testQueue = new AMQQueue(exchangeName, getTestQueueName()); + MessageProducer mandatoryProducer = transactedSession.createProducer( + testQueue, + true, // mandatory + false); // immediate + + Message message = transactedSession.createMessage(); + mandatoryProducer.send(message); + transactedSession.commit(); + _testExceptionListener.assertReceivedReturnedMessageWithLongExceptionMessage(message, testQueue); + } + + private StringBuilder getLongExchangeName() + { + StringBuilder longExchangeName = new StringBuilder(); + for (int i = 0; i < 50; i++) + { + longExchangeName.append("abcde"); + } + return longExchangeName; + } + + public void testNoRouteForNonMandatoryMessage_brokerKeepsConnectionOpenAndCallsExceptionListener() throws Exception + { + createConnectionWithCloseWhenNoRoute(true); + + Session transactedSession = _connection.createSession(true, Session.SESSION_TRANSACTED); + String testQueueName = getTestQueueName(); + MessageProducer nonMandatoryProducer = ((AMQSession) transactedSession).createProducer( + transactedSession.createQueue(testQueueName), + false, // mandatory + false); // immediate + + Message message = transactedSession.createMessage(); + nonMandatoryProducer.send(message); + + // should succeed - the message is simply discarded + transactedSession.commit(); + + _testExceptionListener.assertNoException(); + } + + + public void testNoRouteOnNonTransactionalSession_brokerKeepsConnectionOpenAndCallsExceptionListener() throws Exception + { + createConnectionWithCloseWhenNoRoute(true); + + Session nonTransactedSession = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + String testQueueName = getTestQueueName(); + MessageProducer mandatoryProducer = ((AMQSession) nonTransactedSession).createProducer( + nonTransactedSession.createQueue(testQueueName), + true, // mandatory + false); // immediate + + Message message = nonTransactedSession.createMessage(); + mandatoryProducer.send(message); + + // should succeed - the message is asynchronously bounced back to the exception listener + message.acknowledge(); + + _testExceptionListener.assertReceivedNoRouteWithReturnedMessage(message, getTestQueueName()); + } + + public void testClientDisablesCloseOnNoRoute_brokerKeepsConnectionOpenAndCallsExceptionListener() throws Exception + { + createConnectionWithCloseWhenNoRoute(false); + + Session transactedSession = _connection.createSession(true, Session.SESSION_TRANSACTED); + String testQueueName = getTestQueueName(); + MessageProducer mandatoryProducer = ((AMQSession) transactedSession).createProducer( + transactedSession.createQueue(testQueueName), + true, // mandatory + false); // immediate + + Message message = transactedSession.createMessage(); + mandatoryProducer.send(message); + transactedSession.commit(); + _testExceptionListener.assertReceivedNoRouteWithReturnedMessage(message, getTestQueueName()); + } + + private void createConnectionWithCloseWhenNoRoute(boolean closeWhenNoRoute) throws URLSyntaxException, NamingException, JMSException + { + Map options = new HashMap(); + options.put(ConnectionURL.OPTIONS_CLOSE_WHEN_NO_ROUTE, Boolean.toString(closeWhenNoRoute)); + _connection = getConnectionWithOptions(options); + _connection.setExceptionListener(_testExceptionListener); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/DupsOkTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/DupsOkTest.java new file mode 100644 index 0000000000..fa36d73283 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/DupsOkTest.java @@ -0,0 +1,167 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.client; + +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +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 java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + + +public class DupsOkTest extends QpidBrokerTestCase +{ + + private Queue _queue; + private static final int MSG_COUNT = 100; + private CountDownLatch _awaitCompletion = new CountDownLatch(1); + + public void setUp() throws Exception + { + super.setUp(); + + _queue = (Queue) getInitialContext().lookup("queue"); + + + //Declare the queue + Connection consumerConnection = getConnection(); + consumerConnection.createSession(false,Session.AUTO_ACKNOWLEDGE).createConsumer(_queue).close(); + + //Create Producer put some messages on the queue + Connection producerConnection = getConnection(); + + producerConnection.start(); + + Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer producer = producerSession.createProducer(_queue); + + for (int count = 1; count <= MSG_COUNT; count++) + { + Message msg = producerSession.createTextMessage("Message " + count); + msg.setIntProperty("count", count); + producer.send(msg); + } + + producerConnection.close(); + } + + /** + * This test sends x messages and receives them with an async consumer. + * Waits for all messages to be received or for 60 s + * and checks whether the queue is empty. + * + * @throws Exception + */ + public void testDupsOK() throws Exception + { + //Create Client + Connection clientConnection = getConnection(); + + final Session clientSession = clientConnection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE); + + MessageConsumer consumer = clientSession.createConsumer(_queue); + + assertEquals("The queue should have msgs at start", MSG_COUNT, ((AMQSession) clientSession).getQueueDepth((AMQDestination) _queue)); + + clientConnection.start(); + + consumer.setMessageListener(new MessageListener() + { + private int _msgCount = 0; + + public void onMessage(Message message) + { + _msgCount++; + if (message == null) + { + fail("Should not get null messages"); + } + + if (message instanceof TextMessage) + { + try + { + if (message.getIntProperty("count") == MSG_COUNT) + { + try + { + if(_msgCount != MSG_COUNT) + { + assertEquals("Wrong number of messages seen.", MSG_COUNT, _msgCount); + } + } + finally + { + //This is the last message so release test. + _awaitCompletion.countDown(); + } + } + } + catch (JMSException e) + { + fail("Unable to get int property 'count'"); + } + } + else + { + fail("Got wrong message type"); + } + } + }); + + try + { + if (!_awaitCompletion.await(120, TimeUnit.SECONDS)) + { + fail("Test did not complete in 120 seconds"); + } + } + catch (InterruptedException e) + { + fail("Unable to wait for test completion"); + throw e; + } + + //Close consumer to give broker time to process in bound Acks. As The main thread will be released while + // before the dispatcher has sent the ack back to the broker. + consumer.close(); + + clientSession.close(); + + final Session clientSession2 = clientConnection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE); + + assertEquals("The queue should have 0 msgs left", 0, ((AMQSession) clientSession2).getQueueDepth((AMQDestination) _queue)); + + clientConnection.close(); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/FlowControlTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/FlowControlTest.java new file mode 100644 index 0000000000..f8bc051be7 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/FlowControlTest.java @@ -0,0 +1,220 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.test.client; + +import org.apache.log4j.Logger; + +import org.apache.qpid.client.AMQSession_0_8; +import org.apache.qpid.client.message.AbstractJMSMessage; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +public class FlowControlTest extends QpidBrokerTestCase +{ + private static final Logger _logger = Logger.getLogger(FlowControlTest.class); + + private Connection _clientConnection; + private Session _clientSession; + private Queue _queue; + + /** + * Simply + * + * @throws Exception + */ + public void testBasicBytesFlowControl() throws Exception + { + _queue = (Queue) getInitialContext().lookup("queue"); + + //Create Client + _clientConnection = getConnection(); + + _clientConnection.start(); + + _clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + //Ensure _queue is created + _clientSession.createConsumer(_queue).close(); + + Connection producerConnection = getConnection(); + + producerConnection.start(); + + Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = producerSession.createProducer(_queue); + + BytesMessage m1 = producerSession.createBytesMessage(); + m1.writeBytes(new byte[128]); + m1.setIntProperty("msg", 1); + producer.send(m1); + BytesMessage m2 = producerSession.createBytesMessage(); + m2.writeBytes(new byte[128]); + m2.setIntProperty("msg", 2); + producer.send(m2); + BytesMessage m3 = producerSession.createBytesMessage(); + m3.writeBytes(new byte[256]); + m3.setIntProperty("msg", 3); + producer.send(m3); + + producer.close(); + producerSession.close(); + producerConnection.close(); + + Connection consumerConnection = getConnection(); + Session consumerSession = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + ((AMQSession_0_8) consumerSession).setPrefetchLimits(0, 256); + MessageConsumer recv = consumerSession.createConsumer(_queue); + consumerConnection.start(); + + Message r1 = recv.receive(RECEIVE_TIMEOUT); + assertNotNull("First message not received", r1); + assertEquals("Messages in wrong order", 1, r1.getIntProperty("msg")); + + Message r2 = recv.receive(RECEIVE_TIMEOUT); + assertNotNull("Second message not received", r2); + assertEquals("Messages in wrong order", 2, r2.getIntProperty("msg")); + + Message r3 = recv.receive(RECEIVE_TIMEOUT); + assertNull("Third message incorrectly delivered", r3); + + ((AbstractJMSMessage)r1).acknowledgeThis(); + + r3 = recv.receive(RECEIVE_TIMEOUT); + assertNull("Third message incorrectly delivered", r3); + + ((AbstractJMSMessage)r2).acknowledgeThis(); + + r3 = recv.receive(RECEIVE_TIMEOUT); + assertNotNull("Third message not received", r3); + assertEquals("Messages in wrong order", 3, r3.getIntProperty("msg")); + + ((AbstractJMSMessage)r3).acknowledgeThis(); + consumerConnection.close(); + } + + public void testTwoConsumersBytesFlowControl() throws Exception + { + _queue = (Queue) getInitialContext().lookup("queue"); + + //Create Client + _clientConnection = getConnection(); + + _clientConnection.start(); + + _clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + //Ensure _queue is created + _clientSession.createConsumer(_queue).close(); + + Connection producerConnection = getConnection(); + + producerConnection.start(); + + Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = producerSession.createProducer(_queue); + + BytesMessage m1 = producerSession.createBytesMessage(); + m1.writeBytes(new byte[128]); + m1.setIntProperty("msg", 1); + producer.send(m1); + BytesMessage m2 = producerSession.createBytesMessage(); + m2.writeBytes(new byte[256]); + m2.setIntProperty("msg", 2); + producer.send(m2); + BytesMessage m3 = producerSession.createBytesMessage(); + m3.writeBytes(new byte[128]); + m3.setIntProperty("msg", 3); + producer.send(m3); + + producer.close(); + producerSession.close(); + producerConnection.close(); + + Connection consumerConnection = getConnection(); + Session consumerSession1 = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + ((AMQSession_0_8) consumerSession1).setPrefetchLimits(0, 256); + MessageConsumer recv1 = consumerSession1.createConsumer(_queue); + + consumerConnection.start(); + + Message r1 = recv1.receive(RECEIVE_TIMEOUT); + assertNotNull("First message not received", r1); + assertEquals("Messages in wrong order", 1, r1.getIntProperty("msg")); + + Message r2 = recv1.receive(RECEIVE_TIMEOUT); + assertNull("Second message incorrectly delivered", r2); + + Session consumerSession2 = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + ((AMQSession_0_8) consumerSession2).setPrefetchLimits(0, 256); + MessageConsumer recv2 = consumerSession2.createConsumer(_queue); + + r2 = recv2.receive(RECEIVE_TIMEOUT); + assertNotNull("Second message not received", r2); + assertEquals("Messages in wrong order", 2, r2.getIntProperty("msg")); + + Message r3 = recv2.receive(RECEIVE_TIMEOUT); + assertNull("Third message incorrectly delivered", r3); + + r3 = recv1.receive(RECEIVE_TIMEOUT); + assertNotNull("Third message not received", r3); + assertEquals("Messages in wrong order", 3, r3.getIntProperty("msg")); + + r2.acknowledge(); + r3.acknowledge(); + recv1.close(); + recv2.close(); + consumerSession1.close(); + consumerSession2.close(); + consumerConnection.close(); + + } + + public static void main(String args[]) throws Throwable + { + FlowControlTest test = new FlowControlTest(); + + int run = 0; + while (true) + { + System.err.println("Test Run:" + ++run); + Thread.sleep(1000); + try + { + test.startBroker(); + test.testBasicBytesFlowControl(); + + Thread.sleep(1000); + } + finally + { + test.stopBroker(); + } + } + } +} + diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/ImmediateAndMandatoryPublishingTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/ImmediateAndMandatoryPublishingTest.java new file mode 100644 index 0000000000..d012b9abbb --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/ImmediateAndMandatoryPublishingTest.java @@ -0,0 +1,237 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.test.client; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.Topic; + +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +/** + * @see CloseOnNoRouteForMandatoryMessageTest for related tests + */ +public class ImmediateAndMandatoryPublishingTest extends QpidBrokerTestCase +{ + private Connection _connection; + private UnroutableMessageTestExceptionListener _testExceptionListener = new UnroutableMessageTestExceptionListener(); + + @Override + public void setUp() throws Exception + { + getBrokerConfiguration().setBrokerAttribute(Broker.CONNECTION_CLOSE_WHEN_NO_ROUTE, false); + super.setUp(); + _connection = getConnection(); + _connection.setExceptionListener(_testExceptionListener); + } + + public void testPublishP2PWithNoConsumerAndImmediateOnAndAutoAck() throws Exception + { + publishIntoExistingDestinationWithNoConsumerAndImmediateOn(Session.AUTO_ACKNOWLEDGE, false); + } + + public void testPublishP2PWithNoConsumerAndImmediateOnAndTx() throws Exception + { + publishIntoExistingDestinationWithNoConsumerAndImmediateOn(Session.SESSION_TRANSACTED, false); + } + + public void testPublishPubSubWithDisconnectedDurableSubscriberAndImmediateOnAndAutoAck() throws Exception + { + publishIntoExistingDestinationWithNoConsumerAndImmediateOn(Session.AUTO_ACKNOWLEDGE, true); + } + + public void testPublishPubSubWithDisconnectedDurableSubscriberAndImmediateOnAndTx() throws Exception + { + publishIntoExistingDestinationWithNoConsumerAndImmediateOn(Session.SESSION_TRANSACTED, true); + } + + public void testPublishP2PIntoNonExistingDesitinationWithMandatoryOnAutoAck() throws Exception + { + publishWithMandatoryOnImmediateOff(Session.AUTO_ACKNOWLEDGE, false); + } + + public void testPublishP2PIntoNonExistingDesitinationWithMandatoryOnAndTx() throws Exception + { + publishWithMandatoryOnImmediateOff(Session.SESSION_TRANSACTED, false); + } + + public void testPubSubMandatoryAutoAck() throws Exception + { + publishWithMandatoryOnImmediateOff(Session.AUTO_ACKNOWLEDGE, true); + } + + public void testPubSubMandatoryTx() throws Exception + { + publishWithMandatoryOnImmediateOff(Session.SESSION_TRANSACTED, true); + } + + public void testP2PNoMandatoryAutoAck() throws Exception + { + publishWithMandatoryOffImmediateOff(Session.AUTO_ACKNOWLEDGE, false); + } + + public void testP2PNoMandatoryTx() throws Exception + { + publishWithMandatoryOffImmediateOff(Session.SESSION_TRANSACTED, false); + } + + public void testPubSubWithImmediateOnAndAutoAck() throws Exception + { + consumerCreateAndClose(true, false); + + Message message = produceMessage(Session.AUTO_ACKNOWLEDGE, true, false, true); + _testExceptionListener.assertReceivedNoRouteWithReturnedMessage(message, getTestQueueName()); + } + + private void publishIntoExistingDestinationWithNoConsumerAndImmediateOn(int acknowledgeMode, boolean pubSub) + throws JMSException, InterruptedException + { + consumerCreateAndClose(pubSub, true); + + Message message = produceMessage(acknowledgeMode, pubSub, false, true); + + _testExceptionListener.assertReceivedNoConsumersWithReturnedMessage(message); + } + + private void publishWithMandatoryOnImmediateOff(int acknowledgeMode, boolean pubSub) throws JMSException, + InterruptedException + { + Message message = produceMessage(acknowledgeMode, pubSub, true, false); + _testExceptionListener.assertReceivedNoRouteWithReturnedMessage(message, getTestQueueName()); + } + + private void publishWithMandatoryOffImmediateOff(int acknowledgeMode, boolean pubSub) throws JMSException, + InterruptedException + { + produceMessage(acknowledgeMode, pubSub, false, false); + + _testExceptionListener.assertNoException(); + } + + private void consumerCreateAndClose(boolean pubSub, boolean durable) throws JMSException + { + Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = null; + MessageConsumer consumer = null; + if (pubSub) + { + destination = session.createTopic(getTestQueueName()); + if (durable) + { + consumer = session.createDurableSubscriber((Topic) destination, getTestName()); + } + else + { + consumer = session.createConsumer(destination); + } + } + else + { + destination = session.createQueue(getTestQueueName()); + consumer = session.createConsumer(destination); + } + consumer.close(); + } + + private Message produceMessage(int acknowledgeMode, boolean pubSub, boolean mandatory, boolean immediate) + throws JMSException + { + Session session = _connection.createSession(acknowledgeMode == Session.SESSION_TRANSACTED, acknowledgeMode); + Destination destination = null; + if (pubSub) + { + destination = session.createTopic(getTestQueueName()); + } + else + { + destination = session.createQueue(getTestQueueName()); + } + + MessageProducer producer = ((AMQSession) session).createProducer(destination, mandatory, immediate); + Message message = session.createMessage(); + producer.send(message); + if (session.getTransacted()) + { + session.commit(); + } + return message; + } + + public void testMandatoryAndImmediateDefaults() throws JMSException, InterruptedException + { + Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // publish to non-existent queue - should get mandatory failure + MessageProducer producer = session.createProducer(session.createQueue(getTestQueueName())); + Message message = session.createMessage(); + producer.send(message); + + _testExceptionListener.assertReceivedNoRouteWithReturnedMessage(message, getTestQueueName()); + + producer = session.createProducer(null); + message = session.createMessage(); + producer.send(session.createQueue(getTestQueueName()), message); + + _testExceptionListener.assertReceivedNoRouteWithReturnedMessage(message, getTestQueueName()); + + // publish to non-existent topic - should get no failure + producer = session.createProducer(session.createTopic(getTestQueueName())); + message = session.createMessage(); + producer.send(message); + + _testExceptionListener.assertNoException(); + + producer = session.createProducer(null); + message = session.createMessage(); + producer.send(session.createTopic(getTestQueueName()), message); + + _testExceptionListener.assertNoException(); + + session.close(); + } + + public void testMandatoryAndImmediateSystemProperties() throws JMSException, InterruptedException + { + setTestClientSystemProperty("qpid.default_mandatory","true"); + Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // publish to non-existent topic - should get mandatory failure + + MessageProducer producer = session.createProducer(session.createTopic(getTestQueueName())); + Message message = session.createMessage(); + producer.send(message); + + _testExceptionListener.assertReceivedNoRouteWithReturnedMessage(message, getTestQueueName()); + + // now set topic specific system property to false - should no longer get mandatory failure on new producer + setTestClientSystemProperty("qpid.default_mandatory_topic","false"); + producer = session.createProducer(null); + message = session.createMessage(); + producer.send(session.createTopic(getTestQueueName()), message); + + _testExceptionListener.assertNoException(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java new file mode 100644 index 0000000000..6b6b4a7b3c --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java @@ -0,0 +1,440 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.test.client; + +import java.util.Enumeration; +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.QueueBrowser; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.naming.NamingException; +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class QueueBrowserAutoAckTest extends QpidBrokerTestCase +{ + protected Connection _clientConnection; + protected Session _clientSession; + protected Queue _queue; + protected static final String MESSAGE_ID_PROPERTY = "MessageIDProperty"; + + public void setUp() throws Exception + { + super.setUp(); + + //Create Client + _clientConnection = getConnection(); + _clientConnection.start(); + + setupSession(); + + _queue = _clientSession.createQueue(getTestQueueName()); + _clientSession.createConsumer(_queue).close(); + + //Ensure there are no messages on the queue to start with. + checkQueueDepth(0); + } + + protected void setupSession() throws Exception + { + _clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + public void tearDown() throws Exception + { + if (_clientConnection != null) + { + _clientConnection.close(); + } + + super.tearDown(); + } + + protected void sendMessages(int num) throws JMSException + { + Connection producerConnection = null; + try + { + producerConnection = getConnection(); + } + catch (Exception e) + { + fail("Unable to lookup connection in JNDI."); + } + + sendMessages(producerConnection, num); + } + + protected void sendMessages(Connection producerConnection, int messageSendCount) throws JMSException + { + producerConnection.start(); + + Session producerSession = producerConnection.createSession(true, Session.AUTO_ACKNOWLEDGE); + + //Ensure _queue is created + producerSession.createConsumer(_queue).close(); + + MessageProducer producer = producerSession.createProducer(_queue); + + for (int messsageID = 0; messsageID < messageSendCount; messsageID++) + { + TextMessage textMsg = producerSession.createTextMessage("Message " + messsageID); + textMsg.setIntProperty(MESSAGE_ID_PROPERTY, messsageID); + producer.send(textMsg); + } + producerSession.commit(); + + producerConnection.close(); + } + + /** + * Using the Protocol getQueueDepth method ensure that the correct number of messages are on the queue. + * + * Also uses a QueueBrowser as a second method of validating the message count on the queue. + * + * @param expectedDepth The expected Queue depth + * @throws JMSException on error + */ + protected void checkQueueDepth(int expectedDepth) throws JMSException + { + + // create QueueBrowser + _logger.info("Creating Queue Browser"); + + QueueBrowser queueBrowser = _clientSession.createBrowser(_queue); + + // check for messages + if (_logger.isDebugEnabled()) + { + _logger.debug("Checking for " + expectedDepth + " messages with QueueBrowser"); + } + + //Check what the session believes the queue count to be. + long queueDepth = 0; + + try + { + queueDepth = ((AMQSession) _clientSession).getQueueDepth((AMQDestination) _queue); + } + catch (AMQException e) + { + } + + assertEquals("Session reports Queue expectedDepth not as expected", expectedDepth, queueDepth); + + + + // Browse the queue to get a second opinion + int msgCount = 0; + Enumeration msgs = queueBrowser.getEnumeration(); + + while (msgs.hasMoreElements()) + { + msgs.nextElement(); + msgCount++; + } + + if (_logger.isDebugEnabled()) + { + _logger.debug("Found " + msgCount + " messages total in browser"); + } + + // check to see if all messages found + assertEquals("Browser did not find all messages", expectedDepth, msgCount); + + //Close browser + queueBrowser.close(); + } + + protected void closeBrowserBeforeAfterGetNext(int messageCount) throws JMSException + { + QueueBrowser queueBrowser = _clientSession.createBrowser(_queue); + + Enumeration msgs = queueBrowser.getEnumeration(); + + int msgCount = 0; + + while (msgs.hasMoreElements() && msgCount < messageCount) + { + msgs.nextElement(); + msgCount++; + } + + try + { + queueBrowser.close(); + } + catch (JMSException e) + { + fail("Close should happen without error:" + e.getMessage()); + } + } + + /** + * This method checks that multiple calls to getEnumeration() on a queueBrowser provide the same behaviour. + * + * @param sentMessages The number of messages sent + * @param browserEnumerationCount The number of times to call getEnumeration() + * @throws JMSException + */ + protected void checkMultipleGetEnum(int sentMessages, int browserEnumerationCount) throws JMSException + { + QueueBrowser queueBrowser = _clientSession.createBrowser(_queue); + + for (int count = 0; count < browserEnumerationCount; count++) + { + _logger.info("Checking getEnumeration:" + count); + Enumeration msgs = queueBrowser.getEnumeration(); + + int msgCount = 0; + + while (msgs.hasMoreElements()) + { + msgs.nextElement(); + msgCount++; + } + + // Verify that the browser can see all the messages sent. + assertEquals(sentMessages, msgCount); + } + + try + { + queueBrowser.close(); + } + catch (JMSException e) + { + fail("Close should happen without error:" + e.getMessage()); + } + } + + protected void checkOverlappingMultipleGetEnum(int expectedMessages, int browserEnumerationCount) throws JMSException + { + checkOverlappingMultipleGetEnum(expectedMessages, browserEnumerationCount, null); + } + + protected void checkOverlappingMultipleGetEnum(int expectedMessages, int browserEnumerationCount, String selector) throws JMSException + { + QueueBrowser queueBrowser = selector == null ? + _clientSession.createBrowser(_queue) : _clientSession.createBrowser(_queue, selector); + + Enumeration[] msgs = new Enumeration[browserEnumerationCount]; + int[] msgCount = new int[browserEnumerationCount]; + + //create Enums + for (int count = 0; count < browserEnumerationCount; count++) + { + msgs[count] = queueBrowser.getEnumeration(); + } + + //interleave reads + for (int cnt = 0; cnt < expectedMessages; cnt++) + { + for (int count = 0; count < browserEnumerationCount; count++) + { + if (msgs[count].hasMoreElements()) + { + msgs[count].nextElement(); + msgCount[count]++; + } + } + } + + //validate all browsers get right message count. + for (int count = 0; count < browserEnumerationCount; count++) + { + assertEquals(msgCount[count], expectedMessages); + } + + try + { + queueBrowser.close(); + } + catch (JMSException e) + { + fail("Close should happen without error:" + e.getMessage()); + } + } + + protected void validate(int messages) throws JMSException + { + //Create a new connection to validate message content + Connection connection = null; + + try + { + connection = getConnection(); + } + catch (Exception e) + { + fail("Unable to make validation connection"); + } + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + connection.start(); + + MessageConsumer consumer = session.createConsumer(_queue); + + _logger.info("Verify messages are still on the queue"); + + Message tempMsg; + + for (int msgCount = 0; msgCount < messages; msgCount++) + { + tempMsg = (TextMessage) consumer.receive(RECEIVE_TIMEOUT); + if (tempMsg == null) + { + fail("Message " + msgCount + " not retrieved from queue"); + } + } + + //Close this new connection + connection.close(); + + _logger.info("All messages recevied from queue"); + + //ensure no message left. + checkQueueDepth(0); + } + + protected void checkQueueDepthWithSelectors(int totalMessages, int clients) throws JMSException + { + + String selector = MESSAGE_ID_PROPERTY + " % " + clients + " = 0" ; + + checkOverlappingMultipleGetEnum(totalMessages / clients, clients, selector); + } + + + /** + * This tests you can browse an empty queue, see QPID-785 + * + * @throws Exception + */ + public void testBrowsingEmptyQueue() throws Exception + { + checkQueueDepth(0); + } + + /* + * Test Messages Remain on Queue + * Create a queu and send messages to it. Browse them and then receive them all to verify they were still there + * + */ + public void testQueueBrowserMsgsRemainOnQueue() throws Exception + { + int messages = 10; + + sendMessages(messages); + + checkQueueDepth(messages); + + validate(messages); + } + + + public void testClosingBrowserMidReceiving() throws NamingException, JMSException + { + int messages = 100; + + sendMessages(messages); + + checkQueueDepth(messages); + + closeBrowserBeforeAfterGetNext(10); + + validate(messages); + } + + /** + * This tests that multiple getEnumerations on a QueueBrowser return the required number of messages. + * @throws NamingException + * @throws JMSException + */ + public void testMultipleGetEnum() throws NamingException, JMSException + { + int messages = 10; + + sendMessages(messages); + + checkQueueDepth(messages); + + checkMultipleGetEnum(messages, 5); + + validate(messages); + } + + public void testMultipleOverlappingGetEnum() throws NamingException, JMSException + { + int messages = 25; + + sendMessages(messages); + + checkQueueDepth(messages); + + checkOverlappingMultipleGetEnum(messages, 5); + + validate(messages); + } + + + public void testBrowsingWithSelector() throws JMSException + { + int messages = 40; + + sendMessages(messages); + + checkQueueDepth(messages); + + for (int clients = 2; clients <= 10; clients++) + { + checkQueueDepthWithSelectors(messages, clients); + } + + validate(messages); + } + + public void testBrowsingWhileStopped() throws JMSException + { + _clientConnection.stop(); + + try + { + QueueBrowser browser = _clientSession.createBrowser(getTestQueue()); + Enumeration messages = browser.getEnumeration(); + fail("Expected exception when attempting to browse on a stopped connection did not occur"); + } + catch(javax.jms.IllegalStateException e) + { + // pass + } + + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserClientAckTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserClientAckTest.java new file mode 100644 index 0000000000..f30b8043ad --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserClientAckTest.java @@ -0,0 +1,34 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.client; + +import javax.jms.Session; + +public class QueueBrowserClientAckTest extends QueueBrowserAutoAckTest +{ + + + protected void setupSession() throws Exception + { + _clientSession = _clientConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserDupsOkTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserDupsOkTest.java new file mode 100644 index 0000000000..b19809b8f2 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserDupsOkTest.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.test.client; + +import javax.jms.Session; + +public class QueueBrowserDupsOkTest extends QueueBrowserAutoAckTest +{ + protected void setupSession() throws Exception + { + _clientSession = _clientConnection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserNoAckTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserNoAckTest.java new file mode 100644 index 0000000000..c97343464c --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserNoAckTest.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.test.client; + +import org.apache.qpid.client.AMQSession; + + +public class QueueBrowserNoAckTest extends QueueBrowserAutoAckTest +{ + + protected void setupSession() throws Exception + { + _clientSession = _clientConnection.createSession(false, AMQSession.NO_ACKNOWLEDGE); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserPreAckTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserPreAckTest.java new file mode 100644 index 0000000000..bb1c0d3698 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserPreAckTest.java @@ -0,0 +1,32 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.client; + +import org.apache.qpid.client.AMQSession; + +public class QueueBrowserPreAckTest extends QueueBrowserAutoAckTest +{ + + protected void setupSession() throws Exception + { + _clientSession = _clientConnection.createSession(false, AMQSession.PRE_ACKNOWLEDGE); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserTransactedTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserTransactedTest.java new file mode 100644 index 0000000000..d79788f017 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/QueueBrowserTransactedTest.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.test.client; + +import javax.jms.Session; + +public class QueueBrowserTransactedTest extends QueueBrowserAutoAckTest +{ + protected void setupSession() throws Exception + { + _clientSession = _clientConnection.createSession(true, Session.SESSION_TRANSACTED); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/RollbackOrderTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/RollbackOrderTest.java new file mode 100644 index 0000000000..d0968aefc7 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/RollbackOrderTest.java @@ -0,0 +1,189 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.client; + +import junit.framework.AssertionFailedError; + +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Queue; +import javax.jms.Session; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * RollbackOrderTest, QPID-1864, QPID-1871 + * + * Description: + * + * The problem that this test is exposing is that the dispatcher used to be capable + * of holding on to a message when stopped. This meant that when the rollback was + * called and the dispatcher stopped it may have hold of a message. So after all + * the local queues(preDeliveryQueue, SynchronousQueue, PostDeliveryTagQueue) + * have been cleared the client still had a single message, the one the + * dispatcher was holding on to. + * + * As a result the TxRollback operation would run and then release the dispatcher. + * Whilst the dispatcher would then proceed to reject the message it was holding + * the Broker would already have resent that message so the rejection would silently + * fail. + * + * And the client would receive that single message 'early', depending on the + * number of messages already received when rollback was called. + * + * + * Aims: + * + * The tests puts 50 messages on to the queue. + * + * The test then tries to cause the dispatcher to stop whilst it is in the process + * of moving a message from the preDeliveryQueue to a consumers sychronousQueue. + * + * To exercise this path we have 50 message flowing to the client to give the + * dispatcher a bit of work to do moving messages. + * + * Then we loop - 10 times + * - Validating that the first message received is always message 1. + * - Receive a few more so that there are a few messages to reject. + * - call rollback, to try and catch the dispatcher mid process. + * + * Outcome: + * + * The hope is that we catch the dispatcher mid process and cause a BasicReject + * to fail. Which will be indicated in the log but will also cause that failed + * rejected message to be the next to be delivered which will not be message 1 + * as expected. + * + * We are testing a race condition here but we can check through the log file if + * the race condition occurred. However, performing that check will only validate + * the problem exists and will not be suitable as part of a system test. + * + * @see org.apache.qpid.test.unit.transacted.CommitRollbackTest + */ +public class RollbackOrderTest extends QpidBrokerTestCase +{ + + private Connection _connection; + private Queue _queue; + private Session _session; + private MessageConsumer _consumer; + + @Override public void setUp() throws Exception + { + super.setUp(); + _connection = getConnection(); + + _session = _connection.createSession(true, Session.SESSION_TRANSACTED); + _queue = _session.createQueue(getTestQueueName()); + _consumer = _session.createConsumer(_queue); + + //Send more messages so it is more likely that the dispatcher is + // processing on rollback. + sendMessage(_session, _queue, 50); + _session.commit(); + + } + + public void testOrderingAfterRollback() throws Exception + { + //Start the session now so we + _connection.start(); + + for (int i = 0; i < 20; i++) + { + Message msg = _consumer.receive(); + assertEquals("Incorrect Message Received", 0, msg.getIntProperty(INDEX)); + + // Pull additional messages through so we have some reject work to do + for (int m=1; m <= 5 ; m++) + { + msg = _consumer.receive(); + assertEquals("Incorrect Message Received (message " + m + ")", m, msg.getIntProperty(INDEX)); + } + + _session.rollback(); + } + } + + public void testOrderingAfterRollbackOnMessage() throws Exception + { + final CountDownLatch count= new CountDownLatch(20); + final Exception exceptions[] = new Exception[20]; + final AtomicBoolean failed = new AtomicBoolean(false); + + _consumer.setMessageListener(new MessageListener() + { + + public void onMessage(Message message) + { + + Message msg = message; + try + { + count.countDown(); + assertEquals("Incorrect Message Received", 0, msg.getIntProperty(INDEX)); + + _session.rollback(); + } + catch (JMSException e) + { + _logger.error("Error:" + e.getMessage(), e); + exceptions[(int)count.getCount()] = e; + } + catch (AssertionFailedError cf) + { + // End Test if Equality test fails + while (count.getCount() != 0) + { + count.countDown(); + } + + _logger.error("Error:" + cf.getMessage(), cf); + failed.set(true); + } + } + }); + //Start the session now so we + _connection.start(); + + count.await(10l, TimeUnit.SECONDS); + assertEquals("Not all message received. Count should be 0.", 0, count.getCount()); + + for (Exception e : exceptions) + { + if (e != null) + { + _logger.error("Encountered exception", e); + failed.set(true); + } + } + + _connection.close(); + + assertFalse("Exceptions thrown during test run, Check Std.err.", failed.get()); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/UnroutableMessageTestExceptionListener.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/UnroutableMessageTestExceptionListener.java new file mode 100644 index 0000000000..99afe0015d --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/UnroutableMessageTestExceptionListener.java @@ -0,0 +1,178 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.test.client; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; + +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQNoConsumersException; +import org.apache.qpid.client.AMQNoRouteException; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.protocol.AMQConstant; + +/** + * Provides utility methods for checking exceptions that are thrown on the client side when a message is + * not routable. + * + * Exception objects are passed either explicitly as method parameters or implicitly + * by previously doing {@link Connection#setExceptionListener(ExceptionListener)}. + */ +public class UnroutableMessageTestExceptionListener implements ExceptionListener +{ + private static final Logger _logger = Logger.getLogger(UnroutableMessageTestExceptionListener.class); + + /** + * Number of seconds to check for an event that should should NOT happen + */ + private static final int NEGATIVE_TIMEOUT = 2; + + /** + * Number of seconds to keep checking for an event that should should happen + */ + private static final int POSITIVE_TIMEOUT = 30; + + private BlockingQueue _exceptions = new ArrayBlockingQueue(1); + + @Override + public void onException(JMSException e) + { + _logger.info("Received exception " + e); + _exceptions.add(e); + } + + public void assertReceivedNoRouteWithReturnedMessage(Message message, String intendedQueueName) + { + JMSException exception = getReceivedException(); + assertNoRouteExceptionWithReturnedMessage(exception, message, intendedQueueName); + } + + public void assertReceivedNoRoute(String intendedQueueName) + { + JMSException exception = getReceivedException(); + assertNoRoute(exception, intendedQueueName); + } + + public void assertReceivedNoConsumersWithReturnedMessage(Message message) + { + JMSException exception = getReceivedException(); + AMQNoConsumersException noConsumersException = (AMQNoConsumersException) exception.getLinkedException(); + assertNotNull("AMQNoConsumersException should be linked to JMSException", noConsumersException); + Message bounceMessage = (Message) noConsumersException.getUndeliveredMessage(); + assertNotNull("Bounced Message is expected", bounceMessage); + + try + { + assertEquals("Unexpected message is bounced", message.getJMSMessageID(), bounceMessage.getJMSMessageID()); + } + catch (JMSException e) + { + throw new RuntimeException("Couldn't check exception", e); + } + } + + public void assertReceivedReturnedMessageWithLongExceptionMessage(Message message, AMQQueue queue) + { + JMSException exception = getReceivedException(); + assertNoRouteException(exception, message); + AMQShortString exchangeName = queue.getExchangeName(); + String expectedMessage = "Error: No Route for message [Exchange: " + exchangeName.asString().substring(0, 220) + "..."; + assertTrue("Unexpected exception message: " + exception.getMessage(), exception.getMessage().contains(expectedMessage)); + } + + public void assertNoRouteExceptionWithReturnedMessage( + JMSException exception, Message message, String intendedQueueName) + { + assertNoRoute(exception, intendedQueueName); + + assertNoRouteException(exception, message); + } + + private void assertNoRouteException(JMSException exception, Message message) + { + AMQNoRouteException noRouteException = (AMQNoRouteException) exception.getLinkedException(); + assertNotNull("AMQNoRouteException should be linked to JMSException", noRouteException); + Message bounceMessage = (Message) noRouteException.getUndeliveredMessage(); + assertNotNull("Bounced Message is expected", bounceMessage); + + try + { + assertEquals("Unexpected message is bounced", message.getJMSMessageID(), bounceMessage.getJMSMessageID()); + } + catch (JMSException e) + { + throw new RuntimeException("Couldn't check exception", e); + } + } + + public void assertNoRoute(JMSException exception, String intendedQueueName) + { + assertTrue( + exception + " message should contain intended queue name", + exception.getMessage().contains(intendedQueueName)); + + AMQException noRouteException = (AMQException) exception.getLinkedException(); + assertNotNull("AMQException should be linked to JMSException", noRouteException); + + assertEquals(AMQConstant.NO_ROUTE, noRouteException.getErrorCode()); + assertTrue( + "Linked exception " + noRouteException + " message should contain intended queue name", + noRouteException.getMessage().contains(intendedQueueName)); + } + + + public void assertNoException() + { + try + { + assertNull("Unexpected JMSException", _exceptions.poll(NEGATIVE_TIMEOUT, TimeUnit.SECONDS)); + } + catch (InterruptedException e) + { + throw new RuntimeException("Couldn't check exception", e); + } + } + + private JMSException getReceivedException() + { + try + { + JMSException exception = _exceptions.poll(POSITIVE_TIMEOUT, TimeUnit.SECONDS); + assertNotNull("JMSException is expected", exception); + return exception; + } + catch(InterruptedException e) + { + throw new RuntimeException("Couldn't check exception", e); + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/destination/AddressBasedDestinationTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/destination/AddressBasedDestinationTest.java new file mode 100644 index 0000000000..14cadc2389 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/destination/AddressBasedDestinationTest.java @@ -0,0 +1,1464 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.client.destination; + +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.QueueBrowser; +import javax.jms.QueueReceiver; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.jms.TopicSession; +import javax.jms.TopicSubscriber; +import javax.naming.Context; +import javax.naming.InitialContext; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.client.AMQAnyDestination; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQSession_0_10; +import org.apache.qpid.client.message.QpidMessageProperties; +import org.apache.qpid.jndi.PropertiesFileInitialContextFactory; +import org.apache.qpid.messaging.Address; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.transport.ExecutionErrorCode; + +public class AddressBasedDestinationTest extends QpidBrokerTestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(AddressBasedDestinationTest.class); + private Connection _connection; + + @Override + public void setUp() throws Exception + { + super.setUp(); + _connection = getConnection() ; + _connection.start(); + } + + @Override + public void tearDown() throws Exception + { + _connection.close(); + super.tearDown(); + } + + public void testCreateOptions() throws Exception + { + Session jmsSession = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + MessageProducer prod; + MessageConsumer cons; + + // default (create never, assert never) ------------------- + // create never -------------------------------------------- + String addr1 = "ADDR:testQueue1"; + AMQDestination dest = new AMQAnyDestination(addr1); + try + { + cons = jmsSession.createConsumer(dest); + } + catch(JMSException e) + { + assertTrue(e.getMessage().contains("The name 'testQueue1' supplied in the address " + + "doesn't resolve to an exchange or a queue")); + } + + try + { + prod = jmsSession.createProducer(dest); + } + catch(JMSException e) + { + assertTrue(e.getCause().getCause().getMessage().contains("The name 'testQueue1' supplied in the address " + + "doesn't resolve to an exchange or a queue")); + } + + assertFalse("Queue should not be created",( + (AMQSession_0_10)jmsSession).isQueueExist(dest,false)); + + + // create always ------------------------------------------- + addr1 = "ADDR:testQueue1; { create: always }"; + dest = new AMQAnyDestination(addr1); + cons = jmsSession.createConsumer(dest); + + assertTrue("Queue not created as expected",( + (AMQSession_0_10)jmsSession).isQueueExist(dest, true)); + assertTrue("Queue not bound as expected",( + (AMQSession_0_10)jmsSession).isQueueBound("", + dest.getAddressName(),dest.getAddressName(), null)); + + // create receiver ----------------------------------------- + addr1 = "ADDR:testQueue2; { create: receiver }"; + dest = new AMQAnyDestination(addr1); + try + { + prod = jmsSession.createProducer(dest); + } + catch(JMSException e) + { + assertTrue(e.getCause().getCause().getMessage().contains("The name 'testQueue2' supplied in the address " + + "doesn't resolve to an exchange or a queue")); + } + + assertFalse("Queue should not be created",( + (AMQSession_0_10)jmsSession).isQueueExist(dest, false)); + + + cons = jmsSession.createConsumer(dest); + + assertTrue("Queue not created as expected",( + (AMQSession_0_10)jmsSession).isQueueExist(dest, true)); + assertTrue("Queue not bound as expected",( + (AMQSession_0_10)jmsSession).isQueueBound("", + dest.getAddressName(),dest.getAddressName(), null)); + + // create never -------------------------------------------- + addr1 = "ADDR:testQueue3; { create: never }"; + dest = new AMQAnyDestination(addr1); + try + { + cons = jmsSession.createConsumer(dest); + } + catch(JMSException e) + { + assertTrue(e.getMessage().contains("The name 'testQueue3' supplied in the address " + + "doesn't resolve to an exchange or a queue")); + } + + try + { + prod = jmsSession.createProducer(dest); + } + catch(JMSException e) + { + assertTrue(e.getCause().getCause().getMessage().contains("The name 'testQueue3' supplied in the address " + + "doesn't resolve to an exchange or a queue")); + } + + assertFalse("Queue should not be created",( + (AMQSession_0_10)jmsSession).isQueueExist(dest, false)); + + // create sender ------------------------------------------ + addr1 = "ADDR:testQueue3; { create: sender }"; + dest = new AMQAnyDestination(addr1); + + try + { + cons = jmsSession.createConsumer(dest); + } + catch(JMSException e) + { + assertTrue(e.getMessage().contains("The name 'testQueue3' supplied in the address " + + "doesn't resolve to an exchange or a queue")); + } + assertFalse("Queue should not be created",( + (AMQSession_0_10)jmsSession).isQueueExist(dest, false)); + + prod = jmsSession.createProducer(dest); + assertTrue("Queue not created as expected",( + (AMQSession_0_10)jmsSession).isQueueExist(dest, true)); + assertTrue("Queue not bound as expected",( + (AMQSession_0_10)jmsSession).isQueueBound("", + dest.getAddressName(),dest.getAddressName(), null)); + + } + + public void testCreateQueue() throws Exception + { + Session jmsSession = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + + String addr = "ADDR:my-queue/hello; " + + "{" + + "create: always, " + + "node: " + + "{" + + "durable: true ," + + "x-declare: " + + "{" + + "exclusive: true," + + "arguments: {" + + "'qpid.alert_size': 1000," + + "'qpid.alert_count': 100" + + "}" + + "}, " + + "x-bindings: [{exchange : 'amq.direct', key : test}, " + + "{exchange : 'amq.fanout'}," + + "{exchange: 'amq.match', arguments: {x-match: any, dep: sales, loc: CA}}," + + "{exchange : 'amq.topic', key : 'a.#'}" + + "]," + + + "}" + + "}"; + AMQDestination dest = new AMQAnyDestination(addr); + MessageConsumer cons = jmsSession.createConsumer(dest); + cons.close(); + + // Even if the consumer is closed the queue and the bindings should be intact. + + assertTrue("Queue not created as expected",( + (AMQSession_0_10)jmsSession).isQueueExist(dest, true)); + + assertTrue("Queue not bound as expected",( + (AMQSession_0_10)jmsSession).isQueueBound("", + dest.getAddressName(),dest.getAddressName(), null)); + + assertTrue("Queue not bound as expected",( + (AMQSession_0_10)jmsSession).isQueueBound("amq.direct", + dest.getAddressName(),"test", null)); + + assertTrue("Queue not bound as expected",( + (AMQSession_0_10)jmsSession).isQueueBound("amq.fanout", + dest.getAddressName(),null, null)); + + assertTrue("Queue not bound as expected",( + (AMQSession_0_10)jmsSession).isQueueBound("amq.topic", + dest.getAddressName(),"a.#", null)); + + Map args = new HashMap(); + args.put("x-match","any"); + args.put("dep","sales"); + args.put("loc","CA"); + assertTrue("Queue not bound as expected",( + (AMQSession_0_10)jmsSession).isQueueBound("amq.match", + dest.getAddressName(),null, args)); + + MessageProducer prod = jmsSession.createProducer(dest); + prod.send(jmsSession.createTextMessage("test")); + + MessageConsumer cons2 = jmsSession.createConsumer(jmsSession.createQueue("ADDR:my-queue")); + Message m = cons2.receive(1000); + assertNotNull("Should receive message sent to my-queue",m); + assertEquals("The subject set in the message is incorrect","hello",m.getStringProperty(QpidMessageProperties.QPID_SUBJECT)); + } + + public void testCreateExchange() throws Exception + { + createExchangeImpl(false, false, false); + } + + /** + * Verify creating an exchange via an Address, with supported + * exchange-declare arguments. + */ + public void testCreateExchangeWithArgs() throws Exception + { + createExchangeImpl(true, false, false); + } + + /** + * Verify that when creating an exchange via an Address, if a + * nonsense argument is specified the broker throws an execution + * exception back on the session with NOT_IMPLEMENTED status. + */ + public void testCreateExchangeWithNonsenseArgs() throws Exception + { + createExchangeImpl(true, true, false); + } + + private void createExchangeImpl(final boolean withExchangeArgs, + final boolean useNonsenseArguments, + final boolean useNonsenseExchangeType) throws Exception + { + Session jmsSession = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + + String addr = "ADDR:my-exchange/hello; " + + "{ " + + "create: always, " + + "node: " + + "{" + + "type: topic, " + + "x-declare: " + + "{ " + + "type:" + + (useNonsenseExchangeType ? "nonsense" : "direct") + + ", " + + "auto-delete: true" + + createExchangeArgsString(withExchangeArgs, useNonsenseArguments) + + "}" + + "}" + + "}"; + + AMQDestination dest = new AMQAnyDestination(addr); + + MessageConsumer cons; + try + { + cons = jmsSession.createConsumer(dest); + if(useNonsenseArguments || useNonsenseExchangeType) + { + fail("Expected execution exception during exchange declare did not occur"); + } + } + catch(JMSException e) + { + if(useNonsenseArguments && e.getCause().getMessage().contains(ExecutionErrorCode.NOT_IMPLEMENTED.toString())) + { + //expected because we used an argument which the broker doesn't have functionality + //for. We can't do the rest of the test as a result of the exception, just stop. + return; + } + else if(useNonsenseExchangeType && (e.getErrorCode().equals(String.valueOf(AMQConstant.NOT_FOUND.getCode())))) + { + return; + } + else + { + fail("Unexpected exception whilst creating consumer: " + e); + } + } + + assertTrue("Exchange not created as expected",( + (AMQSession_0_10)jmsSession).isExchangeExist(dest,true)); + + // The existence of the queue is implicitly tested here + assertTrue("Queue not bound as expected",( + (AMQSession_0_10)jmsSession).isQueueBound("my-exchange", + dest.getQueueName(),"hello", null)); + + // The client should be able to query and verify the existence of my-exchange (QPID-2774) + dest = new AMQAnyDestination("ADDR:my-exchange; {create: never}"); + cons = jmsSession.createConsumer(dest); + } + + private String createExchangeArgsString(final boolean withExchangeArgs, + final boolean useNonsenseArguments) + { + String argsString; + + if(withExchangeArgs && useNonsenseArguments) + { + argsString = ", arguments: {" + + "'abcd.1234.wxyz': 1, " + + "}"; + } + else if(withExchangeArgs) + { + argsString = ", arguments: {" + + "'qpid.msg_sequence': 1, " + + "'qpid.ive': 1" + + "}"; + } + else + { + argsString = ""; + } + + return argsString; + } + + public void checkQueueForBindings(Session jmsSession, AMQDestination dest,String headersBinding) throws Exception + { + assertTrue("Queue not created as expected",( + (AMQSession_0_10)jmsSession).isQueueExist(dest, true)); + + assertTrue("Queue not bound as expected",( + (AMQSession_0_10)jmsSession).isQueueBound("", + dest.getAddressName(),dest.getAddressName(), null)); + + assertTrue("Queue not bound as expected",( + (AMQSession_0_10)jmsSession).isQueueBound("amq.direct", + dest.getAddressName(),"test", null)); + + assertTrue("Queue not bound as expected",( + (AMQSession_0_10)jmsSession).isQueueBound("amq.topic", + dest.getAddressName(),"a.#", null)); + + Address a = Address.parse(headersBinding); + assertTrue("Queue not bound as expected",( + (AMQSession_0_10)jmsSession).isQueueBound("amq.match", + dest.getAddressName(),null, a.getOptions())); + } + + /** + * Test goal: Verifies that a producer and consumer creation triggers the correct + * behavior for x-bindings specified in node props. + */ + public void testBindQueueWithArgs() throws Exception + { + + Session jmsSession = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + String headersBinding = "{exchange: 'amq.match', arguments: {x-match: any, dep: sales, loc: CA}}"; + + String addr = "node: " + + "{" + + "durable: true ," + + "x-declare: " + + "{ " + + "auto-delete: true," + + "arguments: {'qpid.alert_count': 100}" + + "}, " + + "x-bindings: [{exchange : 'amq.direct', key : test}, " + + "{exchange : 'amq.topic', key : 'a.#'}," + + headersBinding + + "]" + + "}" + + "}"; + + + AMQDestination dest1 = new AMQAnyDestination("ADDR:my-queue/hello; {create: receiver, " +addr); + MessageConsumer cons = jmsSession.createConsumer(dest1); + checkQueueForBindings(jmsSession,dest1,headersBinding); + + AMQDestination dest2 = new AMQAnyDestination("ADDR:my-queue2/hello; {create: sender, " +addr); + MessageProducer prod = jmsSession.createProducer(dest2); + checkQueueForBindings(jmsSession,dest2,headersBinding); + } + + /** + * Test goal: Verifies the capacity property in address string is handled properly. + * Test strategy: + * Creates a destination with capacity 10. + * Creates consumer with client ack. + * Sends 15 messages to the queue, tries to receive 10. + * Tries to receive the 11th message and checks if its null. + * + * Since capacity is 10 and we haven't acked any messages, + * we should not have received the 11th. + * + * Acks the 10th message and verifies we receive the rest of the msgs. + */ + public void testCapacity() throws Exception + { + verifyCapacity("ADDR:my-queue; {create: always, link:{capacity: 10}}"); + } + + public void testSourceAndTargetCapacity() throws Exception + { + verifyCapacity("ADDR:my-queue; {create: always, link:{capacity: {source:10, target:15} }}"); + } + + private void verifyCapacity(String address) throws Exception + { + if (!isCppBroker()) + { + _logger.info("Not C++ broker, exiting test"); + return; + } + + Session jmsSession = _connection.createSession(false,Session.CLIENT_ACKNOWLEDGE); + + AMQDestination dest = new AMQAnyDestination(address); + MessageConsumer cons = jmsSession.createConsumer(dest); + MessageProducer prod = jmsSession.createProducer(dest); + + for (int i=0; i< 15; i++) + { + prod.send(jmsSession.createTextMessage("msg" + i) ); + } + Message msg = null; + for (int i=0; i< 10; i++) + { + msg = cons.receive(RECEIVE_TIMEOUT); + assertNotNull("Should have received " + i + " message", msg); + assertEquals("Unexpected message received", "msg" + i, ((TextMessage)msg).getText()); + } + assertNull("Shouldn't have received the 11th message as capacity is 10",cons.receive(RECEIVE_TIMEOUT)); + msg.acknowledge(); + for (int i=11; i<16; i++) + { + assertNotNull("Should have received the " + i + "th message as we acked the last 10",cons.receive(RECEIVE_TIMEOUT)); + } + } + + /** + * Test goal: Verifies if the new address format based destinations + * can be specified and loaded correctly from the properties file. + * + */ + public void testLoadingFromPropertiesFile() throws Exception + { + Hashtable map = new Hashtable(); + map.put("destination.myQueue1", "ADDR:my-queue/hello; {create: always, node: " + + "{x-declare: {auto-delete: true, arguments : {'qpid.alert_size': 1000}}}}"); + + map.put("destination.myQueue2", "ADDR:my-queue2; { create: receiver }"); + + map.put("destination.myQueue3", "BURL:direct://amq.direct/my-queue3?routingkey='test'"); + + PropertiesFileInitialContextFactory props = new PropertiesFileInitialContextFactory(); + Context ctx = props.getInitialContext(map); + + AMQDestination dest1 = (AMQDestination)ctx.lookup("myQueue1"); + AMQDestination dest2 = (AMQDestination)ctx.lookup("myQueue2"); + AMQDestination dest3 = (AMQDestination)ctx.lookup("myQueue3"); + + Session jmsSession = _connection.createSession(false,Session.CLIENT_ACKNOWLEDGE); + MessageConsumer cons1 = jmsSession.createConsumer(dest1); + MessageConsumer cons2 = jmsSession.createConsumer(dest2); + MessageConsumer cons3 = jmsSession.createConsumer(dest3); + + assertTrue("Destination1 was not created as expected",( + (AMQSession_0_10)jmsSession).isQueueExist(dest1, true)); + + assertTrue("Destination1 was not bound as expected",( + (AMQSession_0_10)jmsSession).isQueueBound("", + dest1.getAddressName(),dest1.getAddressName(), null)); + + assertTrue("Destination2 was not created as expected",( + (AMQSession_0_10)jmsSession).isQueueExist(dest2,true)); + + assertTrue("Destination2 was not bound as expected",( + (AMQSession_0_10)jmsSession).isQueueBound("", + dest2.getAddressName(),dest2.getAddressName(), null)); + + MessageProducer producer = jmsSession.createProducer(dest3); + producer.send(jmsSession.createTextMessage("Hello")); + TextMessage msg = (TextMessage)cons3.receive(1000); + assertEquals("Destination3 was not created as expected.",msg.getText(),"Hello"); + } + + /** + * Test goal: Verifies the subject can be overridden using "qpid.subject" message property. + * Test strategy: Creates and address with a default subject "topic1" + * Creates a message with "qpid.subject"="topic2" and sends it. + * Verifies that the message goes to "topic2" instead of "topic1". + */ + public void testOverridingSubject() throws Exception + { + Session jmsSession = _connection.createSession(false,Session.CLIENT_ACKNOWLEDGE); + + AMQDestination topic1 = new AMQAnyDestination("ADDR:amq.topic/topic1; {link:{name: queue1}}"); + + MessageProducer prod = jmsSession.createProducer(topic1); + + Message m = jmsSession.createTextMessage("Hello"); + m.setStringProperty("qpid.subject", "topic2"); + + MessageConsumer consForTopic1 = jmsSession.createConsumer(topic1); + MessageConsumer consForTopic2 = jmsSession.createConsumer(new AMQAnyDestination("ADDR:amq.topic/topic2; {link:{name: queue2}}")); + + prod.send(m); + Message msg = consForTopic1.receive(1000); + assertNull("message shouldn't have been sent to topic1",msg); + + msg = consForTopic2.receive(1000); + assertNotNull("message should have been sent to topic2",msg); + + } + + /** + * Test goal: Verifies that session.createQueue method + * works as expected both with the new and old addressing scheme. + */ + public void testSessionCreateQueue() throws Exception + { + Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + + // Using the BURL method + Destination queue = ssn.createQueue("my-queue"); + MessageProducer prod = ssn.createProducer(queue); + MessageConsumer cons = ssn.createConsumer(queue); + assertTrue("my-queue was not created as expected",( + (AMQSession_0_10)ssn).isQueueBound("amq.direct", + "my-queue","my-queue", null)); + + prod.send(ssn.createTextMessage("test")); + assertNotNull("consumer should receive a message",cons.receive(1000)); + cons.close(); + + // Using the ADDR method + // default case + queue = ssn.createQueue("ADDR:my-queue2"); + try + { + prod = ssn.createProducer(queue); + fail("The client should throw an exception, since there is no queue present in the broker"); + } + catch(Exception e) + { + String s = "The name 'my-queue2' supplied in the address " + + "doesn't resolve to an exchange or a queue"; + assertEquals(s,e.getCause().getCause().getMessage()); + } + + // explicit create case + queue = ssn.createQueue("ADDR:my-queue2; {create: sender}"); + prod = ssn.createProducer(queue); + cons = ssn.createConsumer(queue); + assertTrue("my-queue2 was not created as expected",( + (AMQSession_0_10)ssn).isQueueBound("", + "my-queue2","my-queue2", null)); + + prod.send(ssn.createTextMessage("test")); + assertNotNull("consumer should receive a message",cons.receive(1000)); + cons.close(); + + // Using the ADDR method to create a more complicated queue + String addr = "ADDR:amq.direct/x512; {" + + "link : {name : 'MY.RESP.QUEUE', " + + "x-declare : { auto-delete: true, exclusive: true, " + + "arguments : {'qpid.alert_size': 1000, 'qpid.policy_type': ring} } } }"; + queue = ssn.createQueue(addr); + + cons = ssn.createConsumer(queue); + prod = ssn.createProducer(queue); + assertTrue("MY.RESP.QUEUE was not created as expected",( + (AMQSession_0_10)ssn).isQueueBound("amq.direct", + "MY.RESP.QUEUE","x512", null)); + cons.close(); + } + + /** + * Test goal: Verifies that session.creatTopic method works as expected + * both with the new and old addressing scheme. + */ + public void testSessionCreateTopic() throws Exception + { + sessionCreateTopicImpl(false); + } + + /** + * Test goal: Verifies that session.creatTopic method works as expected + * both with the new and old addressing scheme when adding exchange arguments. + */ + public void testSessionCreateTopicWithExchangeArgs() throws Exception + { + sessionCreateTopicImpl(true); + } + + private void sessionCreateTopicImpl(boolean withExchangeArgs) throws Exception + { + Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + + // Using the BURL method + Topic topic = ssn.createTopic("ACME"); + MessageProducer prod = ssn.createProducer(topic); + MessageConsumer cons = ssn.createConsumer(topic); + + prod.send(ssn.createTextMessage("test")); + assertNotNull("consumer should receive a message",cons.receive(1000)); + cons.close(); + + // Using the ADDR method + topic = ssn.createTopic("ADDR:ACME"); + prod = ssn.createProducer(topic); + cons = ssn.createConsumer(topic); + + prod.send(ssn.createTextMessage("test")); + assertNotNull("consumer should receive a message",cons.receive(1000)); + cons.close(); + + String addr = "ADDR:vehicles/bus; " + + "{ " + + "create: always, " + + "node: " + + "{" + + "type: topic, " + + "x-declare: " + + "{ " + + "type:direct, " + + "auto-delete: true" + + createExchangeArgsString(withExchangeArgs, false) + + "}" + + "}, " + + "link: {name : my-topic, " + + "x-bindings: [{exchange : 'vehicles', key : car}, " + + "{exchange : 'vehicles', key : van}]" + + "}" + + "}"; + + // Using the ADDR method to create a more complicated topic + topic = ssn.createTopic(addr); + cons = ssn.createConsumer(topic); + prod = ssn.createProducer(topic); + + assertTrue("The queue was not bound to vehicle exchange using bus as the binding key",( + (AMQSession_0_10)ssn).isQueueBound("vehicles", + "my-topic","bus", null)); + + assertTrue("The queue was not bound to vehicle exchange using car as the binding key",( + (AMQSession_0_10)ssn).isQueueBound("vehicles", + "my-topic","car", null)); + + assertTrue("The queue was not bound to vehicle exchange using van as the binding key",( + (AMQSession_0_10)ssn).isQueueBound("vehicles", + "my-topic","van", null)); + + Message msg = ssn.createTextMessage("test"); + msg.setStringProperty("qpid.subject", "van"); + prod.send(msg); + assertNotNull("consumer should receive a message",cons.receive(1000)); + cons.close(); + } + + /** + * Test Goal : Verify the default subjects used for each exchange type. + * The default for amq.topic is "#" and for the rest it's "" + */ + public void testDefaultSubjects() throws Exception + { + Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + + MessageConsumer queueCons = ssn.createConsumer(new AMQAnyDestination("ADDR:amq.direct")); + MessageConsumer topicCons = ssn.createConsumer(new AMQAnyDestination("ADDR:amq.topic")); + + MessageProducer queueProducer = ssn.createProducer(new AMQAnyDestination("ADDR:amq.direct")); + MessageProducer topicProducer1 = ssn.createProducer(new AMQAnyDestination("ADDR:amq.topic/usa.weather")); + MessageProducer topicProducer2 = ssn.createProducer(new AMQAnyDestination("ADDR:amq.topic/sales")); + + queueProducer.send(ssn.createBytesMessage()); + assertNotNull("The consumer subscribed to amq.direct " + + "with empty binding key should have received the message ",queueCons.receive(1000)); + + topicProducer1.send(ssn.createTextMessage("25c")); + assertEquals("The consumer subscribed to amq.topic " + + "with '#' binding key should have received the message ", + ((TextMessage)topicCons.receive(1000)).getText(),"25c"); + + topicProducer2.send(ssn.createTextMessage("1000")); + assertEquals("The consumer subscribed to amq.topic " + + "with '#' binding key should have received the message ", + ((TextMessage)topicCons.receive(1000)).getText(),"1000"); + } + + /** + * Test Goal : Verify that 'mode : browse' works as expected using a regular consumer. + * This indirectly tests ring queues as well. + */ + public void testBrowseMode() throws Exception + { + + Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + + String addr = "ADDR:my-ring-queue; {create: always, mode: browse, " + + "node: {x-bindings: [{exchange : 'amq.direct', key : test}], " + + "x-declare:{arguments : {'qpid.policy_type':ring, 'qpid.max_count':2}}}}"; + + Destination dest = ssn.createQueue(addr); + MessageConsumer browseCons = ssn.createConsumer(dest); + MessageProducer prod = ssn.createProducer(ssn.createQueue("ADDR:amq.direct/test")); + + prod.send(ssn.createTextMessage("Test1")); + prod.send(ssn.createTextMessage("Test2")); + + TextMessage msg = (TextMessage)browseCons.receive(1000); + assertEquals("Didn't receive the first message",msg.getText(),"Test1"); + + msg = (TextMessage)browseCons.receive(1000); + assertEquals("Didn't receive the first message",msg.getText(),"Test2"); + + browseCons.close(); + prod.send(ssn.createTextMessage("Test3")); + browseCons = ssn.createConsumer(dest); + + msg = (TextMessage)browseCons.receive(1000); + assertEquals("Should receive the second message again",msg.getText(),"Test2"); + + msg = (TextMessage)browseCons.receive(1000); + assertEquals("Should receive the third message since it's a ring queue",msg.getText(),"Test3"); + + assertNull("Should not receive anymore messages",browseCons.receive(500)); + } + + /** + * Test Goal : When the same destination is used when creating two consumers, + * If the type == topic, verify that unique subscription queues are created, + * unless subscription queue has a name. + * + * If the type == queue, same queue should be shared. + */ + public void testSubscriptionForSameDestination() throws Exception + { + Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + Destination dest = ssn.createTopic("ADDR:amq.topic/foo"); + MessageConsumer consumer1 = ssn.createConsumer(dest); + MessageConsumer consumer2 = ssn.createConsumer(dest); + MessageProducer prod = ssn.createProducer(dest); + + prod.send(ssn.createTextMessage("A")); + TextMessage m = (TextMessage)consumer1.receive(1000); + assertEquals("Consumer1 should recieve message A",m.getText(),"A"); + m = (TextMessage)consumer2.receive(1000); + assertEquals("Consumer2 should recieve message A",m.getText(),"A"); + + consumer1.close(); + consumer2.close(); + + dest = ssn.createTopic("ADDR:amq.topic/foo; { link: {name: my-queue}}"); + consumer1 = ssn.createConsumer(dest); + try + { + consumer2 = ssn.createConsumer(dest); + fail("An exception should be thrown as 'my-queue' already have an exclusive subscriber"); + } + catch(Exception e) + { + } + _connection.close(); + + _connection = getConnection() ; + _connection.start(); + ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + dest = ssn.createTopic("ADDR:my_queue; {create: always}"); + consumer1 = ssn.createConsumer(dest); + consumer2 = ssn.createConsumer(dest); + prod = ssn.createProducer(dest); + + prod.send(ssn.createTextMessage("A")); + Message m1 = consumer1.receive(1000); + Message m2 = consumer2.receive(1000); + + if (m1 != null) + { + assertNull("Only one consumer should receive the message",m2); + } + else + { + assertNotNull("Only one consumer should receive the message",m2); + } + } + + public void testXBindingsWithoutExchangeName() throws Exception + { + Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + String addr = "ADDR:MRKT; " + + "{" + + "create: receiver," + + "node : {type: topic, x-declare: {type: topic} }," + + "link:{" + + "name: my-topic," + + "x-bindings:[{key:'NYSE.#'},{key:'NASDAQ.#'},{key:'CNTL.#'}]" + + "}" + + "}"; + + // Using the ADDR method to create a more complicated topic + Topic topic = ssn.createTopic(addr); + MessageConsumer cons = ssn.createConsumer(topic); + + assertTrue("The queue was not bound to MRKT exchange using NYSE.# as the binding key",( + (AMQSession_0_10)ssn).isQueueBound("MRKT", + "my-topic","NYSE.#", null)); + + assertTrue("The queue was not bound to MRKT exchange using NASDAQ.# as the binding key",( + (AMQSession_0_10)ssn).isQueueBound("MRKT", + "my-topic","NASDAQ.#", null)); + + assertTrue("The queue was not bound to MRKT exchange using CNTL.# as the binding key",( + (AMQSession_0_10)ssn).isQueueBound("MRKT", + "my-topic","CNTL.#", null)); + + MessageProducer prod = ssn.createProducer(topic); + Message msg = ssn.createTextMessage("test"); + msg.setStringProperty("qpid.subject", "NASDAQ.ABCD"); + prod.send(msg); + assertNotNull("consumer should receive a message",cons.receive(1000)); + cons.close(); + } + + public void testXSubscribeOverrides() throws Exception + { + Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + String str = "ADDR:my_queue; {create:always,link: {x-subscribes:{exclusive: true, arguments: {a:b,x:y}}}}"; + Destination dest = ssn.createTopic(str); + MessageConsumer consumer1 = ssn.createConsumer(dest); + try + { + MessageConsumer consumer2 = ssn.createConsumer(dest); + fail("An exception should be thrown as 'my-queue' already have an exclusive subscriber"); + } + catch(Exception e) + { + } + } + + public void testQueueReceiversAndTopicSubscriber() throws Exception + { + Queue queue = new AMQAnyDestination("ADDR:my-queue; {create: always}"); + Topic topic = new AMQAnyDestination("ADDR:amq.topic/test"); + + QueueSession qSession = ((AMQConnection)_connection).createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + QueueReceiver receiver = qSession.createReceiver(queue); + + TopicSession tSession = ((AMQConnection)_connection).createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber sub = tSession.createSubscriber(topic); + + Session ssn = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer prod1 = ssn.createProducer(ssn.createQueue("ADDR:my-queue")); + prod1.send(ssn.createTextMessage("test1")); + + MessageProducer prod2 = ssn.createProducer(ssn.createTopic("ADDR:amq.topic/test")); + prod2.send(ssn.createTextMessage("test2")); + + Message msg1 = receiver.receive(); + assertNotNull(msg1); + assertEquals("test1",((TextMessage)msg1).getText()); + + Message msg2 = sub.receive(); + assertNotNull(msg2); + assertEquals("test2",((TextMessage)msg2).getText()); + } + + public void testDurableSubscriber() throws Exception + { + Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + + String bindingStr = "x-bindings:[{key:'NYSE.#'},{key:'NASDAQ.#'},{key:'CNTL.#'}]}}"; + + Properties props = new Properties(); + props.setProperty("java.naming.factory.initial", "org.apache.qpid.jndi.PropertiesFileInitialContextFactory"); + props.setProperty("destination.address1", "ADDR:amq.topic/test"); + props.setProperty("destination.address2", "ADDR:amq.topic/test; {node:{" + bindingStr); + props.setProperty("destination.address3", "ADDR:amq.topic/test; {link:{" + bindingStr); + String addrStr = "ADDR:my_queue; {create:always,link: {x-subscribes:{exclusive: true, arguments: {a:b,x:y}}}}"; + props.setProperty("destination.address5", addrStr); + + Context ctx = new InitialContext(props); + + for (int i=1; i < 4; i++) + { + Topic topic = (Topic) ctx.lookup("address"+i); + createDurableSubscriber(ctx,ssn,"address"+i,topic,"ADDR:amq.topic/test"); + } + + Topic topic = ssn.createTopic("ADDR:news.us"); + createDurableSubscriber(ctx,ssn,"my-dest",topic,"ADDR:news.us"); + + Topic namedQueue = (Topic) ctx.lookup("address5"); + try + { + createDurableSubscriber(ctx,ssn,"my-queue",namedQueue,"ADDR:amq.topic/test"); + fail("Exception should be thrown. Durable subscribers cannot be created for Queues"); + } + catch(JMSException e) + { + assertEquals("Durable subscribers can only be created for Topics", + e.getMessage()); + } + } + + public void testDurableSubscription() throws Exception + { + Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic("ADDR:amq.topic/" + getTestQueueName()); + MessageProducer publisher = session.createProducer(topic); + MessageConsumer subscriber = session.createDurableSubscriber(topic, getTestQueueName()); + + TextMessage messageToSend = session.createTextMessage("Test0"); + publisher.send(messageToSend); + ((AMQSession)session).sync(); + + Message receivedMessage = subscriber.receive(1000); + assertNotNull("Message has not been received", receivedMessage); + assertEquals("Unexpected message", messageToSend.getText(), ((TextMessage)receivedMessage).getText()); + + subscriber.close(); + + messageToSend = session.createTextMessage("Test1"); + publisher.send(messageToSend); + ((AMQSession)session).sync(); + + subscriber = session.createDurableSubscriber(topic, getTestQueueName()); + receivedMessage = subscriber.receive(1000); + assertNotNull("Message has not been received", receivedMessage); + assertEquals("Unexpected message", messageToSend.getText(), ((TextMessage)receivedMessage).getText()); + } + + public void testDurableSubscriptionnWithSelector() throws Exception + { + Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic("ADDR:amq.topic/" + getTestQueueName()); + MessageProducer publisher = session.createProducer(topic); + MessageConsumer subscriber = session.createDurableSubscriber(topic, getTestQueueName(), "id=1", false); + + TextMessage messageToSend = session.createTextMessage("Test0"); + messageToSend.setIntProperty("id", 1); + publisher.send(messageToSend); + ((AMQSession)session).sync(); + + Message receivedMessage = subscriber.receive(1000); + assertNotNull("Message has not been received", receivedMessage); + assertEquals("Unexpected message", messageToSend.getText(), ((TextMessage)receivedMessage).getText()); + assertEquals("Unexpected id", 1, receivedMessage.getIntProperty("id")); + + subscriber.close(); + + messageToSend = session.createTextMessage("Test1"); + messageToSend.setIntProperty("id", 1); + publisher.send(messageToSend); + ((AMQSession)session).sync(); + + subscriber = session.createDurableSubscriber(topic, getTestQueueName(), "id=1", false); + receivedMessage = subscriber.receive(1000); + assertNotNull("Message has not been received", receivedMessage); + assertEquals("Unexpected message", messageToSend.getText(), ((TextMessage)receivedMessage).getText()); + assertEquals("Unexpected id", 1, receivedMessage.getIntProperty("id")); + } + + private void createDurableSubscriber(Context ctx,Session ssn,String destName,Topic topic, String producerAddr) throws Exception + { + MessageConsumer cons = ssn.createDurableSubscriber(topic, destName); + MessageProducer prod = ssn.createProducer(ssn.createTopic(producerAddr)); + + Message m = ssn.createTextMessage(destName); + prod.send(m); + Message msg = cons.receive(1000); + assertNotNull("Message not received as expected when using Topic : " + topic,msg); + assertEquals(destName,((TextMessage)msg).getText()); + ssn.unsubscribe(destName); + } + + public void testDeleteOptions() throws Exception + { + Session jmsSession = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + MessageConsumer cons; + + // default (create never, assert never) ------------------- + // create never -------------------------------------------- + String addr1 = "ADDR:testQueue1;{create: always, delete: always}"; + AMQDestination dest = new AMQAnyDestination(addr1); + try + { + cons = jmsSession.createConsumer(dest); + cons.close(); + } + catch(JMSException e) + { + fail("Exception should not be thrown. Exception thrown is : " + e); + } + + assertFalse("Queue not deleted as expected",( + (AMQSession_0_10)jmsSession).isQueueExist(dest, false)); + + + String addr2 = "ADDR:testQueue2;{create: always, delete: receiver}"; + dest = new AMQAnyDestination(addr2); + try + { + cons = jmsSession.createConsumer(dest); + cons.close(); + } + catch(JMSException e) + { + fail("Exception should not be thrown. Exception thrown is : " + e); + } + + assertFalse("Queue not deleted as expected",( + (AMQSession_0_10)jmsSession).isQueueExist(dest, false)); + + + String addr3 = "ADDR:testQueue3;{create: always, delete: sender}"; + dest = new AMQAnyDestination(addr3); + try + { + cons = jmsSession.createConsumer(dest); + MessageProducer prod = jmsSession.createProducer(dest); + prod.close(); + } + catch(JMSException e) + { + fail("Exception should not be thrown. Exception thrown is : " + e); + } + + assertFalse("Queue not deleted as expected",( + (AMQSession_0_10)jmsSession).isQueueExist(dest, false)); + } + + /** + * Test Goals : 1. Test if the client sets the correct accept mode for unreliable + * and at-least-once. + * 2. Test default reliability modes for Queues and Topics. + * 3. Test if an exception is thrown if exactly-once is used. + * 4. Test if an exception is thrown if at-least-once is used with topics. + * + * Test Strategy: For goal #1 & #2 + * For unreliable and at-least-once the test tries to receives messages + * in client_ack mode but does not ack the messages. + * It will then close the session, recreate a new session + * and will then try to verify the queue depth. + * For unreliable the messages should have been taken off the queue. + * For at-least-once the messages should be put back onto the queue. + * + */ + + public void testReliabilityOptions() throws Exception + { + String addr1 = "ADDR:testQueue1;{create: always, delete : receiver, link : {reliability : unreliable}}"; + acceptModeTest(addr1,0); + + String addr2 = "ADDR:testQueue2;{create: always, delete : receiver, link : {reliability : at-least-once}}"; + acceptModeTest(addr2,2); + + // Default accept-mode for topics + acceptModeTest("ADDR:amq.topic/test",0); + + // Default accept-mode for queues + acceptModeTest("ADDR:testQueue1;{create: always}",2); + + String addr3 = "ADDR:testQueue2;{create: always, delete : receiver, link : {reliability : exactly-once}}"; + try + { + AMQAnyDestination dest = new AMQAnyDestination(addr3); + fail("An exception should be thrown indicating it's an unsupported type"); + } + catch(Exception e) + { + assertTrue(e.getCause().getMessage().contains("The reliability mode 'exactly-once' is not yet supported")); + } + } + + private void acceptModeTest(String address, int expectedQueueDepth) throws Exception + { + Session ssn = _connection.createSession(false,Session.CLIENT_ACKNOWLEDGE); + MessageConsumer cons; + MessageProducer prod; + + AMQDestination dest = new AMQAnyDestination(address); + cons = ssn.createConsumer(dest); + prod = ssn.createProducer(dest); + + for (int i=0; i < expectedQueueDepth; i++) + { + prod.send(ssn.createTextMessage("Msg" + i)); + } + + for (int i=0; i < expectedQueueDepth; i++) + { + Message msg = cons.receive(1000); + assertNotNull(msg); + assertEquals("Msg" + i,((TextMessage)msg).getText()); + } + + ssn.close(); + ssn = _connection.createSession(false,Session.CLIENT_ACKNOWLEDGE); + long queueDepth = ((AMQSession) ssn).getQueueDepth(dest); + assertEquals(expectedQueueDepth,queueDepth); + cons.close(); + prod.close(); + } + + public void testDestinationOnSend() throws Exception + { + Session ssn = _connection.createSession(false,Session.CLIENT_ACKNOWLEDGE); + MessageConsumer cons = ssn.createConsumer(ssn.createTopic("ADDR:amq.topic/test")); + MessageProducer prod = ssn.createProducer(null); + + Topic queue = ssn.createTopic("ADDR:amq.topic/test"); + prod.send(queue,ssn.createTextMessage("A")); + + Message msg = cons.receive(1000); + assertNotNull(msg); + assertEquals("A",((TextMessage)msg).getText()); + prod.close(); + cons.close(); + } + + public void testReplyToWithNamelessExchange() throws Exception + { + System.setProperty("qpid.declare_exchanges","false"); + replyToTest("ADDR:my-queue;{create: always}"); + System.setProperty("qpid.declare_exchanges","true"); + } + + public void testReplyToWithCustomExchange() throws Exception + { + replyToTest("ADDR:hello;{create:always,node:{type:topic}}"); + } + + private void replyToTest(String replyTo) throws Exception + { + Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination replyToDest = AMQDestination.createDestination(replyTo); + MessageConsumer replyToCons = session.createConsumer(replyToDest); + + Destination dest = session.createQueue("ADDR:amq.direct/test"); + + MessageConsumer cons = session.createConsumer(dest); + MessageProducer prod = session.createProducer(dest); + Message m = session.createTextMessage("test"); + m.setJMSReplyTo(replyToDest); + prod.send(m); + + Message msg = cons.receive(); + MessageProducer prodR = session.createProducer(msg.getJMSReplyTo()); + prodR.send(session.createTextMessage("x")); + + Message m1 = replyToCons.receive(); + assertNotNull("The reply to consumer should have received the messsage",m1); + } + + public void testAltExchangeInAddressString() throws Exception + { + String addr1 = "ADDR:my-exchange/test; {create: always, node:{type: topic,x-declare:{alternate-exchange:'amq.fanout'}}}"; + Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + String altQueueAddr = "ADDR:my-alt-queue;{create: always, delete: receiver,node:{x-bindings:[{exchange:'amq.fanout'}] }}"; + MessageConsumer cons = session.createConsumer(session.createQueue(altQueueAddr)); + + MessageProducer prod = session.createProducer(session.createTopic(addr1)); + prod.send(session.createMessage()); + prod.close(); + assertNotNull("The consumer on the queue bound to the alt-exchange should receive the message",cons.receive(1000)); + + String addr2 = "ADDR:test-queue;{create:sender, delete: sender,node:{type:queue,x-declare:{alternate-exchange:'amq.fanout'}}}"; + prod = session.createProducer(session.createTopic(addr2)); + prod.send(session.createMessage()); + prod.close(); + assertNotNull("The consumer on the queue bound to the alt-exchange should receive the message",cons.receive(1000)); + cons.close(); + } + + public void testUnknownAltExchange() throws Exception + { + Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + String altQueueAddr = "ADDR:my-alt-queue;{create: always, delete: receiver,node:{x-bindings:[{exchange:'doesnotexist'}] }}"; + try + { + session.createConsumer(session.createQueue(altQueueAddr)); + fail("Attempt to create a queue with an unknown alternate exchange should fail"); + } + catch(JMSException e) + { + assertEquals("Failure code is not as expected", "404", e.getErrorCode()); + } + } + + public void testUnknownExchangeType() throws Exception + { + createExchangeImpl(false, false, true); + } + + public void testQueueBrowserWithSelectorAutoAcknowledgement() throws Exception + { + assertQueueBrowserWithSelector(Session.AUTO_ACKNOWLEDGE); + } + + public void testQueueBrowserWithSelectorClientAcknowldgement() throws Exception + { + assertQueueBrowserWithSelector(Session.CLIENT_ACKNOWLEDGE); + } + + public void testQueueBrowserWithSelectorTransactedSession() throws Exception + { + assertQueueBrowserWithSelector(Session.SESSION_TRANSACTED); + } + + public void testConsumerWithSelectorAutoAcknowledgement() throws Exception + { + assertConsumerWithSelector(Session.AUTO_ACKNOWLEDGE); + } + + public void testConsumerWithSelectorClientAcknowldgement() throws Exception + { + assertConsumerWithSelector(Session.CLIENT_ACKNOWLEDGE); + } + + public void testConsumerWithSelectorTransactedSession() throws Exception + { + assertConsumerWithSelector(Session.SESSION_TRANSACTED); + } + + private void assertQueueBrowserWithSelector(int acknowledgement) throws Exception + { + String queueAddress = "ADDR:" + getTestQueueName() + ";{create: always}"; + + boolean transacted = acknowledgement == Session.SESSION_TRANSACTED; + Session session = _connection.createSession(transacted, acknowledgement); + + Queue queue = session.createQueue(queueAddress); + + final int numberOfMessages = 10; + List sentMessages = sendMessage(session, queue, numberOfMessages); + assertNotNull("Messages were not sent", sentMessages); + assertEquals("Unexpected number of messages were sent", numberOfMessages, sentMessages.size()); + + QueueBrowser browser = session.createBrowser(queue, INDEX + "%2=0"); + _connection.start(); + + Enumeration enumaration = browser.getEnumeration(); + + int counter = 0; + int expectedIndex = 0; + while (enumaration.hasMoreElements()) + { + Message m = enumaration.nextElement(); + assertNotNull("Expected not null message at step " + counter, m); + int messageIndex = m.getIntProperty(INDEX); + assertEquals("Unexpected index", expectedIndex, messageIndex); + expectedIndex += 2; + counter++; + } + assertEquals("Unexpected number of messsages received", 5, counter); + } + + private void assertConsumerWithSelector(int acknowledgement) throws Exception + { + String queueAddress = "ADDR:" + getTestQueueName() + ";{create: always}"; + + boolean transacted = acknowledgement == Session.SESSION_TRANSACTED; + Session session = _connection.createSession(transacted, acknowledgement); + + Queue queue = session.createQueue(queueAddress); + + final int numberOfMessages = 10; + List sentMessages = sendMessage(session, queue, numberOfMessages); + assertNotNull("Messages were not sent", sentMessages); + assertEquals("Unexpected number of messages were sent", numberOfMessages, sentMessages.size()); + + MessageConsumer consumer = session.createConsumer(queue, INDEX + "%2=0"); + + int expectedIndex = 0; + for (int i = 0; i < 5; i++) + { + Message m = consumer.receive(RECEIVE_TIMEOUT); + assertNotNull("Expected not null message at step " + i, m); + int messageIndex = m.getIntProperty(INDEX); + assertEquals("Unexpected index", expectedIndex, messageIndex); + expectedIndex += 2; + + if (transacted) + { + session.commit(); + } + else if (acknowledgement == Session.CLIENT_ACKNOWLEDGE) + { + m.acknowledge(); + } + } + + Message m = consumer.receive(RECEIVE_TIMEOUT); + assertNull("Unexpected message received", m); + } + + /** + * Tests that a client using a session in {@link Session#CLIENT_ACKNOWLEDGE} can correctly + * recover a session and re-receive the same message. + */ + public void testTopicRereceiveAfterRecover() throws Exception + { + final Session jmsSession = _connection.createSession(false,Session.CLIENT_ACKNOWLEDGE); + final Destination topic = jmsSession.createTopic("ADDR:amq.topic/topic1; {link:{name: queue1}}"); + + final MessageProducer prod = jmsSession.createProducer(topic); + final MessageConsumer consForTopic1 = jmsSession.createConsumer(topic); + final Message sentMessage = jmsSession.createTextMessage("Hello"); + + prod.send(sentMessage); + Message receivedMessage = consForTopic1.receive(1000); + assertNotNull("message should be received by consumer", receivedMessage); + + jmsSession.recover(); + receivedMessage = consForTopic1.receive(1000); + assertNotNull("message should be re-received by consumer after recover", receivedMessage); + receivedMessage.acknowledge(); + } + + /** + * Tests that a client using a session in {@link Session#SESSION_TRANSACTED} can correctly + * rollback a session and re-receive the same message. + */ + public void testTopicRereceiveAfterRollback() throws Exception + { + final Session jmsSession = _connection.createSession(true,Session.SESSION_TRANSACTED); + final Destination topic = jmsSession.createTopic("ADDR:amq.topic/topic1; {link:{name: queue1}}"); + + final MessageProducer prod = jmsSession.createProducer(topic); + final MessageConsumer consForTopic1 = jmsSession.createConsumer(topic); + final Message sentMessage = jmsSession.createTextMessage("Hello"); + + prod.send(sentMessage); + jmsSession.commit(); + + Message receivedMessage = consForTopic1.receive(1000); + assertNotNull("message should be received by consumer", receivedMessage); + + jmsSession.rollback(); + receivedMessage = consForTopic1.receive(1000); + assertNotNull("message should be re-received by consumer after rollback", receivedMessage); + jmsSession.commit(); + } + + /** + * Test Goals : + * + * 1. Verify that link bindings are created and destroyed after creating and closing a subscriber. + * 2. Verify that link bindings are created and destroyed after creating and closing a subscriber. + */ + public void testLinkBindingBehavior() throws Exception + { + Session jmsSession = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + String addr = "ADDR:my-queue; {create: always, " + + "link: " + + "{" + + "x-bindings: [{exchange : 'amq.direct', key : test}]," + + "}" + + "}"; + + AMQDestination dest = (AMQDestination)jmsSession.createQueue(addr); + MessageConsumer cons = jmsSession.createConsumer(dest); + AMQSession_0_10 ssn = (AMQSession_0_10)jmsSession; + + assertTrue("Queue not created as expected",ssn.isQueueExist(dest, true)); + assertTrue("Queue not bound as expected",ssn.isQueueBound("amq.direct","my-queue","test", null)); + + cons.close(); // closing consumer, link binding should be removed now. + assertTrue("Queue should still be there",ssn.isQueueExist(dest, true)); + assertFalse("Binding should not exist anymore",ssn.isQueueBound("amq.direct","my-queue","test", null)); + + MessageProducer prod = jmsSession.createProducer(dest); + assertTrue("Queue not bound as expected",ssn.isQueueBound("amq.direct","my-queue","test", null)); + prod.close(); + assertFalse("Binding should not exist anymore",ssn.isQueueBound("amq.direct","my-queue","test", null)); + } + + /** + * Test Goals : Verifies that the subscription queue created is as specified under link properties. + */ + public void testCustomizingSubscriptionQueue() throws Exception + { + Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + String xDeclareArgs = "x-declare: { exclusive: false, auto-delete: false," + + "alternate-exchange: 'amq.fanout'," + + "arguments: {'qpid.alert_size': 1000,'qpid.alert_count': 100}" + + "}"; + + String addr = "ADDR:amq.topic/test; {link: {name:my-queue, durable:true," + xDeclareArgs + "}}"; + Destination dest = ssn.createTopic(addr); + MessageConsumer cons = ssn.createConsumer(dest); + + String verifyAddr = "ADDR:my-queue;{ node: {durable:true, " + xDeclareArgs + "}}"; + AMQDestination verifyDest = (AMQDestination)ssn.createQueue(verifyAddr); + ((AMQSession_0_10)ssn).isQueueExist(verifyDest, true); + + // Verify that the producer does not delete the subscription queue. + MessageProducer prod = ssn.createProducer(dest); + prod.close(); + ((AMQSession_0_10)ssn).isQueueExist(verifyDest, true); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/failover/FailoverTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/failover/FailoverTest.java new file mode 100644 index 0000000000..2875e2c6b1 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/failover/FailoverTest.java @@ -0,0 +1,349 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.test.client.failover; + +import org.apache.log4j.Logger; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.jms.ConnectionListener; +import org.apache.qpid.test.utils.FailoverBaseCase; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import java.util.Random; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class FailoverTest extends FailoverBaseCase implements ConnectionListener +{ + private static final Logger _logger = Logger.getLogger(FailoverTest.class); + + private static final int DEFAULT_NUM_MESSAGES = 10; + private static final int DEFAULT_SEED = 20080921; + protected int numMessages = 0; + protected Connection connection; + private Session producerSession; + private Queue queue; + private MessageProducer producer; + private Session consumerSession; + private MessageConsumer consumer; + + private CountDownLatch failoverComplete; + private boolean CLUSTERED = Boolean.getBoolean("profile.clustered"); + private int seed; + private Random rand; + private int _currentPort = getFailingPort(); + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + numMessages = Integer.getInteger("profile.failoverMsgCount",DEFAULT_NUM_MESSAGES); + seed = Integer.getInteger("profile.failoverRandomSeed",DEFAULT_SEED); + rand = new Random(seed); + + connection = getConnection(); + ((AMQConnection) connection).setConnectionListener(this); + connection.start(); + failoverComplete = new CountDownLatch(1); + } + + private void init(boolean transacted, int mode) throws Exception + { + consumerSession = connection.createSession(transacted, mode); + queue = consumerSession.createQueue(getName()+System.currentTimeMillis()); + consumer = consumerSession.createConsumer(queue); + + producerSession = connection.createSession(transacted, mode); + producer = producerSession.createProducer(queue); + } + + @Override + public void tearDown() throws Exception + { + try + { + connection.close(); + } + catch (Exception e) + { + + } + + super.tearDown(); + } + + private void consumeMessages(int startIndex,int endIndex, boolean transacted) throws JMSException + { + Message msg; + _logger.debug("**************** Receive (Start: " + startIndex + ", End:" + endIndex + ")***********************"); + + for (int i = startIndex; i < endIndex; i++) + { + msg = consumer.receive(1000); + assertNotNull("Message " + i + " was null!", msg); + + _logger.debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + _logger.debug("Received : " + ((TextMessage) msg).getText()); + _logger.debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + + assertEquals("Invalid message order","message " + i, ((TextMessage) msg).getText()); + + } + _logger.debug("***********************************************************"); + + if (transacted) + { + consumerSession.commit(); + } + } + + private void sendMessages(int startIndex,int endIndex, boolean transacted) throws Exception + { + _logger.debug("**************** Send (Start: " + startIndex + ", End:" + endIndex + ")***********************"); + + for (int i = startIndex; i < endIndex; i++) + { + producer.send(producerSession.createTextMessage("message " + i)); + + _logger.debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + _logger.debug("Sending message"+i); + _logger.debug("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + } + + _logger.debug("***********************************************************"); + + if (transacted) + { + producerSession.commit(); + } + else + { + ((AMQSession)producerSession).sync(); + } + } + + public void testP2PFailover() throws Exception + { + testP2PFailover(numMessages, true,true, false); + } + + public void testP2PFailoverWithMessagesLeftToConsumeAndProduce() throws Exception + { + if (CLUSTERED) + { + testP2PFailover(numMessages, false,false, false); + } + } + + public void testP2PFailoverWithMessagesLeftToConsume() throws Exception + { + if (CLUSTERED) + { + testP2PFailover(numMessages, false, true, false); + } + } + + public void testP2PFailoverTransacted() throws Exception + { + testP2PFailover(numMessages, true,true, true); + } + + public void testP2PFailoverTransactedWithMessagesLeftToConsumeAndProduce() throws Exception + { + // Currently the cluster does not support transactions that span a failover + if (CLUSTERED) + { + testP2PFailover(numMessages, false, false, false); + } + } + private void testP2PFailover(int totalMessages, boolean consumeAll, boolean produceAll , boolean transacted) throws Exception + { + init(transacted, Session.AUTO_ACKNOWLEDGE); + runP2PFailover(totalMessages,consumeAll, produceAll , transacted); + } + + private void runP2PFailover(int totalMessages, boolean consumeAll, boolean produceAll , boolean transacted) throws Exception + { + int toProduce = totalMessages; + + _logger.debug("==================================================================="); + _logger.debug("Total messages used for the test " + totalMessages + " messages"); + _logger.debug("==================================================================="); + + if (!produceAll) + { + toProduce = totalMessages - rand.nextInt(totalMessages); + } + + _logger.debug("=================="); + _logger.debug("Sending " + toProduce + " messages"); + _logger.debug("=================="); + + sendMessages(0,toProduce, transacted); + + // Consume some messages + int toConsume = toProduce; + if (!consumeAll) + { + toConsume = toProduce - rand.nextInt(toProduce); + } + + consumeMessages(0,toConsume, transacted); + + _logger.debug("=================="); + _logger.debug("Consuming " + toConsume + " messages"); + _logger.debug("=================="); + + _logger.info("Failing over"); + + causeFailure(_currentPort, DEFAULT_FAILOVER_TIME); + + // Check that you produce and consume the rest of messages. + _logger.debug("=================="); + _logger.debug("Sending " + (totalMessages-toProduce) + " messages"); + _logger.debug("=================="); + + sendMessages(toProduce,totalMessages, transacted); + consumeMessages(toConsume,totalMessages, transacted); + + _logger.debug("=================="); + _logger.debug("Consuming " + (totalMessages-toConsume) + " messages"); + _logger.debug("=================="); + } + + private void causeFailure(int port, long delay) + { + + failBroker(port); + + _logger.info("Awaiting Failover completion"); + try + { + if (!failoverComplete.await(delay, TimeUnit.MILLISECONDS)) + { + fail("failover did not complete"); + } + } + catch (InterruptedException e) + { + //evil ignore IE. + } + } + + public void testClientAckFailover() throws Exception + { + init(false, Session.CLIENT_ACKNOWLEDGE); + sendMessages(0,1, false); + Message msg = consumer.receive(); + assertNotNull("Expected msgs not received", msg); + + causeFailure(getFailingPort(), DEFAULT_FAILOVER_TIME); + + Exception failure = null; + try + { + msg.acknowledge(); + } + catch (Exception e) + { + failure = e; + } + assertNotNull("Exception should be thrown", failure); + } + + /** + * The idea is to run a failover test in a loop by failing over + * to the other broker each time. + */ + public void testFailoverInALoop() throws Exception + { + if (!CLUSTERED) + { + return; + } + + int iterations = Integer.getInteger("profile.failoverIterations",0); + boolean useAltPort = false; + int altPort = FAILING_PORT; + int stdPort = DEFAULT_PORT; + init(false, Session.AUTO_ACKNOWLEDGE); + for (int i=0; i < iterations; i++) + { + _logger.debug("==================================================================="); + _logger.debug("Failover In a loop : iteration number " + i); + _logger.debug("==================================================================="); + + runP2PFailover(numMessages, false,false, false); + startBroker(_currentPort); + if (useAltPort) + { + _currentPort = altPort; + useAltPort = false; + } + else + { + _currentPort = stdPort; + useAltPort = true; + } + + } + //To prevent any failover logic being initiated when we shutdown the brokers. + connection.close(); + + // Shutdown the brokers + stopBroker(altPort); + stopBroker(stdPort); + + } + + 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() + { + failoverComplete.countDown(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/JMSDestinationTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/JMSDestinationTest.java new file mode 100644 index 0000000000..760884e654 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/JMSDestinationTest.java @@ -0,0 +1,359 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.client.message; + +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.client.CustomJMSXProperty; +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.management.common.mbeans.ManagedQueue; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +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.Topic; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.TabularData; + +import java.util.Iterator; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * From the API Docs getJMSDestination: + * + * When a message is received, its JMSDestination value must be equivalent to + * the value assigned when it was sent. + */ +public class JMSDestinationTest extends QpidBrokerTestCase +{ + + private Connection _connection; + private Session _session; + + private CountDownLatch _receiveMessage; + private Message _message; + + public void setUp() throws Exception + { + getBrokerConfiguration().addJmxManagementConfiguration(); + + super.setUp(); + + _connection = getConnection(); + + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + /** + * Test a message sent to a queue comes back with JMSDestination queue + * + * @throws Exception + */ + public void testQueue() throws Exception + { + + Queue queue = _session.createQueue(getTestQueueName()); + + MessageConsumer consumer = _session.createConsumer(queue); + + sendMessage(_session, queue, 1); + + _connection.start(); + + Message receivedMessage = consumer.receive(10000); + + assertNotNull("Message should not be null", receivedMessage); + + Destination receivedDestination = receivedMessage.getJMSDestination(); + + assertNotNull("JMSDestination should not be null", receivedDestination); + + assertEquals("Incorrect Destination type", queue.getClass(), receivedDestination.getClass()); + } + + /** + * Test a message sent to a topic comes back with JMSDestination topic + * + * @throws Exception + */ + public void testTopic() throws Exception + { + + Topic topic = _session.createTopic(getTestQueueName() + "Topic"); + + MessageConsumer consumer = _session.createConsumer(topic); + + sendMessage(_session, topic, 1); + + _connection.start(); + + Message receivedMessage = consumer.receive(10000); + + assertNotNull("Message should not be null", receivedMessage); + + Destination receivedDestination = receivedMessage.getJMSDestination(); + + assertNotNull("JMSDestination should not be null", receivedDestination); + assertEquals("Incorrect Destination type", topic.getClass(), receivedDestination.getClass()); + } + + /** + * Test a message sent to a topic then moved on the broker + * comes back with JMSDestination queue. + * + * i.e. The client is not just setting the value to be the same as the + * current consumer destination. + * + * This test can only be run against the Java broker as it uses JMX to move + * messages between queues. + * + * @throws Exception + */ + public void testMovedToQueue() throws Exception + { + // Setup JMXUtils + JMXTestUtils jmxUtils = new JMXTestUtils(this); + + // Open the JMX Connection + jmxUtils.open(); + try + { + + Queue queue = _session.createQueue(getTestQueueName()); + + _session.createConsumer(queue).close(); + + sendMessage(_session, queue, 1); + + Topic topic = _session.createTopic(getTestQueueName() + "Topic"); + + MessageConsumer consumer = _session.createConsumer(topic); + + // Use Management to move message. + + ManagedQueue managedQueue = jmxUtils. + getManagedObject(ManagedQueue.class, + jmxUtils.getQueueObjectName(getConnectionFactory().getVirtualPath().substring(1), + getTestQueueName())); + + // Find the first message on the queue + TabularData data = managedQueue.viewMessages(1L, 2L); + + Iterator values = data.values().iterator(); + assertTrue("No Messages found via JMX", values.hasNext()); + + // Get its message ID + Long msgID = (Long) ((CompositeDataSupport) values.next()).get("AMQ MessageId"); + + // Start the connection and consume message that has been moved to the + // queue + _connection.start(); + + Message message = consumer.receive(1000); + + //Validate we don't have a message on the queue before we start + assertNull("Message should be null", message); + + // Move it to from the topic to the queue + managedQueue.moveMessages(msgID, msgID, ((AMQTopic) topic).getQueueName()); + + // Retrieve the newly moved message + message = consumer.receive(1000); + + assertNotNull("Message should not be null", message); + + Destination receivedDestination = message.getJMSDestination(); + + assertNotNull("JMSDestination should not be null", receivedDestination); + + assertEquals("Incorrect Destination type", queue.getClass(), receivedDestination.getClass()); + + } + finally + { + jmxUtils.close(); + } + + } + + /** + * Test a message sent to a queue comes back with JMSDestination queue + * when received via a message listener + * + * @throws Exception + */ + public void testQueueAsync() throws Exception + { + + Queue queue = _session.createQueue(getTestQueueName()); + + MessageConsumer consumer = _session.createConsumer(queue); + + sendMessage(_session, queue, 1); + + _connection.start(); + + _message = null; + _receiveMessage = new CountDownLatch(1); + + consumer.setMessageListener(new MessageListener() + { + public void onMessage(Message message) + { + _message = message; + _receiveMessage.countDown(); + } + }); + + assertTrue("Timed out waiting for message to be received ", _receiveMessage.await(1, TimeUnit.SECONDS)); + + assertNotNull("Message should not be null", _message); + + Destination receivedDestination = _message.getJMSDestination(); + + assertNotNull("JMSDestination should not be null", receivedDestination); + + assertEquals("Incorrect Destination type", queue.getClass(), receivedDestination.getClass()); + } + + /** + * Test a message received without the JMS_QPID_DESTTYPE can be resent + * and correctly have the property set. + * + * To do this we need to create a 0-10 connection and send a message + * which is then received by a 0-8/9 client. + * + * @throws Exception + */ + public void testReceiveResend() throws Exception + { + // Create a 0-10 Connection and send message + setSystemProperty(ClientProperties.AMQP_VERSION, "0-10"); + + Connection connection010 = getConnection(); + + Session session010 = connection010.createSession(true, Session.SESSION_TRANSACTED); + + // Create queue for testing + Queue queue = session010.createQueue(getTestQueueName()); + + // Ensure queue exists + session010.createConsumer(queue).close(); + + sendMessage(session010, queue, 1); + + // Close the 010 connection + connection010.close(); + + // Create a 0-8 Connection and receive message + setSystemProperty(ClientProperties.AMQP_VERSION, "0-8"); + + Connection connection08 = getConnection(); + + Session session08 = connection08.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageConsumer consumer = session08.createConsumer(queue); + + connection08.start(); + + Message message = consumer.receive(1000); + + assertNotNull("Didn't receive 0-10 message.", message); + + // Validate that JMS_QPID_DESTTYPE is not set + try + { + message.getIntProperty(CustomJMSXProperty.JMS_QPID_DESTTYPE.toString()); + fail("JMS_QPID_DESTTYPE should not be set, so should throw NumberFormatException"); + } + catch (NumberFormatException nfe) + { + + } + + // Resend message back to queue and validate that + // a) getJMSDestination works without the JMS_QPID_DESTTYPE + // b) we can actually send without a BufferOverFlow. + + MessageProducer producer = session08.createProducer(queue); + producer.send(message); + + message = consumer.receive(1000); + + assertNotNull("Didn't receive recent 0-8 message.", message); + + // Validate that JMS_QPID_DESTTYPE is not set + assertEquals("JMS_QPID_DESTTYPE should be set to a Queue", AMQDestination.QUEUE_TYPE, + message.getIntProperty(CustomJMSXProperty.JMS_QPID_DESTTYPE.toString())); + + } + + public void testQueueWithBindingUrlUsingCustomExchange() throws Exception + { + String exchangeName = "exch_" + getTestQueueName(); + String queueName = "queue_" + getTestQueueName(); + + String address = String.format("direct://%s/%s/%s?routingkey='%s'", exchangeName, queueName, queueName, queueName); + sendReceive(address); + } + + public void testQueueWithBindingUrlUsingAmqDirectExchange() throws Exception + { + String queueName = getTestQueueName(); + String address = String.format("direct://amq.direct/%s/%s?routingkey='%s'", queueName, queueName, queueName); + sendReceive(address); + } + + public void testQueueWithBindingUrlUsingDefaultExchange() throws Exception + { + String queueName = getTestQueueName(); + String address = String.format("direct:///%s/%s?routingkey='%s'", queueName, queueName, queueName); + sendReceive(address); + } + + private void sendReceive(String address) throws JMSException, Exception + { + Destination dest = _session.createQueue(address); + MessageConsumer consumer = _session.createConsumer(dest); + + _connection.start(); + + sendMessage(_session, dest, 1); + + Message receivedMessage = consumer.receive(10000); + + assertNotNull("Message should not be null", receivedMessage); + + Destination receivedDestination = receivedMessage.getJMSDestination(); + + assertNotNull("JMSDestination should not be null", receivedDestination); + assertEquals("JMSDestination should match that sent", address, receivedDestination.toString()); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/JMSReplyToTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/JMSReplyToTest.java new file mode 100644 index 0000000000..fe8180d6c6 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/JMSReplyToTest.java @@ -0,0 +1,169 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.client.message; + +import java.util.concurrent.atomic.AtomicReference; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.IllegalStateException; +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.TemporaryQueue; + +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +/** + * Tests that {@link Message#setJMSReplyTo(Destination)} can be used to pass a {@link Destination} between + * messaging clients as is commonly used in request/response messaging pattern implementations. + */ +public class JMSReplyToTest extends QpidBrokerTestCase +{ + private AtomicReference _caughtException = new AtomicReference(); + private Queue _requestQueue; + private Connection _connection; + private Session _session; + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + _requestQueue = startAsyncRespondingJmsConsumerOnSeparateConnection(); + + _connection = getConnection(); + _connection.start(); + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + } + + public void testRequestResponseUsingJmsReplyTo() throws Exception + { + final String responseQueueName = getTestQueueName() + ".response"; + Queue replyToQueue = _session.createQueue(responseQueueName); + sendRequestAndValidateResponse(replyToQueue); + } + + public void testRequestResponseUsingTemporaryJmsReplyTo() throws Exception + { + TemporaryQueue replyToQueue = _session.createTemporaryQueue(); + + sendRequestAndValidateResponse(replyToQueue); + } + + private void sendRequestAndValidateResponse(Queue replyToQueue) throws JMSException, Exception + { + MessageConsumer replyConsumer = _session.createConsumer(replyToQueue); + + Message requestMessage = createRequestMessageWithJmsReplyTo(_session, replyToQueue); + sendRequest(_requestQueue, _session, requestMessage); + + receiveAndValidateResponse(replyConsumer, requestMessage); + + assertNull("Async responder caught unexpected exception", _caughtException.get()); + } + + private Message createRequestMessageWithJmsReplyTo(Session session, Queue replyToQueue) + throws JMSException + { + Message requestMessage = session.createTextMessage("My request"); + requestMessage.setJMSReplyTo(replyToQueue); + return requestMessage; + } + + private void sendRequest(final Queue requestQueue, Session session, Message requestMessage) throws Exception + { + MessageProducer producer = session.createProducer(requestQueue); + producer.send(requestMessage); + } + + private void receiveAndValidateResponse(MessageConsumer replyConsumer, Message requestMessage) throws JMSException + { + Message responseMessage = replyConsumer.receive(RECEIVE_TIMEOUT); + assertNotNull("Response message not received", responseMessage); + assertEquals("Correlation id of the response should match message id of the request", + responseMessage.getJMSCorrelationID(), requestMessage.getJMSMessageID()); + } + + private Queue startAsyncRespondingJmsConsumerOnSeparateConnection() throws Exception + { + final String requestQueueName = getTestQueueName() + ".request"; + final Connection responderConnection = getConnection(); + responderConnection.start(); + final Session responderSession = responderConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Queue requestQueue = responderSession.createQueue(requestQueueName); + + final MessageConsumer requestConsumer = responderSession.createConsumer(requestQueue); + requestConsumer.setMessageListener(new AsyncResponder(responderSession)); + + return requestQueue; + } + + private final class AsyncResponder implements MessageListener + { + private final Session _responderSession; + + private AsyncResponder(Session responderSession) + { + _responderSession = responderSession; + } + + @Override + public void onMessage(Message requestMessage) + { + try + { + Destination replyTo = getReplyToQueue(requestMessage); + + Message responseMessage = _responderSession.createMessage(); + responseMessage.setJMSCorrelationID(requestMessage.getJMSMessageID()); + + sendResponseToQueue(replyTo, responseMessage); + } + catch (Throwable t) + { + _caughtException.set(t); + } + } + + private Destination getReplyToQueue(Message requestMessage) throws JMSException, IllegalStateException + { + Destination replyTo = requestMessage.getJMSReplyTo(); + if (replyTo == null) + { + throw new IllegalStateException("JMSReplyTo was null on message " + requestMessage); + } + return replyTo; + } + + private void sendResponseToQueue(Destination replyTo, Message responseMessage) + throws JMSException + { + MessageProducer responseProducer = _responderSession.createProducer(replyTo); + responseProducer.send(responseMessage); + } + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/MessageToStringTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/MessageToStringTest.java new file mode 100644 index 0000000000..dc1f690b1e --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/MessageToStringTest.java @@ -0,0 +1,255 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.client.message; + +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.MapMessage; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.ObjectMessage; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.StreamMessage; +import javax.jms.TextMessage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutput; +import java.io.ObjectOutputStream; +import java.util.UUID; + +public class MessageToStringTest extends QpidBrokerTestCase +{ + private Connection _connection; + private Session _session; + private Queue _queue; + private MessageConsumer _consumer; + private static final String BYTE_TEST = "MapByteTest"; + + public void setUp() throws Exception + { + super.setUp(); + + //Create Producer put some messages on the queue + _connection = getConnection(); + + //Create Consumer + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + String queueName = getTestQueueName(); + + //Create Queue + ((AMQSession) _session).createQueue(new AMQShortString(queueName), true, false, false); + _queue = _session.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='false'&autodelete='true'"); + + + _consumer = _session.createConsumer(_queue); + + _connection.start(); + } + + public void tearDown() throws Exception + { + //clean up + _connection.close(); + + super.tearDown(); + } + + public void testBytesMessage() throws JMSException + { + //Create Sample Message using UUIDs + UUID test = UUID.randomUUID(); + + BytesMessage testMessage = _session.createBytesMessage(); + + //Convert UUID into bytes for transit + byte[] testBytes = test.toString().getBytes(); + + testMessage.writeBytes(testBytes); + + sendAndTest(testMessage, testBytes); + } + + public void testMapMessage() throws JMSException, IOException + { + //Create Sample Message using UUIDs + UUID test = UUID.randomUUID(); + + MapMessage testMessage = _session.createMapMessage(); + + byte[] testBytes = convertToBytes(test); + + testMessage.setBytes(BYTE_TEST, testBytes); + + sendAndTest(testMessage, testBytes); + } + + public void testObjectMessage() throws JMSException + { + MessageProducer producer = _session.createProducer(_queue); + + //Create Sample Message using UUIDs + UUID test = UUID.randomUUID(); + + Message testMessage = _session.createObjectMessage(test); + + sendAndTest(testMessage, test); + } + + public void testStreamMessage() throws JMSException, IOException + { + //Create Sample Message using UUIDs + UUID test = UUID.randomUUID(); + + StreamMessage testMessage = _session.createStreamMessage(); + + byte[] testBytes = convertToBytes(test); + + testMessage.writeBytes(testBytes); + + sendAndTest(testMessage, testBytes); + } + + public void testTextMessage() throws JMSException, IOException + { + //Create Sample Message using UUIDs + UUID test = UUID.randomUUID(); + + TextMessage testMessage = _session.createTextMessage(); + + String stringValue = String.valueOf(test); + byte[] testBytes = stringValue.getBytes(); + + testMessage.setText(stringValue); + + sendAndTest(testMessage, testBytes); + } + + //***************** Helpers + + private void sendAndTest(Message message, Object testBytes) throws JMSException + { + MessageProducer producer = _session.createProducer(_queue); + + producer.send(message); + + Message receivedMessage = _consumer.receive(1000); + + assertNotNull("Message was not received.", receivedMessage); + + //Ensure that to calling toString doesn't error and that doing this doesn't break next tests. + assertNotNull("Message returned null from toString", receivedMessage.toString()); + + byte[] byteResults; + UUID result; + + try + { + if (receivedMessage instanceof ObjectMessage) + { + result = (UUID) ((ObjectMessage) receivedMessage).getObject(); + assertEquals("UUIDs were not equal", testBytes, result); + } + else + { + byteResults = getBytes(receivedMessage, ((byte[]) testBytes).length); + assertBytesEquals("UUIDs were not equal", (byte[]) testBytes, byteResults); + } + } + catch (Exception e) + { + fail(e.getMessage()); + } + + } + + private void assertBytesEquals(String message, byte[] expected, byte[] actual) + { + if (expected.length == actual.length) + { + int index = 0; + boolean failed = false; + for (byte b : expected) + { + if (actual[index++] != b) + { + failed = true; + break; + } + } + + if (!failed) + { + return; + } + + } + + fail(message); + } + + private byte[] getBytes(Message receivedMessage, int testBytesLength) throws JMSException + { + byte[] byteResults = new byte[testBytesLength]; + + if (receivedMessage instanceof BytesMessage) + { + assertEquals(testBytesLength, ((BytesMessage) receivedMessage).readBytes(byteResults)); + } + else if (receivedMessage instanceof StreamMessage) + { + assertEquals(testBytesLength, ((StreamMessage) receivedMessage).readBytes(byteResults)); + } + else if (receivedMessage instanceof MapMessage) + { + byteResults = ((MapMessage) receivedMessage).getBytes(BYTE_TEST); + assertEquals(testBytesLength, byteResults.length); + } + else if (receivedMessage instanceof TextMessage) + { + byteResults = ((TextMessage) receivedMessage).getText().getBytes(); + assertEquals(testBytesLength, byteResults.length); + } + + + return byteResults; + } + + private byte[] convertToBytes(UUID test) throws IOException + { + //Convert UUID into bytes for transit + ObjectOutput out; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + out = new ObjectOutputStream(bos); + out.writeObject(test); + out.close(); + + return bos.toByteArray(); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/ObjectMessageTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/ObjectMessageTest.java new file mode 100644 index 0000000000..3bd2c4a44e --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/ObjectMessageTest.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.test.client.message; + +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.ObjectMessage; +import javax.jms.Queue; +import javax.jms.Session; +import java.util.UUID; + +public class ObjectMessageTest extends QpidBrokerTestCase +{ + private Connection _connection; + private Session _session; + private MessageConsumer _consumer; + private MessageProducer _producer; + + public void setUp() throws Exception + { + super.setUp(); + + //Create Connection + _connection = getConnection(); + + + //Create Session + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + //Create Queue + String queueName = getTestQueueName(); + ((AMQSession) _session).createQueue(new AMQShortString(queueName), true, false, false); + Queue queue = _session.createQueue("direct://amq.direct/"+queueName+"/"+queueName+"?durable='false'&autodelete='true'"); + + //Create Consumer + _consumer = _session.createConsumer(queue); + + //Create Producer + _producer = _session.createProducer(queue); + + _connection.start(); + } + + public void tearDown() throws Exception + { + //clean up + _connection.close(); + + super.tearDown(); + } + + public void testGetAndSend() throws JMSException + { + //Create Sample Message using UUIDs + UUID test = UUID.randomUUID(); + + ObjectMessage testMessage = _session.createObjectMessage(test); + + Object o = testMessage.getObject(); + + assertNotNull("Object was null", o); + + sendAndTest(testMessage, test); + } + + public void testSend() throws JMSException + { + //Create Sample Message using UUIDs + UUID test = UUID.randomUUID(); + + ObjectMessage testMessage = _session.createObjectMessage(test); + + sendAndTest(testMessage, test); + } + + public void testTostringAndSend() throws JMSException + { + //Create Sample Message using UUIDs + UUID test = UUID.randomUUID(); + + ObjectMessage testMessage = _session.createObjectMessage(test); + + assertNotNull("Object was null", testMessage.toString()); + + sendAndTest(testMessage, test); + } + + public void testSendNull() throws JMSException + { + + ObjectMessage testMessage = _session.createObjectMessage(null); + + assertNotNull("Object was null", testMessage.toString()); + + sendAndTest(testMessage, null); + } + + //***************** Helpers + + private void sendAndTest(ObjectMessage message, Object sent) throws JMSException + { + _producer.send(message); + + ObjectMessage receivedMessage = (ObjectMessage) _consumer.receive(1000); + + assertNotNull("Message was not received.", receivedMessage); + + UUID result = (UUID) receivedMessage.getObject(); + + assertEquals("First read: UUIDs were not equal", sent, result); + + result = (UUID) receivedMessage.getObject(); + + assertEquals("Second read: UUIDs were not equal", sent, result); + } + + + public void testSendEmptyObjectMessage() throws JMSException + { + ObjectMessage testMessage = _session.createObjectMessage(); + testMessage.setStringProperty("test-property", "test-value"); + assertNotNull("Object was null", testMessage.toString()); + + _producer.send(testMessage); + + ObjectMessage receivedMessage = (ObjectMessage) _consumer.receive(1000); + + assertNotNull("Message was not received.", receivedMessage); + assertNull("No object was sent", receivedMessage.getObject()); + assertEquals("Unexpected property received", "test-value", receivedMessage.getStringProperty("test-property")); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/SelectorTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/SelectorTest.java new file mode 100644 index 0000000000..d945301bbe --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/message/SelectorTest.java @@ -0,0 +1,314 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.client.message; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.BasicMessageProducer; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.InvalidSelectorException; +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.TextMessage; +import java.util.concurrent.CountDownLatch; + +public class SelectorTest extends QpidBrokerTestCase implements MessageListener +{ + private static final Logger _logger = LoggerFactory.getLogger(SelectorTest.class); + + private AMQConnection _connection; + private AMQDestination _destination; + private int count; + private static final String INVALID_SELECTOR = "Cost LIKE 5"; + CountDownLatch _responseLatch = new CountDownLatch(1); + + private static final String BAD_MATHS_SELECTOR = " 1 % 5"; + + private static final long RECIEVE_TIMEOUT = 1000; + + protected void setUp() throws Exception + { + super.setUp(); + init((AMQConnection) getConnection("guest", "guest")); + } + + private void init(AMQConnection connection) throws JMSException + { + init(connection, new AMQQueue(connection, getTestQueueName(), true)); + } + + private void init(AMQConnection connection, AMQDestination destination) throws JMSException + { + _connection = connection; + _destination = destination; + connection.start(); + } + + public void onMessage(Message message) + { + count++; + _logger.info("Got Message:" + message); + _responseLatch.countDown(); + } + + public void testUsingOnMessage() throws Exception + { + String selector = "Cost = 2 AND \"property-with-hyphen\" = 'wibble'"; + // selector = "JMSType = Special AND Cost = 2 AND AMQMessageID > 0 AND JMSDeliveryMode=" + DeliveryMode.NON_PERSISTENT; + + Session session = (AMQSession) _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); + // _session.createConsumer(destination).setMessageListener(this); + session.createConsumer(_destination, selector).setMessageListener(this); + + try + { + Message msg = session.createTextMessage("Message"); + msg.setJMSPriority(1); + msg.setIntProperty("Cost", 2); + msg.setStringProperty("property-with-hyphen", "wibble"); + msg.setJMSType("Special"); + + _logger.info("Sending Message:" + msg); + + ((BasicMessageProducer) session.createProducer(_destination)).send(msg, DeliveryMode.NON_PERSISTENT); + _logger.info("Message sent, waiting for response..."); + + _responseLatch.await(); + + if (count > 0) + { + _logger.info("Got message"); + } + + if (count == 0) + { + fail("Did not get message!"); + // throw new RuntimeException("Did not get message!"); + } + } + catch (JMSException e) + { + _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage()); + if (!(e instanceof InvalidSelectorException)) + { + fail("Wrong exception:" + e.getMessage()); + } + else + { + _logger.debug("SUCCESS!!"); + } + } + catch (InterruptedException e) + { + _logger.debug("IE :" + e.getClass().getSimpleName() + ":" + e.getMessage()); + } + + } + + public void testUnparsableSelectors() throws Exception + { + AMQSession session = (AMQSession) _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); + boolean caught = false; + + //Try Creating a Browser + try + { + session.createBrowser(session.createQueue("Ping"), INVALID_SELECTOR); + } + catch (JMSException e) + { + _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage()); + if (!(e instanceof InvalidSelectorException)) + { + fail("Wrong exception:" + e.getMessage()); + } + caught = true; + } + assertTrue("No exception thrown!", caught); + caught = false; + + //Try Creating a Consumer + try + { + session.createConsumer(session.createQueue("Ping"), INVALID_SELECTOR); + } + catch (JMSException e) + { + _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage()); + if (!(e instanceof InvalidSelectorException)) + { + fail("Wrong exception:" + e.getMessage()); + } + caught = true; + } + assertTrue("No exception thrown!", caught); + caught = false; + + //Try Creating a Receiever + try + { + session.createReceiver(session.createQueue("Ping"), INVALID_SELECTOR); + } + catch (JMSException e) + { + _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage()); + if (!(e instanceof InvalidSelectorException)) + { + fail("Wrong exception:" + e.getMessage()); + } + caught = true; + } + assertTrue("No exception thrown!", caught); + caught = false; + + try + { + session.createReceiver(session.createQueue("Ping"), BAD_MATHS_SELECTOR); + } + catch (JMSException e) + { + _logger.debug("JMS:" + e.getClass().getSimpleName() + ":" + e.getMessage()); + if (!(e instanceof InvalidSelectorException)) + { + fail("Wrong exception:" + e.getMessage()); + } + caught = true; + } + assertTrue("No exception thrown!", caught); + caught = false; + + } + + public void testRuntimeSelectorError() throws JMSException + { + Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(_destination , "testproperty % 5 = 1"); + MessageProducer producer = session.createProducer(_destination); + Message sentMsg = session.createTextMessage(); + + sentMsg.setIntProperty("testproperty", 1); // 1 % 5 + producer.send(sentMsg); + Message recvd = consumer.receive(RECIEVE_TIMEOUT); + assertNotNull(recvd); + + sentMsg.setStringProperty("testproperty", "hello"); // "hello" % 5 makes no sense + producer.send(sentMsg); + try + { + recvd = consumer.receive(RECIEVE_TIMEOUT); + assertNull(recvd); + } + catch (Exception e) + { + + } + assertFalse("Connection should not be closed", _connection.isClosed()); + } + + public void testSelectorWithJMSMessageID() throws Exception + { + Session session = _connection.createSession(true, Session.SESSION_TRANSACTED); + + MessageProducer prod = session.createProducer(_destination); + MessageConsumer consumer = session.createConsumer(_destination,"JMSMessageID IS NOT NULL"); + + for (int i=0; i<2; i++) + { + Message msg = session.createTextMessage("Msg" + String.valueOf(i)); + prod.send(msg); + } + session.commit(); + + Message msg1 = consumer.receive(1000); + Message msg2 = consumer.receive(1000); + + Assert.assertNotNull("Msg1 should not be null", msg1); + Assert.assertNotNull("Msg2 should not be null", msg2); + + session.commit(); + + prod.setDisableMessageID(true); + + for (int i=2; i<4; i++) + { + Message msg = session.createTextMessage("Msg" + String.valueOf(i)); + prod.send(msg); + } + + session.commit(); + Message msg3 = consumer.receive(1000); + Assert.assertNull("Msg3 should be null", msg3); + session.commit(); + consumer = session.createConsumer(_destination,"JMSMessageID IS NULL"); + + Message msg4 = consumer.receive(1000); + Message msg5 = consumer.receive(1000); + session.commit(); + Assert.assertNotNull("Msg4 should not be null", msg4); + Assert.assertNotNull("Msg5 should not be null", msg5); + } + + public void testSelectorWithJMSDeliveryMode() throws Exception + { + Session session = _connection.createSession(false, Session.SESSION_TRANSACTED); + + Destination dest1 = session.createTopic("test1"); + Destination dest2 = session.createTopic("test2"); + + MessageProducer prod1 = session.createProducer(dest1); + MessageProducer prod2 = session.createProducer(dest2); + MessageConsumer consumer1 = session.createConsumer(dest1,"JMSDeliveryMode = 'PERSISTENT'"); + MessageConsumer consumer2 = session.createConsumer(dest2,"JMSDeliveryMode = 'NON_PERSISTENT'"); + + Message msg1 = session.createTextMessage("Persistent"); + prod1.send(msg1); + prod2.send(msg1); + + prod1.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + prod2.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + + Message msg2 = session.createTextMessage("Non_Persistent"); + prod1.send(msg2); + prod2.send(msg2); + + TextMessage m1 = (TextMessage)consumer1.receive(1000); + assertEquals("Consumer1 should receive the persistent message","Persistent",m1.getText()); + assertNull("Consumer1 should not receiver another message",consumer1.receive(1000)); + + TextMessage m2 = (TextMessage)consumer2.receive(1000); + assertEquals("Consumer2 should receive the non persistent message","Non_Persistent",m2.getText()); + assertNull("Consumer2 should not receiver another message",consumer2.receive(1000)); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/queue/LVQTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/queue/LVQTest.java new file mode 100644 index 0000000000..51566403b3 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/queue/LVQTest.java @@ -0,0 +1,84 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.client.queue; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +public class LVQTest extends QpidBrokerTestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(LVQTest.class); + private Connection _connection; + + @Override + public void setUp() throws Exception + { + super.setUp(); + _connection = getConnection() ; + _connection.start(); + } + + @Override + public void tearDown() throws Exception + { + _connection.close(); + super.tearDown(); + } + + public void testLVQQueue() throws Exception + { + String addr = "ADDR:my-lvq-queue; {create: always, " + + "node: {x-bindings: [{exchange : 'amq.direct', key : test}], " + + "x-declare:{arguments : {'qpid.last_value_queue':1}}}}"; + + Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + + Destination dest = ssn.createQueue(addr); + MessageConsumer consumer = ssn.createConsumer(dest); + MessageProducer prod = ssn.createProducer(ssn.createQueue("ADDR:amq.direct/test")); + + for (int i=0; i<40; i++) + { + Message msg = ssn.createTextMessage(String.valueOf(i)); + msg.setStringProperty("qpid.LVQ_key", String.valueOf(i%10)); + prod.send(msg); + } + + for (int i=0; i<10; i++) + { + TextMessage msg = (TextMessage)consumer.receive(500); + assertEquals("The last value is not reflected","3" + i,msg.getText()); + } + + assertNull("There should not be anymore messages",consumer.receive(500)); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/client/queue/QueuePolicyTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/queue/QueuePolicyTest.java new file mode 100644 index 0000000000..b785326ef2 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/client/queue/QueuePolicyTest.java @@ -0,0 +1,120 @@ +/* +* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +* +*/ +package org.apache.qpid.test.client.queue; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +public class QueuePolicyTest extends QpidBrokerTestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(QueuePolicyTest.class); + private Connection _connection; + + @Override + public void setUp() throws Exception + { + super.setUp(); + _connection = getConnection() ; + _connection.start(); + } + + @Override + public void tearDown() throws Exception + { + _connection.close(); + super.tearDown(); + } + + /** + * Test Goal : To create a ring queue programitcally with max queue count using the + * address string and observe that it works as expected. + */ + public void testRejectPolicy() throws Exception + { + String addr = "ADDR:queue; {create: always, " + + "node: {x-bindings: [{exchange : 'amq.direct', key : test}], " + + "x-declare:{ arguments : {'qpid.max_count':5} }}}"; + + Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + + Destination dest = ssn.createQueue(addr); + MessageConsumer consumer = ssn.createConsumer(dest); + MessageProducer prod = ssn.createProducer(ssn.createQueue("ADDR:amq.direct/test")); + + for (int i=0; i<6; i++) + { + prod.send(ssn.createMessage()); + } + + try + { + prod.send(ssn.createMessage()); + ((AMQSession)ssn).sync(); + fail("The client did not receive an exception after exceeding the queue limit"); + } + catch (AMQException e) + { + assertTrue("The correct error code is not set",e.getErrorCode().toString().contains("506")); + } + } + + /** + * Test Goal : To create a ring queue programitcally using the address string and observe + * that it works as expected. + */ + public void testRingPolicy() throws Exception + { + Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE); + + String addr = "ADDR:my-ring-queue; {create: always, " + + "node: {x-bindings: [{exchange : 'amq.direct', key : test}], " + + "x-declare:{arguments : {'qpid.policy_type':ring, 'qpid.max_count':2} }}}"; + + Destination dest = ssn.createQueue(addr); + MessageConsumer consumer = ssn.createConsumer(dest); + MessageProducer prod = ssn.createProducer(ssn.createQueue("ADDR:amq.direct/test")); + + _connection.stop(); + + prod.send(ssn.createTextMessage("Test1")); + prod.send(ssn.createTextMessage("Test2")); + prod.send(ssn.createTextMessage("Test3")); + + _connection.start(); + + TextMessage msg = (TextMessage)consumer.receive(1000); + assertEquals("The consumer should receive the msg with body='Test2'","Test2",msg.getText()); + + msg = (TextMessage)consumer.receive(1000); + assertEquals("The consumer should receive the msg with body='Test3'","Test3",msg.getText()); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/Acknowledge2ConsumersTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/Acknowledge2ConsumersTest.java new file mode 100644 index 0000000000..23efb656d2 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/Acknowledge2ConsumersTest.java @@ -0,0 +1,193 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.test.unit.ack; + +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Queue; +import javax.jms.Session; + +public class Acknowledge2ConsumersTest extends QpidBrokerTestCase +{ + protected static int NUM_MESSAGES = 100; + protected Connection _con; + protected Queue _queue; + private Session _producerSession; + private Session _consumerSession; + private MessageConsumer _consumerA; + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + _queue = (Queue) getInitialContext().lookup("queue"); + + //Create Producer put some messages on the queue + _con = getConnection(); + } + + private void init(boolean transacted, int mode) throws JMSException + { + _producerSession = _con.createSession(true, Session.SESSION_TRANSACTED); + _consumerSession = _con.createSession(transacted, mode); + _consumerA = _consumerSession.createConsumer(_queue); + _con.start(); + } + + /** + * Produces Messages that + * + * @param transacted + * @param mode + * + * @throws Exception + */ + private void test2ConsumersAcking(boolean transacted, int mode) throws Exception + { + init(transacted, mode); + + // These should all end up being prefetched by sessionA + sendMessage(_producerSession, _queue, NUM_MESSAGES / 2); + + //Create a second consumer (consumerB) to consume some of the messages + MessageConsumer consumerB = _consumerSession.createConsumer(_queue); + + // These messages should be roundrobined between A and B + sendMessage(_producerSession, _queue, NUM_MESSAGES / 2); + + int count = 0; + //Use consumerB to receive messages it has + Message msg = consumerB.receive(1500); + while (msg != null) + { + if (mode == Session.CLIENT_ACKNOWLEDGE) + { + msg.acknowledge(); + } + count++; + msg = consumerB.receive(1500); + } + if (transacted) + { + _consumerSession.commit(); + } + + // Close the consumers + _consumerA.close(); + consumerB.close(); + + // and close the session to release any prefetched messages. + _consumerSession.close(); + assertEquals("Wrong number of messages on queue", NUM_MESSAGES - count, + ((AMQSession) _producerSession).getQueueDepth((AMQDestination) _queue)); + + // Clean up messages that may be left on the queue + _consumerSession = _con.createSession(transacted, mode); + _consumerA = _consumerSession.createConsumer(_queue); + msg = _consumerA.receive(1500); + while (msg != null) + { + if (mode == Session.CLIENT_ACKNOWLEDGE) + { + msg.acknowledge(); + } + msg = _consumerA.receive(1500); + } + _consumerA.close(); + if (transacted) + { + _consumerSession.commit(); + } + _consumerSession.close(); + } + + public void test2ConsumersAutoAck() throws Exception + { + test2ConsumersAcking(false, Session.AUTO_ACKNOWLEDGE); + } + + public void test2ConsumersClientAck() throws Exception + { + test2ConsumersAcking(false, Session.CLIENT_ACKNOWLEDGE); + } + + public void test2ConsumersTx() throws Exception + { + test2ConsumersAcking(true, Session.SESSION_TRANSACTED); + } + + + +// +// /** +// * Check that session level acknowledge does correctly ack all previous +// * values. Send 3 messages(0,1,2) then ack 1 and 2. If session ack is +// * working correctly then acking 1 will also ack 0. Acking 2 will not +// * attempt to re-ack 0 and 1. +// * +// * @throws Exception +// */ +// public void testSessionAck() throws Exception +// { +// init(false, Session.CLIENT_ACKNOWLEDGE); +// +// sendMessage(_producerSession, _queue, 3); +// Message msg; +// +// // Drop msg 0 +// _consumerA.receive(RECEIVE_TIMEOUT); +// +// // Take msg 1 +// msg = _consumerA.receive(RECEIVE_TIMEOUT); +// +// assertNotNull("Message 1 not correctly received.", msg); +// assertEquals("Incorrect message received", 1, msg.getIntProperty(INDEX)); +// +// // This should also ack msg 0 +// msg.acknowledge(); +// +// // Take msg 2 +// msg = _consumerA.receive(RECEIVE_TIMEOUT); +// +// assertNotNull("Message 2 not correctly received.", msg); +// assertEquals("Incorrect message received", 2, msg.getIntProperty(INDEX)); +// +// // This should just ack msg 2 +// msg.acknowledge(); +// +// _consumerA.close(); +// _consumerSession.close(); +// +// assertEquals("Queue not empty.", 0, +// ((AMQSession) _producerSession).getQueueDepth((AMQDestination) _queue)); +// _con.close(); +// +// +// } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/AcknowledgeOnMessageTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/AcknowledgeOnMessageTest.java new file mode 100644 index 0000000000..602eb5137a --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/AcknowledgeOnMessageTest.java @@ -0,0 +1,226 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.ack; + +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.JMSAMQException; +import org.apache.qpid.client.failover.FailoverException; + +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.Session; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +/** + * This test extends the synchronous AcknowledgeTest to use a MessageListener + * and receive messages asynchronously. + */ +public class AcknowledgeOnMessageTest extends AcknowledgeTest implements MessageListener +{ + protected CountDownLatch _receivedAll; + protected AtomicReference _causeOfFailure = new AtomicReference(null); + + @Override + public void setUp() throws Exception + { + super.setUp(); + } + + /** + * Override the synchronous AcknowledgeTest init to provide the _receivedAll + * CountDownLatch init and ensure that we set the MessageListener. + * @param transacted + * @param mode + * @throws Exception + */ + @Override + public void init(boolean transacted, int mode) throws Exception + { + _receivedAll = new CountDownLatch(NUM_MESSAGES); + + super.init(transacted, mode); + _consumer.setMessageListener(this); + } + + /** + * This test overrides the testAcking from the simple recieve() model to all + * for asynchronous receiving of messages. + * + * Again the transaction/ack mode is provided to this main test run + * + * The init method is called which will setup the listener so that we can + * then sit and await using the _receivedAll CountDownLatch. We wait for up + * to 10s if no messages have been received in the last 10s then test will + * fail. + * + * If the test fails then it will attempt to retrieve any exception that the + * asynchronous delivery thread may have recorded. + * + * @param transacted + * @param mode + * + * @throws Exception + */ + @Override + protected void testAcking(boolean transacted, int mode) throws Exception + { + init(transacted, mode); + + _connection.start(); + + // Set the lastCount to NUM_MESSAGES, this ensures that the compare + // against the receviedAll count is accurate. + int lastCount = NUM_MESSAGES; + + // Wait for messages to arrive + boolean complete = _receivedAll.await(10000L, TimeUnit.MILLISECONDS); + + // If the messasges haven't arrived + while (!complete) + { + // Check how many we have received + int currentCount = (int) _receivedAll.getCount(); + + // make sure we have received a message in the last cycle. + if (lastCount == currentCount) + { + // If we didn't receive any messages then stop. + // Something must have gone wrong. + System.err.println("Giving up waiting as we didn't receive anything."); + break; + } + // Remember the currentCount as the lastCount for the next cycle. + // so we can exit if things get locked up. + lastCount = currentCount; + + // Wait again for messages to arrive. + complete = _receivedAll.await(10000L, TimeUnit.MILLISECONDS); + } + + // If we failed to receive all the messages then fail the test. + if (!complete) + { + // Check to see if we ended due to an exception in the onMessage handler + Exception cause = _causeOfFailure.get(); + if (cause != null) + { + _logger.error("Cause of failure is: ", cause); + fail(cause.getMessage()); + } + else + { + _logger.info("AOMT: Check QueueDepth:" + _queue); + long onQueue=((AMQSession) getConnection().createSession(false, Session.AUTO_ACKNOWLEDGE)).getQueueDepth((AMQDestination) _queue); + fail("All messages not received missing:" + _receivedAll.getCount() + "/" + NUM_MESSAGES+" On Queue:"+onQueue); + + } + } + + // Even if we received all the messages. + // Check to see if we ended due to an exception in the onMessage handler + Exception cause = _causeOfFailure.get(); + if (cause != null) + { + _logger.error("Failed due to following exception", cause); + fail(cause.getMessage()); + } + + try + { + _consumer.close(); + } + catch (JMSAMQException amqe) + { + if (amqe.getLinkedException() instanceof FailoverException) + { + fail("QPID-143 : Auto Ack can acknowledge message from previous session after failver. If failover occurs between deliver and ack."); + } + // else Rethrow for TestCase to catch. + throw amqe; + } + + _consumerSession.close(); + + _logger.info("AOMT: check number of message at end of test."); + assertEquals("Wrong number of messages on queue", 0, + ((AMQSession) getConnection().createSession(false, Session.AUTO_ACKNOWLEDGE)).getQueueDepth((AMQDestination) _queue)); + } + + /** + * The MessageListener interface that recieves the message and counts down + * the _receivedAll CountDownLatch. + * + * Again like AcknowledgeTest acknowledgement is actually handled in + * doAcknowlegement. + * + * The message INDEX is validated to ensure the correct message order is + * preserved. + * + * @param message + */ + public void onMessage(Message message) + { + // Log received Message for debugging + _logger.info("RECEIVED MESSAGE:" + message); + + try + { + int count = NUM_MESSAGES - (int) _receivedAll.getCount(); + + assertEquals("Incorrect message received", count, message.getIntProperty(INDEX)); + + count++; + if (count < NUM_MESSAGES) + { + //Send the next message + _producer.send(createNextMessage(_consumerSession, count)); + } + + doAcknowlegement(message); + + _receivedAll.countDown(); + } + catch (Exception e) + { + // This will end the test run by counting down _receivedAll + fail(e); + } + } + + /** + * Pass the given exception back to the waiting thread to fail the test run. + * + * @param e The exception that is causing the test to fail. + */ + protected void fail(Exception e) + { + //record the failure + _causeOfFailure.set(e); + // End the test. + while (_receivedAll.getCount() != 0) + { + _receivedAll.countDown(); + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java new file mode 100644 index 0000000000..841d0ea4ba --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java @@ -0,0 +1,188 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.test.unit.ack; + +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +/** + * Test the various JMS Acknowledge Modes the single testAcking method does all + * the work of receiving and validation of acking. + * + * The ack mode is provided from the various test methods. + */ +public class AcknowledgeTest extends QpidBrokerTestCase +{ + protected int NUM_MESSAGES; + protected Connection _connection; + protected Queue _queue; + protected Session _consumerSession; + protected MessageConsumer _consumer; + protected MessageProducer _producer; + + @Override + protected void setUp() throws Exception + { + super.setUp(); + NUM_MESSAGES = 5; + + _queue = getTestQueue(); + + //Create Producer put some messages on the queue + _connection = getConnection(); + } + + protected void init(boolean transacted, int mode) throws Exception + { + _consumerSession = _connection.createSession(transacted, mode); + _consumer = _consumerSession.createConsumer(_queue); + _producer = _consumerSession.createProducer(_queue); + + // These should all end up being prefetched by session + sendMessage(_consumerSession, _queue, 1); + + syncIfNotTransacted(transacted); + + assertEquals("Wrong number of messages on queue", 1, + ((AMQSession) _consumerSession).getQueueDepth((AMQDestination) _queue)); + } + + /** + * The main test method. + * + * Receive the initial message and then proceed to send and ack messages + * until we have processed NUM_MESSAGES worth of messages. + * + * Each message is tagged with an INDEX value and these are used to check + * that the messages are received in the correct order. + * + * The test concludes by validating that the queue depth is 0 as expected. + * + * @param transacted + * @param mode + * + * @throws Exception + */ + protected void testAcking(boolean transacted, int mode) throws Exception + { + init(transacted, mode); + + _connection.start(); + + Message msg = _consumer.receive(1500); + + int count = 0; + while (count < NUM_MESSAGES) + { + assertNotNull("Message " + count + " not correctly received.", msg); + assertEquals("Incorrect message received", count, msg.getIntProperty(INDEX)); + count++; + + if (count < NUM_MESSAGES) + { + //Send the next message + _producer.send(createNextMessage(_consumerSession, count)); + syncIfNotTransacted(transacted); + } + + doAcknowlegement(msg); + + msg = _consumer.receive(1500); + } + + if (_consumerSession.getTransacted()) + { + //Acknowledge the last msg if we are testing transacted otherwise queueDepth will be 1 + doAcknowlegement(msg); + } + + assertEquals("Wrong number of messages on queue", 0, + ((AMQSession) _consumerSession).getQueueDepth((AMQDestination) _queue)); + } + + /** + * Perform the acknowledgement of messages if additionally required. + * + * @param msg + * + * @throws JMSException + */ + protected void doAcknowlegement(Message msg) throws JMSException + { + if (_consumerSession.getTransacted()) + { + _consumerSession.commit(); + } + + if (_consumerSession.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE) + { + msg.acknowledge(); + } + } + + public void testClientAck() throws Exception + { + testAcking(false, Session.CLIENT_ACKNOWLEDGE); + } + + public void testAutoAck() throws Exception + { + testAcking(false, Session.AUTO_ACKNOWLEDGE); + } + + public void testTransacted() throws Exception + { + testAcking(true, Session.SESSION_TRANSACTED); + } + + public void testDupsOk() throws Exception + { + testAcking(false, Session.DUPS_OK_ACKNOWLEDGE); + } + + public void testNoAck() throws Exception + { + testAcking(false, AMQSession.NO_ACKNOWLEDGE); + } + + public void testPreAck() throws Exception + { + testAcking(false, AMQSession.PRE_ACKNOWLEDGE); + } + + private void syncIfNotTransacted(boolean transacted) throws Exception + { + if(!transacted) + { + ((AMQSession)_consumerSession).sync(); + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/ClientAcknowledgeTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/ClientAcknowledgeTest.java new file mode 100644 index 0000000000..291e1697ca --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/ClientAcknowledgeTest.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.test.unit.ack; + +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +public class ClientAcknowledgeTest extends QpidBrokerTestCase +{ + private static final long ONE_DAY_MS = 1000l * 60 * 60 * 24; + private Connection _connection; + private Queue _queue; + private Session _consumerSession; + private MessageConsumer _consumer; + private MessageProducer _producer; + + @Override + protected void setUp() throws Exception + { + super.setUp(); + _queue = getTestQueue(); + _connection = getConnection(); + } + + /** + * Test that message.acknowledge actually acknowledges, regardless of + * the flusher thread period, by restarting the broker after calling + * acknowledge, and then verifying after restart that the message acked + * is no longer present. This test requires a persistent store. + */ + public void testClientAckWithLargeFlusherPeriod() throws Exception + { + setTestClientSystemProperty("qpid.session.max_ack_delay", Long.toString(ONE_DAY_MS)); + _consumerSession = _connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + _consumer = _consumerSession.createConsumer(_queue); + _connection.start(); + + _producer = _consumerSession.createProducer(_queue); + _producer.send(createNextMessage(_consumerSession, 1)); + _producer.send(createNextMessage(_consumerSession, 2)); + + Message message = _consumer.receive(1000l); + assertNotNull("Message has not been received", message); + assertEquals("Unexpected message is received", 1, message.getIntProperty(INDEX)); + message.acknowledge(); + + //restart broker to allow verification of the acks + //without explicitly closing connection (which acks) + restartBroker(); + + // try to receive the message again, which should fail (as it was ackd) + _connection = getConnection(); + _connection.start(); + _consumerSession = _connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + _consumer = _consumerSession.createConsumer(_queue); + message = _consumer.receive(1000l); + assertNotNull("Message has not been received", message); + assertEquals("Unexpected message is received", 2, message.getIntProperty(INDEX)); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/RecoverTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/RecoverTest.java new file mode 100644 index 0000000000..23ea4ac258 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ack/RecoverTest.java @@ -0,0 +1,483 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.ack; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.jms.Session; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +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.TextMessage; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +public class RecoverTest extends QpidBrokerTestCase +{ + static final Logger _logger = LoggerFactory.getLogger(RecoverTest.class); + + private static final int POSIITIVE_TIMEOUT = 2000; + + private volatile Exception _error; + private AtomicInteger count; + + protected AMQConnection _connection; + protected Session _consumerSession; + protected MessageConsumer _consumer; + static final int SENT_COUNT = 4; + + @Override + protected void setUp() throws Exception + { + super.setUp(); + _error = null; + count = new AtomicInteger(); + } + + protected void initTest() throws Exception + { + _connection = (AMQConnection) getConnection(); + + _consumerSession = _connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Queue queue = _consumerSession.createQueue(getTestQueueName()); + + _consumer = _consumerSession.createConsumer(queue); + + _logger.info("Sending four messages"); + sendMessage(_connection.createSession(false, Session.AUTO_ACKNOWLEDGE), queue, SENT_COUNT); + _logger.info("Starting connection"); + _connection.start(); + } + + protected Message validateNextMessages(int nextCount, int startIndex) throws JMSException + { + Message message = null; + for (int index = 0; index < nextCount; index++) + { + message = _consumer.receive(3000); + assertEquals(startIndex + index, message.getIntProperty(INDEX)); + } + return message; + } + + protected void validateRemainingMessages(int remaining) throws JMSException + { + int index = SENT_COUNT - remaining; + + Message message = null; + while (index != SENT_COUNT) + { + message = _consumer.receive(3000); + assertNotNull(message); + assertEquals(index++, message.getIntProperty(INDEX)); + } + + if (message != null) + { + _logger.info("Received redelivery of three messages. Acknowledging last message"); + message.acknowledge(); + } + + _logger.info("Calling acknowledge with no outstanding messages"); + // all acked so no messages to be delivered + _consumerSession.recover(); + + message = _consumer.receiveNoWait(); + assertNull(message); + _logger.info("No messages redelivered as is expected"); + } + + public void testRecoverResendsMsgs() throws Exception + { + initTest(); + + Message message = validateNextMessages(1, 0); + message.acknowledge(); + _logger.info("Received and acknowledged first message"); + + _consumer.receive(); + _consumer.receive(); + _consumer.receive(); + _logger.info("Received all four messages. Calling recover with three outstanding messages"); + // no ack for last three messages so when I call recover I expect to get three messages back + + _consumerSession.recover(); + + validateRemainingMessages(3); + } + + public void testRecoverResendsMsgsAckOnEarlier() throws Exception + { + initTest(); + + Message message = validateNextMessages(2, 0); + message.acknowledge(); + _logger.info("Received 2 messages, acknowledge() first message, should acknowledge both"); + + _consumer.receive(); + _consumer.receive(); + _logger.info("Received all four messages. Calling recover with two outstanding messages"); + // no ack for last three messages so when I call recover I expect to get three messages back + _consumerSession.recover(); + + Message message2 = _consumer.receive(3000); + assertNotNull(message2); + assertEquals(2, message2.getIntProperty(INDEX)); + + Message message3 = _consumer.receive(3000); + assertNotNull(message3); + assertEquals(3, message3.getIntProperty(INDEX)); + + _logger.info("Received redelivery of two messages. calling acknolwedgeThis() first of those message"); + ((org.apache.qpid.jms.Message) message2).acknowledgeThis(); + + _logger.info("Calling recover"); + // all acked so no messages to be delivered + _consumerSession.recover(); + + message3 = _consumer.receive(3000); + assertNotNull(message3); + assertEquals(3, message3.getIntProperty(INDEX)); + ((org.apache.qpid.jms.Message) message3).acknowledgeThis(); + + // all acked so no messages to be delivered + validateRemainingMessages(0); + } + + public void testAcknowledgePerConsumer() throws Exception + { + AMQConnection con = (AMQConnection) getConnection(); + + Session consumerSession = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Queue queue = + new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q1"), new AMQShortString("Q1"), + false, true); + Queue queue2 = + new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q2"), new AMQShortString("Q2"), + false, true); + MessageConsumer consumer = consumerSession.createConsumer(queue); + MessageConsumer consumer2 = consumerSession.createConsumer(queue2); + + AMQConnection con2 = (AMQConnection) getConnection(); + Session producerSession = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageProducer producer = producerSession.createProducer(queue); + MessageProducer producer2 = producerSession.createProducer(queue2); + + producer.send(producerSession.createTextMessage("msg1")); + producer2.send(producerSession.createTextMessage("msg2")); + + con2.close(); + + _logger.info("Starting connection"); + con.start(); + + TextMessage tm2 = (TextMessage) consumer2.receive(2000); + assertNotNull(tm2); + assertEquals("msg2", tm2.getText()); + + tm2.acknowledge(); + consumerSession.recover(); + + TextMessage tm1 = (TextMessage) consumer.receive(2000); + assertNotNull(tm1); + assertEquals("msg1", tm1.getText()); + + con.close(); + + } + + public void testRecoverInAutoAckListener() throws Exception + { + AMQConnection con = (AMQConnection) getConnection(); + + final Session consumerSession = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = + new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q3"), new AMQShortString("Q3"), + false, true); + MessageConsumer consumer = consumerSession.createConsumer(queue); + MessageProducer producer = consumerSession.createProducer(queue); + producer.send(consumerSession.createTextMessage("hello")); + + final Object lock = new Object(); + + consumer.setMessageListener(new MessageListener() + { + + public void onMessage(Message message) + { + try + { + count.incrementAndGet(); + if (count.get() == 1) + { + if (message.getJMSRedelivered()) + { + setError(new Exception("Message marked as redelivered on what should be first delivery attempt")); + } + + consumerSession.recover(); + } + else if (count.get() == 2) + { + if (!message.getJMSRedelivered()) + { + setError(new Exception("Message not marked as redelivered on what should be second delivery attempt")); + } + } + else + { + _logger.error(message.toString()); + setError(new Exception("Message delivered too many times!: " + count)); + } + } + catch (JMSException e) + { + _logger.error("Error recovering session: " + e, e); + setError(e); + } + + synchronized (lock) + { + lock.notify(); + } + } + }); + + con.start(); + + long waitTime = 30000L; + long waitUntilTime = System.currentTimeMillis() + waitTime; + + synchronized (lock) + { + while ((count.get() <= 1) && (waitTime > 0)) + { + lock.wait(waitTime); + if (count.get() <= 1) + { + waitTime = waitUntilTime - System.currentTimeMillis(); + } + } + } + + Thread.sleep(1000); + + if (_error != null) + { + throw _error; + } + + assertEquals("Message not received the correct number of times.", + 2, count.get()); + } + + private void setError(Exception e) + { + _error = e; + } + + /** + * Goal : Check if ordering is preserved when doing recovery under reasonable circumstances. + * Refer QPID-2471 for more details. + * Test strategy : + * Send 8 messages to a topic. + * The consumer will call recover until it sees a message 5 times, + * at which point it will ack that message. + * It will continue the above until it acks all the messages. + * While doing so it will verify that the messages are not + * delivered out of order. + */ + public void testOrderingWithSyncConsumer() throws Exception + { + Connection con = (Connection) getConnection(); + javax.jms.Session session = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Destination topic = session.createTopic("myTopic"); + MessageConsumer cons = session.createConsumer(topic); + + sendMessage(session,topic,8); + con.start(); + + int messageSeen = 0; + int expectedIndex = 0; + long startTime = System.currentTimeMillis(); + + while(expectedIndex < 8) + { + // Based on historical data, on average the test takes about 6 secs to complete. + if (System.currentTimeMillis() - startTime > 8000) + { + fail("Test did not complete on time. Received " + + expectedIndex + " msgs so far. Please check the logs"); + } + + Message message = cons.receive(POSIITIVE_TIMEOUT); + int actualIndex = message.getIntProperty(INDEX); + + assertEquals("Received Message Out Of Order",expectedIndex, actualIndex); + + //don't ack the message until we receive it 5 times + if( messageSeen < 5 ) + { + _logger.debug("Ignoring message " + actualIndex + " and calling recover"); + session.recover(); + messageSeen++; + } + else + { + messageSeen = 0; + expectedIndex++; + message.acknowledge(); + _logger.debug("Acknowledging message " + actualIndex); + } + } + } + + /** + * Goal : Same as testOderingWithSyncConsumer + * Test strategy : + * Same as testOderingWithSyncConsumer but using a + * Message Listener instead of a sync receive(). + */ + public void testOrderingWithAsyncConsumer() throws Exception + { + Connection con = (Connection) getConnection(); + final javax.jms.Session session = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Destination topic = session.createTopic("myTopic"); + MessageConsumer cons = session.createConsumer(topic); + + sendMessage(session,topic,8); + con.start(); + + final Object lock = new Object(); + final AtomicBoolean pass = new AtomicBoolean(false); //used as work around for 'final' + + cons.setMessageListener(new MessageListener() + { + private int messageSeen = 0; + private int expectedIndex = 0; + + public void onMessage(Message message) + { + try + { + int actualIndex = message.getIntProperty(INDEX); + assertEquals("Received Message Out Of Order", expectedIndex, actualIndex); + + //don't ack the message until we receive it 5 times + if( messageSeen < 5 ) + { + _logger.debug("Ignoring message " + actualIndex + " and calling recover"); + session.recover(); + messageSeen++; + } + else + { + messageSeen = 0; + expectedIndex++; + message.acknowledge(); + _logger.debug("Acknowledging message " + actualIndex); + if (expectedIndex == 8) + { + pass.set(true); + synchronized (lock) + { + lock.notifyAll(); + } + } + } + } + catch (JMSException e) + { + _error = e; + synchronized (lock) + { + lock.notifyAll(); + } + } + } + }); + + synchronized(lock) + { + // Based on historical data, on average the test takes about 6 secs to complete. + lock.wait(8000); + } + + assertNull("Unexpected exception thrown by async listener", _error); + + if (!pass.get()) + { + fail("Test did not complete on time. Please check the logs"); + } + } + + /** + * This test ensures that after exhausting credit (prefetch), a {@link Session#recover()} successfully + * restores credit and allows the same messages to be re-received. + */ + public void testRecoverSessionAfterCreditExhausted() throws Exception + { + final int maxPrefetch = 5; + + // We send more messages than prefetch size. This ensure that if the 0-10 client were to + // complete the message commands before the rollback command is sent, the broker would + // send additional messages utilising the release credit. This problem would manifest itself + // as an incorrect message (or no message at all) being received at the end of the test. + + final int numMessages = maxPrefetch * 2; + + setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, String.valueOf(maxPrefetch)); + + Connection con = (Connection) getConnection(); + final javax.jms.Session session = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Destination dest = session.createQueue(getTestQueueName()); + MessageConsumer cons = session.createConsumer(dest); + + sendMessage(session, dest, numMessages); + con.start(); + + for (int i=0; i< maxPrefetch; i++) + { + final Message message = cons.receive(POSIITIVE_TIMEOUT); + assertNotNull("Received:" + i, message); + assertEquals("Unexpected message received", i, message.getIntProperty(INDEX)); + } + + _logger.info("Recovering"); + session.recover(); + + Message result = cons.receive(POSIITIVE_TIMEOUT); + // Expect the first message + assertEquals("Unexpected message received", 0, result.getIntProperty(INDEX)); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java new file mode 100644 index 0000000000..b545f610d1 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java @@ -0,0 +1,324 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.basic; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.message.JMSBytesMessage; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.transport.util.Waiter; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageNotReadableException; +import javax.jms.MessageNotWriteableException; +import javax.jms.MessageProducer; +import javax.jms.Session; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class BytesMessageTest extends QpidBrokerTestCase implements MessageListener +{ + private static final Logger _logger = LoggerFactory.getLogger(BytesMessageTest.class); + + private Connection _connection; + private Destination _destination; + private Session _session; + private final List received = new ArrayList(); + private final List messages = new ArrayList(); + private int _count = 100; + public String _connectionString = "vm://:1"; + + protected void setUp() throws Exception + { + super.setUp(); + init((AMQConnection) getConnection("guest", "guest")); + } + + protected void tearDown() throws Exception + { + super.tearDown(); + } + + void init(AMQConnection connection) throws Exception + { + init(connection, new AMQQueue(connection, randomize("BytesMessageTest"), true)); + } + + void init(AMQConnection connection, AMQDestination destination) throws Exception + { + _connection = connection; + _destination = destination; + _session = connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); + + // Set up a slow consumer. + _session.createConsumer(destination).setMessageListener(this); + connection.start(); + } + + public void test() throws Exception + { + try + { + send(_count); + waitFor(_count); + check(); + _logger.info("Completed without failure"); + } + finally + { + _connection.close(); + } + } + + void send(int count) throws JMSException + { + // create a publisher + MessageProducer producer = _session.createProducer(_destination); + for (int i = 0; i < count; i++) + { + BytesMessage msg = _session.createBytesMessage(); + + try + { + msg.readFloat(); + Assert.fail("Message should not be readable"); + } + catch (MessageNotReadableException mnwe) + { + // normal execution + } + + byte[] data = ("Message " + i).getBytes(); + msg.writeBytes(data); + messages.add(data); + producer.send(msg); + } + } + + void waitFor(int count) throws InterruptedException + { + synchronized (received) + { + Waiter w = new Waiter(received, 30000); + while (received.size() < count && w.hasTime()) + { + w.await(); + } + } + } + + void check() throws JMSException + { + List actual = new ArrayList(); + for (JMSBytesMessage m : received) + { + ByteBuffer buffer = m.getData(); + byte[] data = new byte[buffer.remaining()]; + buffer.get(data); + actual.add(data); + + // Check Body Write Status + try + { + m.writeBoolean(true); + Assert.fail("Message should not be writeable"); + } + catch (MessageNotWriteableException mnwe) + { + // normal execution + } + + m.clearBody(); + + try + { + m.writeBoolean(true); + } + catch (MessageNotWriteableException mnwe) + { + Assert.fail("Message should be writeable"); + } + + // Check property write status + try + { + m.setStringProperty("test", "test"); + Assert.fail("Message should not be writeable"); + } + catch (MessageNotWriteableException mnwe) + { + // normal execution + } + + m.clearProperties(); + + try + { + m.setStringProperty("test", "test"); + } + catch (MessageNotWriteableException mnwe) + { + Assert.fail("Message should be writeable"); + } + + } + + assertEqual(messages.iterator(), actual.iterator()); + } + + private static void assertEqual(Iterator expected, Iterator actual) + { + List errors = new ArrayList(); + while (expected.hasNext() && actual.hasNext()) + { + try + { + assertEquivalent((byte[]) expected.next(), (byte[]) actual.next()); + } + catch (Exception e) + { + errors.add(e.getMessage()); + } + } + while (expected.hasNext()) + { + errors.add("Expected " + expected.next() + " but no more actual values."); + } + while (actual.hasNext()) + { + errors.add("Found " + actual.next() + " but no more expected values."); + } + + if (!errors.isEmpty()) + { + throw new RuntimeException(errors.toString()); + } + } + + private static void assertEquivalent(byte[] expected, byte[] actual) + { + if (expected.length != actual.length) + { + throw new RuntimeException("Expected length " + expected.length + " got " + actual.length); + } + + for (int i = 0; i < expected.length; i++) + { + if (expected[i] != actual[i]) + { + throw new RuntimeException("Failed on byte " + i + " of " + expected.length); + } + } + } + + public void onMessage(Message message) + { + synchronized (received) + { + received.add((JMSBytesMessage) message); + received.notify(); + } + } + + private static String randomize(String in) + { + return in + System.currentTimeMillis(); + } + + public static void main(String[] argv) throws Exception + { + final String connectionString; + final int count; + if (argv.length == 0) + { + connectionString = "vm://:1"; + count = 100; + } + else + { + connectionString = argv[0]; + count = Integer.parseInt(argv[1]); + } + + _logger.info("connectionString = " + connectionString); + _logger.info("count = " + count); + + BytesMessageTest test = new BytesMessageTest(); + test._connectionString = connectionString; + test._count = count; + test.test(); + } + + public void testModificationAfterSend() throws Exception + { + Connection connection = getConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + BytesMessage jmsMsg = session.createBytesMessage(); + Destination destination = getTestQueue(); + + /* Set the constant message contents. */ + + jmsMsg.setStringProperty("foo", "test"); + + /* Pre-populate the message body buffer to the target size. */ + byte[] jmsMsgBodyBuffer = new byte[1024]; + + connection.start(); + + /* Send messages. */ + MessageProducer producer = session.createProducer(destination); + + MessageConsumer consumer = session.createConsumer(destination); + + for(int writtenMsgCount = 0; writtenMsgCount < 10; writtenMsgCount++) + { + /* Set the per send message contents. */ + jmsMsgBodyBuffer[0] = (byte) writtenMsgCount; + jmsMsg.writeBytes(jmsMsgBodyBuffer, 0, jmsMsgBodyBuffer.length); + /** Try to write a message. */ + producer.send(jmsMsg); + } + + + for(int writtenMsgCount = 0; writtenMsgCount < 10; writtenMsgCount++) + { + BytesMessage recvdMsg = (BytesMessage) consumer.receive(1000L); + assertNotNull("Expected to receive message " + writtenMsgCount + " but did not", recvdMsg); + assertEquals("Message "+writtenMsgCount+" not of expected size", (long) ((writtenMsgCount + 1)*1024), + recvdMsg.getBodyLength()); + + } + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/FieldTableMessageTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/FieldTableMessageTest.java new file mode 100644 index 0000000000..599c8061a7 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/FieldTableMessageTest.java @@ -0,0 +1,165 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.basic; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.message.JMSBytesMessage; +import org.apache.qpid.framing.AMQFrameDecodingException; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.FieldTableFactory; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.BytesMessage; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class FieldTableMessageTest extends QpidBrokerTestCase implements MessageListener +{ + private static final Logger _logger = LoggerFactory.getLogger(FieldTableMessageTest.class); + + private AMQConnection _connection; + private AMQDestination _destination; + private AMQSession _session; + private final ArrayList received = new ArrayList(); + private FieldTable _expected; + private int _count = 10; + private String _connectionString = "vm://:1"; + private CountDownLatch _waitForCompletion; + + protected void setUp() throws Exception + { + super.setUp(); + init( (AMQConnection) getConnection("guest", "guest")); + } + + protected void tearDown() throws Exception + { + super.tearDown(); + } + + private void init(AMQConnection connection) throws Exception + { + init(connection, new AMQQueue(connection, randomize("FieldTableMessageTest"), true)); + } + + private void init(AMQConnection connection, AMQDestination destination) throws Exception + { + _connection = connection; + _destination = destination; + _session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); + + // set up a slow consumer + _session.createConsumer(destination).setMessageListener(this); + connection.start(); + + // _expected = new FieldTableTest().load("FieldTableTest2.properties"); + _expected = load(); + } + + private FieldTable load() throws IOException + { + FieldTable result = FieldTableFactory.newFieldTable(); + result.setLong("one", 1L); + result.setLong("two", 2L); + result.setLong("three", 3L); + result.setLong("four", 4L); + result.setLong("five", 5L); + + return result; + } + + public void test() throws Exception + { + int count = _count; + _waitForCompletion = new CountDownLatch(_count); + send(count); + _waitForCompletion.await(20, TimeUnit.SECONDS); + check(); + _logger.info("Completed without failure"); + _connection.close(); + } + + void send(int count) throws JMSException, IOException + { + // create a publisher + MessageProducer producer = _session.createProducer(_destination); + for (int i = 0; i < count; i++) + { + BytesMessage msg = _session.createBytesMessage(); + msg.writeBytes(_expected.getDataAsBytes()); + producer.send(msg); + } + } + + + void check() throws JMSException, AMQFrameDecodingException, IOException + { + for (Object m : received) + { + final BytesMessage bytesMessage = (BytesMessage) m; + final long bodyLength = bytesMessage.getBodyLength(); + byte[] data = new byte[(int) bodyLength]; + bytesMessage.readBytes(data); + FieldTable actual = FieldTableFactory.newFieldTable(new DataInputStream(new ByteArrayInputStream(data)), bodyLength); + for (String key : _expected.keys()) + { + assertEquals("Values for " + key + " did not match", _expected.getObject(key), actual.getObject(key)); + } + } + } + + public void onMessage(Message message) + { + synchronized (received) + { + received.add((JMSBytesMessage) message); + _waitForCompletion.countDown(); + } + } + + private static String randomize(String in) + { + return in + System.currentTimeMillis(); + } + + public static void main(String[] argv) throws Exception + { + FieldTableMessageTest test = new FieldTableMessageTest(); + test._connectionString = (argv.length == 0) ? "vm://:1" : argv[0]; + test.setUp(); + test._count = (argv.length > 1) ? Integer.parseInt(argv[1]) : 5; + test.test(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java new file mode 100644 index 0000000000..8961574d1e --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java @@ -0,0 +1,171 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.test.unit.basic; + +import java.util.Collections; +import java.util.Map; +import javax.jms.Connection; +import javax.jms.InvalidDestinationException; +import javax.jms.JMSException; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.QueueSender; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.jms.ConnectionURL; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class InvalidDestinationTest extends QpidBrokerTestCase +{ + private AMQConnection _connection; + + protected void setUp() throws Exception + { + super.setUp(); + _connection = (AMQConnection) getConnection("guest", "guest"); + } + + protected void tearDown() throws Exception + { + _connection.close(); + super.tearDown(); + } + + public void testInvalidDestination() throws Exception + { + QueueSession queueSession = _connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + + Queue invalidDestination = queueSession.createQueue("unknownQ"); + + Queue validDestination = queueSession.createQueue(getTestQueueName()); + + // This is the only easy way to create and bind a queue from the API :-( + queueSession.createConsumer(validDestination); + QueueSender sender; + TextMessage msg= queueSession.createTextMessage("Hello"); + + try + { + sender = queueSession.createSender(invalidDestination); + + sender.send(msg); + fail("Expected InvalidDestinationException"); + } + catch (InvalidDestinationException ex) + { + // pass + } + + sender = queueSession.createSender(null); + + try + { + sender.send(invalidDestination,msg); + fail("Expected InvalidDestinationException"); + } + catch (InvalidDestinationException ex) + { + // pass + } + sender.send(validDestination,msg); + sender.close(); + sender = queueSession.createSender(validDestination); + sender.send(msg); + } + + /** + * Tests that specifying the {@value ClientProperties#VERIFY_QUEUE_ON_SEND} system property + * results in an exception when sending to an invalid queue destination. + */ + public void testInvalidDestinationOnMessageProducer() throws Exception + { + setTestSystemProperty(ClientProperties.VERIFY_QUEUE_ON_SEND, "true"); + final AMQConnection connection = (AMQConnection) getConnection(); + doInvalidDestinationOnMessageProducer(connection); + } + + /** + * Tests that specifying the {@value ConnectionURL.OPTIONS_VERIFY_QUEUE_ON_SEND} + * connection URL option property results in an exception when sending to an + * invalid queue destination. + */ + public void testInvalidDestinationOnMessageProducerURL() throws Exception + { + Map options = Collections.singletonMap(ConnectionURL.OPTIONS_VERIFY_QUEUE_ON_SEND, "true"); + doInvalidDestinationOnMessageProducer(getConnectionWithOptions(options)); + } + + private void doInvalidDestinationOnMessageProducer(Connection connection) throws JMSException + { + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + String invalidQueueName = getTestQueueName() + "UnknownQ"; + Queue invalidDestination = session.createQueue(invalidQueueName); + + String validQueueName = getTestQueueName() + "KnownQ"; + Queue validDestination = session.createQueue(validQueueName); + + // This is the only easy way to create and bind a queue from the API :-( + session.createConsumer(validDestination); + + MessageProducer sender; + TextMessage msg = session.createTextMessage("Hello"); + try + { + sender = session.createProducer(invalidDestination); + sender.send(msg); + fail("Expected InvalidDestinationException"); + } + catch (InvalidDestinationException ex) + { + // pass + } + + sender = session.createProducer(null); + invalidDestination = new AMQQueue("amq.direct",invalidQueueName); + + try + { + sender.send(invalidDestination,msg); + fail("Expected InvalidDestinationException"); + } + catch (InvalidDestinationException ex) + { + // pass + } + sender.send(validDestination, msg); + sender.close(); + sender = session.createProducer(validDestination); + sender.send(msg); + + //Verify sending to an 'invalid' Topic doesn't throw an exception + String invalidTopic = getTestQueueName() + "UnknownT"; + Topic topic = session.createTopic(invalidTopic); + sender = session.createProducer(topic); + sender.send(msg); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java new file mode 100644 index 0000000000..ace8324dab --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.test.unit.basic; + + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +public class LargeMessageTest extends QpidBrokerTestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(LargeMessageTest.class); + + private Destination _destination; + private AMQSession _session; + private AMQConnection _connection; + + protected void setUp() throws Exception + { + super.setUp(); + try + { + _connection = (AMQConnection) getConnection("guest", "guest"); + init( _connection ); + } + catch (Exception e) + { + fail("Unable to initialilse connection: " + e); + } + } + + protected void tearDown() throws Exception + { + _connection.close(); + super.tearDown(); + } + + private void init(AMQConnection connection) throws Exception + { + Destination destination = new AMQQueue(connection, "LargeMessageTest", true); + init(connection, destination); + } + + private void init(AMQConnection connection, Destination destination) throws Exception + { + _destination = destination; + _session = (AMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + connection.start(); + } + + // Test boundary of 1 packet to 2 packets + public void test64kminus9() + { + checkLargeMessage((64 * 1024) - 9); + } + + public void test64kminus8() + { + checkLargeMessage((64 * 1024)-8); + } + + public void test64kminus7() + { + checkLargeMessage((64 * 1024)-7); + } + + + public void test64kplus1() + { + checkLargeMessage((64 * 1024) + 1); + } + + // Test packet boundary of 3 packtes + public void test128kminus1() + { + checkLargeMessage((128 * 1024) - 1); + } + + public void test128k() + { + checkLargeMessage(128 * 1024); + } + + public void test128kplus1() + { + checkLargeMessage((128 * 1024) + 1); + } + + // Testing larger messages + + public void test256k() + { + checkLargeMessage(256 * 1024); + } + + public void test512k() + { + checkLargeMessage(512 * 1024); + } + + public void test1024k() + { + checkLargeMessage(1024 * 1024); + } + + protected void checkLargeMessage(int messageSize) + { + try + { + MessageConsumer consumer = _session.createConsumer(_destination); + MessageProducer producer = _session.createProducer(_destination); + _logger.info("Testing message of size:" + messageSize); + + String _messageText = buildLargeMessage(messageSize); + + _logger.debug("Message built"); + + producer.send(_session.createTextMessage(_messageText)); + + TextMessage result = (TextMessage) consumer.receive(10000); + + assertNotNull("Null message recevied", result); + assertEquals("Message Size", _messageText.length(), result.getText().length()); + assertEquals("Message content differes", _messageText, result.getText()); + } + catch (JMSException e) + { + _logger.error("Exception occured", e); + fail("Exception occured:" + e.getCause()); + } + } + + private String buildLargeMessage(int size) + { + StringBuilder builder = new StringBuilder(size); + + char ch = 'a'; + + for (int i = 1; i <= size; i++) + { + builder.append(ch); + + if ((i % 1000) == 0) + { + ch++; + if (ch == ('z' + 1)) + { + ch = 'a'; + } + } + } + + return builder.toString(); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(LargeMessageTest.class); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/MapMessageTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/MapMessageTest.java new file mode 100644 index 0000000000..1b9c9fcb17 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/MapMessageTest.java @@ -0,0 +1,1269 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.basic; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.message.JMSMapMessage; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MapMessage; +import javax.jms.Message; +import javax.jms.MessageFormatException; +import javax.jms.MessageListener; +import javax.jms.MessageNotWriteableException; +import javax.jms.MessageProducer; +import javax.jms.Session; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class MapMessageTest extends QpidBrokerTestCase implements MessageListener +{ + private static final Logger _logger = LoggerFactory.getLogger(MapMessageTest.class); + + private AMQConnection _connection; + private Destination _destination; + private AMQSession _session; + private final List received = new ArrayList(); + + private static final String MESSAGE = "Message "; + private int _count = 100; + public String _connectionString = "vm://:1"; + private byte[] _bytes = { 99, 98, 97, 96, 95 }; + private static final float _smallfloat = 100.0f; + + protected void setUp() throws Exception + { + super.setUp(); + try + { + init((AMQConnection) getConnection("guest", "guest")); + } + catch (Exception e) + { + fail("Unable to initialilse connection: " + e); + } + } + + protected void tearDown() throws Exception + { + _logger.info("Tearing Down unit.basic.MapMessageTest"); + super.tearDown(); + } + + private void init(AMQConnection connection) throws Exception + { + Destination destination = new AMQQueue(connection, randomize("MapMessageTest"), true); + init(connection, destination); + } + + private void init(AMQConnection connection, Destination destination) throws Exception + { + _connection = connection; + _destination = destination; + _session = (AMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // set up a slow consumer + _session.createConsumer(destination).setMessageListener(this); + connection.start(); + } + + public void test() throws Exception + { + int count = _count; + send(count); + waitFor(count); + check(); + _connection.close(); + } + + void send(int count) throws JMSException + { + // create a publisher + MessageProducer producer = _session.createProducer(_destination); + for (int i = 0; i < count; i++) + { + MapMessage message = _session.createMapMessage(); + + setMapValues(message, i); + + producer.send(message); + } + } + + private void setMapValues(MapMessage message, int i) throws JMSException + { + message.setBoolean("odd", (i / 2) == 0); + message.setByte("byte",Byte.MAX_VALUE); + message.setBytes("bytes", _bytes); + message.setChar("char",'c'); + message.setDouble("double", Double.MAX_VALUE); + message.setFloat("float", Float.MAX_VALUE); + message.setFloat("smallfloat", 100); + message.setInt("messageNumber", i); + message.setInt("int", Integer.MAX_VALUE); + message.setLong("long", Long.MAX_VALUE); + message.setShort("short", Short.MAX_VALUE); + message.setString("message", MESSAGE + i); + + // Test Setting Object Values + message.setObject("object-bool", true); + message.setObject("object-byte", Byte.MAX_VALUE); + message.setObject("object-bytes", _bytes); + message.setObject("object-char", 'c'); + message.setObject("object-double", Double.MAX_VALUE); + message.setObject("object-float", Float.MAX_VALUE); + message.setObject("object-int", Integer.MAX_VALUE); + message.setObject("object-long", Long.MAX_VALUE); + message.setObject("object-short", Short.MAX_VALUE); + + // Set a null String value + message.setString("nullString", null); + // Highlight protocol problem + message.setString("emptyString", ""); + + } + + void waitFor(int count) throws Exception + { + long waitTime = 30000L; + long waitUntilTime = System.currentTimeMillis() + 30000L; + + synchronized (received) + { + while ((received.size() < count) && (waitTime > 0)) + { + if (received.size() < count) + { + received.wait(waitTime); + } + + if (received.size() < count) + { + waitTime = waitUntilTime - System.currentTimeMillis(); + } + } + + if (received.size() < count) + { + throw new Exception("Timed-out. Waiting for " + count + " only got " + received.size()); + } + } + } + + void check() throws JMSException + { + int count = 0; + for (JMSMapMessage m : received) + { + testMapValues(m, count); + + testCorrectExceptions(m); + + testMessageWriteStatus(m); + + testPropertyWriteStatus(m); + + count++; + } + } + + private void testCorrectExceptions(JMSMapMessage m) throws JMSException + { + testBoolean(m); + + testByte(m); + + testBytes(m); + + testChar(m); + + testDouble(m); + + testFloat(m); + + testInt(m); + + testLong(m); + + testShort(m); + + testString(m); + } + + private void testString(JMSMapMessage m) throws JMSException + { + + Assert.assertFalse(m.getBoolean("message")); + + try + { + m.getByte("message"); + fail("Exception Expected."); + } + catch (NumberFormatException nfe) + { + // normal execution + } + + try + { + m.getShort("message"); + fail("Exception Expected."); + } + catch (NumberFormatException nfe) + { + // normal execution + } + + // Try bad reads + try + { + m.getChar("message"); + fail("Exception Expected."); + } + catch (MessageFormatException npe) + { + // normal execution + } + + try + { + m.getInt("message"); + fail("Exception Expected."); + } + catch (NumberFormatException nfe) + { + // normal execution + } + + try + { + m.getLong("message"); + fail("Exception Expected."); + } + catch (NumberFormatException nfe) + { + // normal execution + } + + // Try bad reads + try + { + m.getFloat("message"); + fail("Exception Expected."); + } + catch (NumberFormatException nfe) + { + // normal execution + } + // Try bad reads + try + { + m.getDouble("message"); + fail("Exception Expected."); + } + catch (NumberFormatException nfe) + { + // normal execution + } + // Try bad reads + try + { + m.getBytes("message"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + Assert.assertEquals(MESSAGE + m.getInt("messageNumber"), m.getString("message")); + } + + private void testShort(JMSMapMessage m) throws JMSException + { + + // Try bad reads + try + { + m.getBoolean("short"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + try + { + m.getByte("short"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + Assert.assertEquals(Short.MAX_VALUE, m.getShort("short")); + + // Try bad reads + try + { + m.getChar("short"); + fail("Exception Expected."); + } + catch (MessageFormatException npe) + { + // normal execution + } + + Assert.assertEquals(Short.MAX_VALUE, m.getInt("short")); + + Assert.assertEquals(Short.MAX_VALUE, m.getLong("short")); + + // Try bad reads + try + { + m.getFloat("short"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + // Try bad reads + try + { + m.getDouble("short"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + // Try bad reads + try + { + m.getBytes("short"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + Assert.assertEquals("" + Short.MAX_VALUE, m.getString("short")); + } + + private void testLong(JMSMapMessage m) throws JMSException + { + + // Try bad reads + try + { + m.getBoolean("long"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + try + { + m.getByte("long"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + try + { + m.getShort("long"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + // Try bad reads + try + { + m.getChar("long"); + fail("Exception Expected."); + } + catch (MessageFormatException npe) + { + // normal execution + } + + try + { + m.getInt("long"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + Assert.assertEquals(Long.MAX_VALUE, m.getLong("long")); + + // Try bad reads + try + { + m.getFloat("long"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + // Try bad reads + try + { + m.getDouble("long"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + // Try bad reads + try + { + m.getBytes("long"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + Assert.assertEquals("" + Long.MAX_VALUE, m.getString("long")); + } + + private void testDouble(JMSMapMessage m) throws JMSException + { + + // Try bad reads + try + { + m.getBoolean("double"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + try + { + m.getByte("double"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + try + { + m.getShort("double"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + // Try bad reads + try + { + m.getChar("double"); + fail("Exception Expected."); + } + catch (MessageFormatException npe) + { + // normal execution + } + + try + { + m.getInt("double"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + try + { + m.getLong("double"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + // Try bad reads + try + { + m.getFloat("double"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + Assert.assertEquals(Double.MAX_VALUE, m.getDouble("double"), 0d); + + // Try bad reads + try + { + m.getBytes("double"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + Assert.assertEquals("" + Double.MAX_VALUE, m.getString("double")); + } + + private void testFloat(JMSMapMessage m) throws JMSException + { + + // Try bad reads + try + { + m.getBoolean("float"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + try + { + m.getByte("float"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + try + { + m.getShort("float"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + // Try bad reads + try + { + m.getChar("float"); + fail("Exception Expected."); + } + catch (MessageFormatException npe) + { + // normal execution + } + + try + { + m.getInt("float"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + try + { + m.getLong("float"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + Assert.assertEquals(Float.MAX_VALUE, m.getFloat("float"), 0f); + + Assert.assertEquals(_smallfloat, m.getDouble("smallfloat"), 0f); + + // Try bad reads + try + { + m.getBytes("float"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + Assert.assertEquals("" + Float.MAX_VALUE, m.getString("float")); + } + + private void testInt(JMSMapMessage m) throws JMSException + { + + // Try bad reads + try + { + m.getBoolean("int"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + try + { + m.getByte("int"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + try + { + m.getShort("int"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + // Try bad reads + try + { + m.getChar("int"); + fail("Exception Expected."); + } + catch (MessageFormatException npe) + { + // normal execution + } + + Assert.assertEquals(Integer.MAX_VALUE, m.getInt("int")); + + Assert.assertEquals(Integer.MAX_VALUE, (int) m.getLong("int")); + + // Try bad reads + try + { + m.getFloat("int"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + // Try bad reads + try + { + m.getDouble("int"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + // Try bad reads + try + { + m.getBytes("int"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + Assert.assertEquals("" + Integer.MAX_VALUE, m.getString("int")); + } + + private void testChar(JMSMapMessage m) throws JMSException + { + + // Try bad reads + try + { + m.getBoolean("char"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + try + { + m.getByte("char"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + try + { + m.getShort("char"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + Assert.assertEquals('c', m.getChar("char")); + + try + { + m.getInt("char"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + try + { + m.getLong("char"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + // Try bad reads + try + { + m.getFloat("char"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + // Try bad reads + try + { + m.getDouble("char"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + // Try bad reads + try + { + m.getBytes("char"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + Assert.assertEquals("" + 'c', m.getString("char")); + } + + private void testBytes(JMSMapMessage m) throws JMSException + { + // Try bad reads + try + { + m.getBoolean("bytes"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + try + { + m.getByte("bytes"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + try + { + m.getShort("bytes"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + // Try bad reads + try + { + m.getChar("bytes"); + fail("Exception Expected."); + } + catch (MessageFormatException npe) + { + // normal execution + } + + try + { + m.getInt("bytes"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + try + { + m.getLong("bytes"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + // Try bad reads + try + { + m.getFloat("bytes"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + // Try bad reads + try + { + m.getDouble("bytes"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + assertBytesEqual(_bytes, m.getBytes("bytes")); + + try + { + m.getString("bytes"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + } + + private void testByte(JMSMapMessage m) throws JMSException + { + // Try bad reads + try + { + m.getBoolean("byte"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + Assert.assertEquals(Byte.MAX_VALUE, m.getByte("byte")); + + Assert.assertEquals((short) Byte.MAX_VALUE, m.getShort("byte")); + + // Try bad reads + try + { + m.getChar("byte"); + fail("Exception Expected."); + } + catch (MessageFormatException npe) + { + // normal execution + } + + // Reading a byte as an int is ok + Assert.assertEquals((short) Byte.MAX_VALUE, m.getInt("byte")); + + Assert.assertEquals((short) Byte.MAX_VALUE, m.getLong("byte")); + + // Try bad reads + try + { + m.getFloat("byte"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + // Try bad reads + try + { + m.getDouble("byte"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + // Try bad reads + try + { + m.getBytes("byte"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + Assert.assertEquals("" + Byte.MAX_VALUE, m.getString("byte")); + + } + + private void testBoolean(JMSMapMessage m) throws JMSException + { + + Assert.assertEquals((m.getInt("messageNumber") / 2) == 0, m.getBoolean("odd")); + + // Try bad reads + try + { + m.getByte("odd"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + // Try bad reads + try + { + m.getShort("odd"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + // Try bad reads + try + { + m.getChar("odd"); + fail("Exception Expected."); + } + catch (MessageFormatException npe) + { + // normal execution + } + // Try bad reads + try + { + m.getInt("odd"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + // Try bad reads + try + { + m.getLong("odd"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + // Try bad reads + try + { + m.getFloat("odd"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + // Try bad reads + try + { + m.getDouble("odd"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + // Try bad reads + try + { + m.getBytes("odd"); + fail("Exception Expected."); + } + catch (MessageFormatException nfe) + { + // normal execution + } + + Assert.assertEquals("" + ((m.getInt("messageNumber") / 2) == 0), m.getString("odd")); + } + + private void testPropertyWriteStatus(JMSMapMessage m) throws JMSException + { + // Check property write status + try + { + m.setStringProperty("test", "test"); + Assert.fail("Message should not be writeable"); + } + catch (MessageNotWriteableException mnwe) + { + // normal execution + } + + m.clearProperties(); + + try + { + m.setStringProperty("test", "test"); + } + catch (MessageNotWriteableException mnwe) + { + Assert.fail("Message should be writeable"); + } + } + + private void testMessageWriteStatus(JMSMapMessage m) throws JMSException + { + try + { + m.setInt("testint", 3); + fail("Message should not be writeable"); + } + catch (MessageNotWriteableException mnwe) + { + // normal execution + } + + m.clearBody(); + + try + { + m.setInt("testint", 3); + } + catch (MessageNotWriteableException mnwe) + { + Assert.fail("Message should be writeable"); + } + } + + private void testMapValues(JMSMapMessage m, int count) throws JMSException + { + // Test get + + // Boolean + assertEqual((count / 2) == 0, m.getBoolean("odd")); + assertEqual("" + ((count / 2) == 0), m.getString("odd")); + + // Byte + assertEqual(Byte.MAX_VALUE, m.getByte("byte")); + assertEqual("" + Byte.MAX_VALUE, m.getString("byte")); + + // Bytes + assertBytesEqual(_bytes, m.getBytes("bytes")); + + // Char + assertEqual('c', m.getChar("char")); + + // Double + assertEqual(Double.MAX_VALUE, m.getDouble("double")); + assertEqual("" + Double.MAX_VALUE, m.getString("double")); + + // Float + assertEqual(Float.MAX_VALUE, m.getFloat("float")); + assertEqual(_smallfloat, (float) m.getDouble("smallfloat")); + assertEqual("" + Float.MAX_VALUE, m.getString("float")); + + // Integer + assertEqual(Integer.MAX_VALUE, m.getInt("int")); + assertEqual("" + Integer.MAX_VALUE, m.getString("int")); + assertEqual(count, m.getInt("messageNumber")); + + // long + assertEqual(Long.MAX_VALUE, m.getLong("long")); + assertEqual("" + Long.MAX_VALUE, m.getString("long")); + + // Short + assertEqual(Short.MAX_VALUE, m.getShort("short")); + assertEqual("" + Short.MAX_VALUE, m.getString("short")); + assertEqual((int) Short.MAX_VALUE, m.getInt("short")); + + // String + assertEqual(MESSAGE + count, m.getString("message")); + + // Test getObjects + assertEqual(true, m.getObject("object-bool")); + assertEqual(Byte.MAX_VALUE, m.getObject("object-byte")); + assertBytesEqual(_bytes, (byte[]) m.getObject("object-bytes")); + assertEqual('c', m.getObject("object-char")); + assertEqual(Double.MAX_VALUE, m.getObject("object-double")); + assertEqual(Float.MAX_VALUE, m.getObject("object-float")); + assertEqual(Integer.MAX_VALUE, m.getObject("object-int")); + assertEqual(Long.MAX_VALUE, m.getObject("object-long")); + assertEqual(Short.MAX_VALUE, m.getObject("object-short")); + + // Check Special values + assertTrue(m.getString("nullString") == null); + assertEqual("", m.getString("emptyString")); + } + + private void assertBytesEqual(byte[] expected, byte[] actual) + { + Assert.assertEquals(expected.length, actual.length); + + for (int index = 0; index < expected.length; index++) + { + Assert.assertEquals(expected[index], actual[index]); + } + } + + private static void assertEqual(Iterator expected, Iterator actual) + { + List errors = new ArrayList(); + while (expected.hasNext() && actual.hasNext()) + { + try + { + assertEqual(expected.next(), actual.next()); + } + catch (Exception e) + { + errors.add(e.getMessage()); + } + } + while (expected.hasNext()) + { + errors.add("Expected " + expected.next() + " but no more actual values."); + } + while (actual.hasNext()) + { + errors.add("Found " + actual.next() + " but no more expected values."); + } + + if (!errors.isEmpty()) + { + throw new RuntimeException(errors.toString()); + } + } + + private static void assertEqual(Object expected, Object actual) + { + if (!expected.equals(actual)) + { + throw new RuntimeException("Expected '" + expected + "' found '" + actual + "'"); + } + } + + public void onMessage(Message message) + { + synchronized (received) + { + _logger.info("****************** Recevied Messgage:" + message); + received.add((JMSMapMessage) message); + received.notify(); + } + } + + private static String randomize(String in) + { + return in + System.currentTimeMillis(); + } + + public static void main(String[] argv) throws Exception + { + MapMessageTest test = new MapMessageTest(); + test._connectionString = (argv.length == 0) ? "vm://:1" : argv[0]; + test.setUp(); + if (argv.length > 1) + { + test._count = Integer.parseInt(argv[1]); + } + + test.test(); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(MapMessageTest.class); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java new file mode 100644 index 0000000000..2d8847ea33 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java @@ -0,0 +1,223 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.basic; + +import org.apache.qpid.framing.AMQShortString; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQDestination; +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; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; + +public class MultipleConnectionTest extends QpidBrokerTestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(MultipleConnectionTest.class); + + public static final String _defaultBroker = "vm://:1"; + public String _connectionString = _defaultBroker; + + private class Receiver + { + private AMQConnection _connection; + private Session[] _sessions; + private MessageCounter[] _counters; + + Receiver(String broker, AMQDestination dest, int sessions) throws Exception + { + this((AMQConnection) getConnection("guest", "guest"), dest, sessions); + } + + Receiver(AMQConnection connection, AMQDestination dest, int sessions) throws Exception + { + _connection = connection; + _sessions = new AMQSession[sessions]; + _counters = new MessageCounter[sessions]; + for (int i = 0; i < sessions; i++) + { + _sessions[i] = _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); + _counters[i] = new MessageCounter(_sessions[i].toString()); + _sessions[i].createConsumer(dest).setMessageListener(_counters[i]); + } + + _connection.start(); + } + + void close() throws JMSException + { + _connection.close(); + } + + public MessageCounter[] getCounters() + { + return _counters; + } + } + + private class Publisher + { + private AMQConnection _connection; + private Session _session; + private MessageProducer _producer; + + Publisher(String broker, AMQDestination dest) throws Exception + { + this((AMQConnection) getConnection("guest", "guest"), dest); + } + + Publisher(AMQConnection connection, AMQDestination dest) throws Exception + { + _connection = connection; + _session = _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); + _producer = _session.createProducer(dest); + } + + void send(String msg) throws JMSException + { + _producer.send(_session.createTextMessage(msg)); + } + + void close() throws JMSException + { + _connection.close(); + } + } + + private static class MessageCounter implements MessageListener + { + private final String _name; + private int _count; + + MessageCounter(String name) + { + _name = name; + } + + public synchronized void onMessage(Message message) + { + _count++; + notify(); + } + + synchronized boolean waitUntil(int expected, long maxWait) throws InterruptedException + { + long start = System.currentTimeMillis(); + while (expected > _count) + { + long timeLeft = maxWait - timeSince(start); + if (timeLeft <= 0) + { + break; + } + + wait(timeLeft); + } + + return expected <= _count; + } + + private long timeSince(long start) + { + return System.currentTimeMillis() - start; + } + + public synchronized String toString() + { + return _name + ": " + _count; + } + } + + private static void waitForCompletion(int expected, long wait, Receiver[] receivers) throws InterruptedException + { + for (int i = 0; i < receivers.length; i++) + { + waitForCompletion(expected, wait, receivers[i].getCounters()); + } + } + + private static void waitForCompletion(int expected, long wait, MessageCounter[] counters) throws InterruptedException + { + for (int i = 0; i < counters.length; i++) + { + if (!counters[i].waitUntil(expected, wait)) + { + throw new RuntimeException("Expected: " + expected + " got " + counters[i]); + } + } + } + + private static String randomize(String in) + { + return in + System.currentTimeMillis(); + } + + public static void main(String[] argv) throws Exception + { + String broker = (argv.length > 0) ? argv[0] : _defaultBroker; + + MultipleConnectionTest test = new MultipleConnectionTest(); + test._connectionString = broker; + test.test(); + } + + public void test() throws Exception + { + String broker = _connectionString; + int messages = 10; + + AMQTopic topic = new AMQTopic(AMQShortString.valueOf(ExchangeDefaults.TOPIC_EXCHANGE_NAME), "amq.topic"); + + Receiver[] receivers = new Receiver[] { new Receiver(broker, topic, 2), new Receiver(broker, topic, 14) }; + + Publisher publisher = new Publisher(broker, topic); + for (int i = 0; i < messages; i++) + { + publisher.send("Message " + (i + 1)); + } + + try + { + waitForCompletion(messages, 5000, receivers); + _logger.info("All receivers received all expected messages"); + } + finally + { + publisher.close(); + for (int i = 0; i < receivers.length; i++) + { + receivers[i].close(); + } + } + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(MultipleConnectionTest.class); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/ObjectMessageTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/ObjectMessageTest.java new file mode 100644 index 0000000000..4b5922902d --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/ObjectMessageTest.java @@ -0,0 +1,276 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.basic; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.message.JMSObjectMessage; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageNotWriteableException; +import javax.jms.MessageProducer; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class ObjectMessageTest extends QpidBrokerTestCase implements MessageListener +{ + private static final Logger _logger = LoggerFactory.getLogger(ObjectMessageTest.class); + + private AMQConnection _connection; + private AMQDestination _destination; + private AMQSession _session; + private final List received = new ArrayList(); + private final List messages = new ArrayList(); + private int _count = 100; + public String _connectionString = "vm://:1"; + + protected void setUp() throws Exception + { + super.setUp(); + try + { + init( (AMQConnection) getConnection("guest", "guest")); + } + catch (Exception e) + { + fail("Uable to initialise: " + e); + } + } + + protected void tearDown() throws Exception + { + super.tearDown(); + } + + private void init(AMQConnection connection) throws Exception + { + init(connection, new AMQQueue(connection, randomize("ObjectMessageTest"), true)); + } + + private void init(AMQConnection connection, AMQDestination destination) throws Exception + { + _connection = connection; + _destination = destination; + _session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); + + // set up a slow consumer + _session.createConsumer(destination).setMessageListener(this); + connection.start(); + } + + public void test() throws Exception + { + int count = _count; + send(count); + waitFor(count); + check(); + _logger.info("Completed without failure"); + _connection.close(); + } + + void send(int count) throws JMSException + { + // create a publisher + MessageProducer producer = _session.createProducer(_destination); + for (int i = 0; i < count; i++) + { + Payload payload = new Payload("Message " + i); + messages.add(payload); + producer.send(_session.createObjectMessage(payload)); + } + } + + void waitFor(int count) throws InterruptedException + { + synchronized (received) + { + long endTime = System.currentTimeMillis() + 30000L; + while (received.size() < count) + { + received.wait(30000); + if(received.size() < count && System.currentTimeMillis() > endTime) + { + throw new RuntimeException("Only received " + received.size() + " messages, was expecting " + count); + } + } + } + } + + void check() throws JMSException + { + List actual = new ArrayList(); + for (JMSObjectMessage m : received) + { + actual.add(m.getObject()); + + try + { + m.setObject("Test text"); + Assert.fail("Message should not be writeable"); + } + catch (MessageNotWriteableException mnwe) + { + // normal execution + } + + m.clearBody(); + + try + { + m.setObject("Test text"); + } + catch (MessageNotWriteableException mnwe) + { + Assert.fail("Message should be writeable"); + } + + // Check property write status + try + { + m.setStringProperty("test", "test"); + Assert.fail("Message should not be writeable"); + } + catch (MessageNotWriteableException mnwe) + { + // normal execution + } + + m.clearProperties(); + + try + { + m.setStringProperty("test", "test"); + } + catch (MessageNotWriteableException mnwe) + { + Assert.fail("Message should be writeable"); + } + + } + + assertEqual(messages.iterator(), actual.iterator()); + + } + + private static void assertEqual(Iterator expected, Iterator actual) + { + List errors = new ArrayList(); + while (expected.hasNext() && actual.hasNext()) + { + try + { + assertEqual(expected.next(), actual.next()); + } + catch (Exception e) + { + errors.add(e.getMessage()); + } + } + while (expected.hasNext()) + { + errors.add("Expected " + expected.next() + " but no more actual values."); + } + while (actual.hasNext()) + { + errors.add("Found " + actual.next() + " but no more expected values."); + } + + if (!errors.isEmpty()) + { + throw new RuntimeException(errors.toString()); + } + } + + private static void assertEqual(Object expected, Object actual) + { + if (!expected.equals(actual)) + { + throw new RuntimeException("Expected '" + expected + "' found '" + actual + "'"); + } + } + + public void onMessage(Message message) + { + synchronized (received) + { + received.add((JMSObjectMessage) message); + received.notify(); + } + } + + private static String randomize(String in) + { + return in + System.currentTimeMillis(); + } + + private static class Payload implements Serializable + { + private final String data; + + Payload(String data) + { + this.data = data; + } + + public int hashCode() + { + return data.hashCode(); + } + + public boolean equals(Object o) + { + return (o instanceof Payload) && ((Payload) o).data.equals(data); + } + + public String toString() + { + return "Payload[" + data + "]"; + } + } + + public static void main(String[] argv) throws Exception + { + ObjectMessageTest test = new ObjectMessageTest(); + test._connectionString = (argv.length == 0) ? "vm://:1" : argv[0]; + test.setUp(); + if (argv.length > 1) + { + test._count = Integer.parseInt(argv[1]); + } + + test.test(); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(ObjectMessageTest.class); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/PropertyValueTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/PropertyValueTest.java new file mode 100644 index 0000000000..c7ff564beb --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/PropertyValueTest.java @@ -0,0 +1,386 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.basic; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageFormatException; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +import org.junit.Assert; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.message.JMSTextMessage; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PropertyValueTest extends QpidBrokerTestCase implements MessageListener +{ + private static final Logger _logger = LoggerFactory.getLogger(PropertyValueTest.class); + + private AMQConnection _connection; + private Destination _destination; + private AMQSession _session; + private final List received = new ArrayList(); + private final List messages = new ArrayList(); + private Map _replyToDestinations; + private int _count = 1; + public String _connectionString = "vm://:1"; + private static final String USERNAME = "guest"; + + protected void setUp() throws Exception + { + _replyToDestinations = new HashMap(); + super.setUp(); + } + + protected void tearDown() throws Exception + { + super.tearDown(); + } + + private void init(AMQConnection connection) throws Exception + { + Destination destination = new AMQQueue(connection, randomize("PropertyValueTest"), true); + init(connection, destination); + } + + private void init(AMQConnection connection, Destination destination) throws Exception + { + _connection = connection; + _destination = destination; + _session = (AMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // set up a slow consumer + _session.createConsumer(destination).setMessageListener(this); + connection.start(); + } + + private Message getTestMessage() throws Exception + { + Connection conn = getConnection(); + Session ssn = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + return ssn.createTextMessage(); + } + + public void testGetNonexistent() throws Exception + { + Message m = getTestMessage(); + String s = m.getStringProperty("nonexistent"); + assertNull(s); + } + + private static final String[] NAMES = { + "setBooleanProperty", "setByteProperty", "setShortProperty", + "setIntProperty", "setLongProperty", "setFloatProperty", + "setDoubleProperty", "setObjectProperty" + }; + + private static final Class[] TYPES = { + boolean.class, byte.class, short.class, int.class, long.class, + float.class, double.class, Object.class + }; + + private static final Object[] VALUES = { + true, (byte) 0, (short) 0, 0, (long) 0, (float) 0, (double) 0, + new Object() + }; + + public void testSetEmptyPropertyName() throws Exception + { + Message m = getTestMessage(); + + for (int i = 0; i < NAMES.length; i++) + { + Method meth = m.getClass().getMethod(NAMES[i], String.class, TYPES[i]); + try + { + meth.invoke(m, "", VALUES[i]); + fail("expected illegal argument exception"); + } + catch (InvocationTargetException e) + { + assertEquals(e.getCause().getClass(), IllegalArgumentException.class); + } + } + } + + public void testSetDisallowedClass() throws Exception + { + Message m = getTestMessage(); + try + { + m.setObjectProperty("foo", new Object()); + fail("expected a MessageFormatException"); + } + catch (MessageFormatException e) + { + // pass + } + } + + public void testOnce() + { + runBatch(1); + } + + public void test50() + { + runBatch(50); + } + + private void runBatch(int runSize) + { + try + { + int run = 0; + while (run < runSize) + { + _logger.error("Run Number:" + run++); + try + { + init( (AMQConnection) getConnection("guest", "guest")); + } + catch (Exception e) + { + _logger.error("exception:", e); + fail("Unable to initialilse connection: " + e); + } + + int count = _count; + send(count); + waitFor(count); + check(); + _logger.info("Completed without failure"); + + Thread.sleep(10); + _connection.close(); + + _logger.error("End Run Number:" + (run - 1)); + } + } + catch (Exception e) + { + _logger.error(e.getMessage(), e); + } + } + + void send(int count) throws JMSException + { + // create a publisher + MessageProducer producer = _session.createProducer(_destination); + for (int i = 0; i < count; i++) + { + String text = "Message " + i; + messages.add(text); + Message m = _session.createTextMessage(text); + + m.setBooleanProperty("Bool", true); + + m.setByteProperty("Byte", (byte) Byte.MAX_VALUE); + m.setDoubleProperty("Double", (double) Double.MAX_VALUE); + m.setFloatProperty("Float", (float) Float.MAX_VALUE); + m.setIntProperty("Int", (int) Integer.MAX_VALUE); + + m.setJMSCorrelationID("Correlation"); + // fixme the m.setJMSMessage has no effect + producer.setPriority(8); + m.setJMSPriority(3); + + // Queue + Queue q; + + if ((i / 2) == 0) + { + q = _session.createTemporaryQueue(); + } + else + { + q = new AMQQueue(_connection, "TestReply"); + } + + m.setJMSReplyTo(q); + + m.setStringProperty("ReplyToIndex", String.valueOf(i)); + _replyToDestinations.put(String.valueOf(i), q); + + _logger.debug("Message:" + m); + + m.setJMSType("Test"); + m.setLongProperty("UnsignedInt", (long) 4294967295L); + m.setLongProperty("Long", (long) Long.MAX_VALUE); + + m.setShortProperty("Short", (short) Short.MAX_VALUE); + m.setStringProperty("String", "Test"); + + _logger.debug("Sending Msg:" + m); + producer.send(m); + } + } + + void waitFor(int count) throws InterruptedException + { + synchronized (received) + { + while (received.size() < count) + { + received.wait(); + } + } + } + + void check() throws JMSException, URISyntaxException + { + List actual = new ArrayList(); + for (JMSTextMessage m : received) + { + actual.add(m.getText()); + + // Check Properties + + Assert.assertEquals("Check Boolean properties are correctly transported", true, m.getBooleanProperty("Bool")); + Assert.assertEquals("Check Byte properties are correctly transported", Byte.MAX_VALUE, + m.getByteProperty("Byte")); + Assert.assertEquals("Check Double properties are correctly transported", Double.MAX_VALUE, + m.getDoubleProperty("Double"), 0d); + Assert.assertEquals("Check Float properties are correctly transported", Float.MAX_VALUE, + m.getFloatProperty("Float"), 0f); + Assert.assertEquals("Check Int properties are correctly transported", Integer.MAX_VALUE, + m.getIntProperty("Int")); + Assert.assertEquals("Check CorrelationID properties are correctly transported", "Correlation", + m.getJMSCorrelationID()); + Assert.assertEquals("Check Priority properties are correctly transported", 8, m.getJMSPriority()); + + // Queue + String replyToIndex = m.getStringProperty("ReplyToIndex"); + Assert.assertEquals("Check ReplyTo properties are correctly transported", _replyToDestinations.get(replyToIndex), m.getJMSReplyTo()); + + Assert.assertEquals("Check Type properties are correctly transported", "Test", m.getJMSType()); + + Assert.assertEquals("Check Short properties are correctly transported", (short) Short.MAX_VALUE, + m.getShortProperty("Short")); + Assert.assertEquals("Check UnsignedInt properties are correctly transported", (long) 4294967295L, + m.getLongProperty("UnsignedInt")); + Assert.assertEquals("Check Long properties are correctly transported", (long) Long.MAX_VALUE, + m.getLongProperty("Long")); + Assert.assertEquals("Check String properties are correctly transported", "Test", m.getStringProperty("String")); + + //JMSXUserID + if (m.getStringProperty("JMSXUserID") != null) + { + Assert.assertEquals("Check 'JMSXUserID' is supported ", USERNAME, + m.getStringProperty("JMSXUserID")); + } + } + + received.clear(); + + assertEqual(messages.iterator(), actual.iterator()); + + messages.clear(); + } + + private static void assertEqual(Iterator expected, Iterator actual) + { + List errors = new ArrayList(); + while (expected.hasNext() && actual.hasNext()) + { + try + { + assertEqual(expected.next(), actual.next()); + } + catch (Exception e) + { + errors.add(e.getMessage()); + } + } + while (expected.hasNext()) + { + errors.add("Expected " + expected.next() + " but no more actual values."); + } + while (actual.hasNext()) + { + errors.add("Found " + actual.next() + " but no more expected values."); + } + + if (!errors.isEmpty()) + { + throw new RuntimeException(errors.toString()); + } + } + + private static void assertEqual(Object expected, Object actual) + { + if (!expected.equals(actual)) + { + throw new RuntimeException("Expected '" + expected + "' found '" + actual + "'"); + } + } + + public void onMessage(Message message) + { + synchronized (received) + { + received.add((JMSTextMessage) message); + received.notify(); + } + } + + private static String randomize(String in) + { + return in + System.currentTimeMillis(); + } + + public static void main(String[] argv) throws Exception + { + PropertyValueTest test = new PropertyValueTest(); + test._connectionString = (argv.length == 0) ? "vm://:1" : argv[0]; + test.setUp(); + if (argv.length > 1) + { + test._count = Integer.parseInt(argv[1]); + } + + test.testOnce(); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(PropertyValueTest.class); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/PubSubTwoConnectionTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/PubSubTwoConnectionTest.java new file mode 100644 index 0000000000..3ef8524656 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/PubSubTwoConnectionTest.java @@ -0,0 +1,75 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.basic; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; + +/** + * @author Apache Software Foundation + */ +public class PubSubTwoConnectionTest extends QpidBrokerTestCase +{ + protected void setUp() throws Exception + { + super.setUp(); + } + + protected void tearDown() throws Exception + { + super.tearDown(); + } + + /** + * This tests that a consumer is set up synchronously + * @throws Exception + */ + public void testTwoConnections() throws Exception + { + + AMQConnection con1 = (AMQConnection) getConnection("guest", "guest"); + + Topic topic = new AMQTopic(con1, "MyTopic"); + + Session session1 = con1.createSession(false, AMQSession.NO_ACKNOWLEDGE); + MessageProducer producer = session1.createProducer(topic); + + Connection con2 = (AMQConnection) getConnection("guest", "guest") ; + Session session2 = con2.createSession(false, AMQSession.NO_ACKNOWLEDGE); + MessageConsumer consumer = session2.createConsumer(topic); + con2.start(); + producer.send(session1.createTextMessage("Hello")); + TextMessage tm1 = (TextMessage) consumer.receive(2000); + assertNotNull(tm1); + assertEquals("Hello", tm1.getText()); + con1.close(); + con2.close(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/SessionStartTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/SessionStartTest.java new file mode 100644 index 0000000000..cc64dbb125 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/SessionStartTest.java @@ -0,0 +1,115 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.basic; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; + +public class SessionStartTest extends QpidBrokerTestCase implements MessageListener +{ + private static final Logger _logger = LoggerFactory.getLogger(SessionStartTest.class); + + private AMQConnection _connection; + private AMQDestination _destination; + private AMQSession _session; + private int count; + public String _connectionString = "vm://:1"; + + protected void setUp() throws Exception + { + super.setUp(); + init((AMQConnection) getConnection("guest", "guest")); + } + + protected void tearDown() throws Exception + { + super.tearDown(); + } + + private void init(AMQConnection connection) throws Exception + { + init(connection, + new AMQQueue(connection.getDefaultQueueExchangeName(), new AMQShortString(randomize("SessionStartTest")), true)); + } + + private void init(AMQConnection connection, AMQDestination destination) throws Exception + { + _connection = connection; + _destination = destination; + connection.start(); + + _session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); + _session.createConsumer(destination).setMessageListener(this); + } + + public synchronized void test() throws JMSException, InterruptedException + { + try + { + _session.createProducer(_destination).send(_session.createTextMessage("Message")); + _logger.info("Message sent, waiting for response..."); + wait(1000); + if (count > 0) + { + _logger.info("Got message"); + } + else + { + throw new RuntimeException("Did not get message!"); + } + } + finally + { + _session.close(); + _connection.close(); + } + } + + public synchronized void onMessage(Message message) + { + count++; + notify(); + } + + private static String randomize(String in) + { + return in + System.currentTimeMillis(); + } + + public static void main(String[] argv) throws Exception + { + SessionStartTest test = new SessionStartTest(); + test._connectionString = (argv.length == 0) ? "localhost:5672" : argv[0]; + test.setUp(); + test.test(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/TextMessageTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/TextMessageTest.java new file mode 100644 index 0000000000..d4081817ee --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/TextMessageTest.java @@ -0,0 +1,246 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.basic; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.message.JMSTextMessage; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageNotWriteableException; +import javax.jms.MessageProducer; +import javax.jms.Session; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class TextMessageTest extends QpidBrokerTestCase implements MessageListener +{ + private static final Logger _logger = LoggerFactory.getLogger(TextMessageTest.class); + + private AMQConnection _connection; + private Destination _destination; + private AMQSession _session; + private final List received = new ArrayList(); + private final List messages = new ArrayList(); + private int _count = 100; + public String _connectionString = "vm://:1"; + private CountDownLatch _waitForCompletion; + + protected void setUp() throws Exception + { + super.setUp(); + try + { + init((AMQConnection) getConnection("guest", "guest")); + } + catch (Exception e) + { + fail("Unable to initialilse connection: " + e); + } + } + + protected void tearDown() throws Exception + { + super.tearDown(); + } + + private void init(AMQConnection connection) throws Exception + { + Destination destination = + new AMQQueue(connection.getDefaultQueueExchangeName(), new AMQShortString(randomize("TextMessageTest")), true); + init(connection, destination); + } + + private void init(AMQConnection connection, Destination destination) throws Exception + { + _connection = connection; + _destination = destination; + _session = (AMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // set up a slow consumer + try + { + _session.createConsumer(destination).setMessageListener(this); + } + catch (Throwable e) + { + _logger.error("Error creating consumer", e); + } + connection.start(); + } + + public void test() throws Exception + { + int count = _count; + _waitForCompletion = new CountDownLatch(_count); + send(count); + _waitForCompletion.await(20, TimeUnit.SECONDS); + check(); + _logger.info("Completed without failure"); + _connection.close(); + } + + void send(int count) throws JMSException + { + // create a publisher + MessageProducer producer = _session.createProducer(_destination); + for (int i = 0; i < count; i++) + { + String text = "Message " + i; + messages.add(text); + Message m = _session.createTextMessage(text); + //m.setStringProperty("String", "hello"); + + _logger.info("Sending Msg:" + m); + producer.send(m); + } + _logger.info("sent " + count + " mesages"); + } + + + void check() throws JMSException + { + List actual = new ArrayList(); + for (JMSTextMessage m : received) + { + actual.add(m.getText()); + + // Check body write status + try + { + m.setText("Test text"); + Assert.fail("Message should not be writeable"); + } + catch (MessageNotWriteableException mnwe) + { + // normal execution + } + + m.clearBody(); + + try + { + m.setText("Test text"); + } + catch (MessageNotWriteableException mnwe) + { + Assert.fail("Message should be writeable"); + } + + // Check property write status + try + { + m.setStringProperty("test", "test"); + Assert.fail("Message should not be writeable"); + } + catch (MessageNotWriteableException mnwe) + { + // normal execution + } + + m.clearProperties(); + + try + { + m.setStringProperty("test", "test"); + } + catch (MessageNotWriteableException mnwe) + { + Assert.fail("Message should be writeable"); + } + + } + + assertEqual(messages.iterator(), actual.iterator()); + } + + private static void assertEqual(Iterator expected, Iterator actual) + { + List errors = new ArrayList(); + while (expected.hasNext() && actual.hasNext()) + { + try + { + assertEqual(expected.next(), actual.next()); + } + catch (Exception e) + { + errors.add(e.getMessage()); + } + } + while (expected.hasNext()) + { + errors.add("Expected " + expected.next() + " but no more actual values."); + } + while (actual.hasNext()) + { + errors.add("Found " + actual.next() + " but no more expected values."); + } + + if (!errors.isEmpty()) + { + throw new RuntimeException(errors.toString()); + } + } + + private static void assertEqual(Object expected, Object actual) + { + if (!expected.equals(actual)) + { + throw new RuntimeException("Expected '" + expected + "' found '" + actual + "'"); + } + } + + public void onMessage(Message message) + { + synchronized (received) + { + _logger.info("===== received one message"); + received.add((JMSTextMessage) message); + _waitForCompletion.countDown(); + } + } + + private static String randomize(String in) + { + return in + System.currentTimeMillis(); + } + + + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(TextMessageTest.class); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/close/CloseTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/close/CloseTest.java new file mode 100644 index 0000000000..48d290c986 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/basic/close/CloseTest.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.test.unit.basic.close; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +public class CloseTest extends QpidBrokerTestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(CloseTest.class); + + public void testCloseQueueReceiver() throws Exception + { + AMQConnection connection = (AMQConnection) getConnection("guest", "guest"); + + Session session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + + Queue queue = session.createQueue("test-queue"); + MessageConsumer consumer = session.createConsumer(queue); + + MessageProducer producer_not_used_but_created_for_testing = session.createProducer(queue); + + connection.start(); + + _logger.info("About to close consumer"); + + consumer.close(); + + _logger.info("Closed Consumer"); + connection.close(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/AMQSessionTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/AMQSessionTest.java new file mode 100644 index 0000000000..0d81b66be0 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/AMQSessionTest.java @@ -0,0 +1,104 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.client; + +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.test.utils.QpidBrokerTestCase; + +import javax.jms.JMSException; +import javax.jms.QueueReceiver; +import javax.jms.TopicSubscriber; + +/** + * Tests for QueueReceiver and TopicSubscriber creation methods on AMQSession + */ +public class AMQSessionTest extends QpidBrokerTestCase +{ + + private static AMQSession _session; + private static AMQTopic _topic; + private static AMQQueue _queue; + private static AMQConnection _connection; + + protected void setUp() throws Exception + { + super.setUp(); + _connection = (AMQConnection) getConnection("guest", "guest"); + _topic = new AMQTopic(_connection,"mytopic"); + _queue = new AMQQueue(_connection,"myqueue"); + _session = (AMQSession) _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); + } + + protected void tearDown() throws Exception + { + try + { + _connection.close(); + } + catch (JMSException e) + { + //just close + } + super.tearDown(); + } + + public void testCreateSubscriber() throws JMSException + { + TopicSubscriber subscriber = _session.createSubscriber(_topic); + assertEquals("Topic names should match from TopicSubscriber", _topic.getTopicName(), subscriber.getTopic().getTopicName()); + + subscriber = _session.createSubscriber(_topic, "abc", false); + assertEquals("Topic names should match from TopicSubscriber with selector", _topic.getTopicName(), subscriber.getTopic().getTopicName()); + } + + public void testCreateDurableSubscriber() throws JMSException + { + TopicSubscriber subscriber = _session.createDurableSubscriber(_topic, "mysubname"); + assertEquals("Topic names should match from durable TopicSubscriber", _topic.getTopicName(), subscriber.getTopic().getTopicName()); + + subscriber = _session.createDurableSubscriber(_topic, "mysubname2", "abc", false); + assertEquals("Topic names should match from durable TopicSubscriber with selector", _topic.getTopicName(), subscriber.getTopic().getTopicName()); + _session.unsubscribe("mysubname"); + _session.unsubscribe("mysubname2"); + } + + public void testCreateQueueReceiver() throws JMSException + { + QueueReceiver receiver = _session.createQueueReceiver(_queue); + assertEquals("Queue names should match from QueueReceiver", _queue.getQueueName(), receiver.getQueue().getQueueName()); + + receiver = _session.createQueueReceiver(_queue, "abc"); + assertEquals("Queue names should match from QueueReceiver with selector", _queue.getQueueName(), receiver.getQueue().getQueueName()); + } + + public void testCreateReceiver() throws JMSException + { + QueueReceiver receiver = _session.createReceiver(_queue); + assertEquals("Queue names should match from QueueReceiver", _queue.getQueueName(), receiver.getQueue().getQueueName()); + + receiver = _session.createReceiver(_queue, "abc"); + assertEquals("Queue names should match from QueueReceiver with selector", _queue.getQueueName(), receiver.getQueue().getQueueName()); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java new file mode 100644 index 0000000000..77df6c58d9 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/DynamicQueueExchangeCreateTest.java @@ -0,0 +1,258 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.client; + +import java.io.IOException; + +import org.apache.qpid.AMQException; +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.management.common.mbeans.ManagedExchange; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.url.BindingURL; + +import javax.jms.Connection; +import javax.jms.InvalidDestinationException; +import javax.jms.JMSException; +import javax.jms.Queue; +import javax.jms.Session; + +public class DynamicQueueExchangeCreateTest extends QpidBrokerTestCase +{ + private JMXTestUtils _jmxUtils; + + @Override + public void setUp() throws Exception + { + getBrokerConfiguration().addJmxManagementConfiguration(); + + _jmxUtils = new JMXTestUtils(this); + + super.setUp(); + _jmxUtils.open(); + } + + @Override + public void tearDown() throws Exception + { + try + { + if (_jmxUtils != null) + { + _jmxUtils.close(); + } + } + finally + { + super.tearDown(); + } + } + + /* + * Tests to validate that setting the respective qpid.declare_queues, + * qpid.declare_exchanges system properties functions as expected. + */ + + public void testQueueNotDeclaredDuringConsumerCreation() throws Exception + { + setSystemProperty(ClientProperties.QPID_DECLARE_QUEUES_PROP_NAME, "false"); + + Connection connection = getConnection(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Queue queue = session.createQueue(getTestQueueName()); + + try + { + session.createConsumer(queue); + fail("JMSException should be thrown as the queue does not exist"); + } + catch (JMSException e) + { + checkExceptionErrorCode(e, AMQConstant.NOT_FOUND); + } + } + + public void testExchangeNotDeclaredDuringConsumerCreation() throws Exception + { + setSystemProperty(ClientProperties.QPID_DECLARE_EXCHANGES_PROP_NAME, "false"); + + Connection connection = getConnection(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + String exchangeName = getTestQueueName(); + Queue queue = session.createQueue("direct://" + exchangeName + "/queue/queue"); + + try + { + session.createConsumer(queue); + fail("JMSException should be thrown as the exchange does not exist"); + } + catch (JMSException e) + { + checkExceptionErrorCode(e, AMQConstant.NOT_FOUND); + } + + //verify the exchange was not declared + String exchangeObjectName = _jmxUtils.getExchangeObjectName("test", exchangeName); + assertFalse("exchange should not exist", _jmxUtils.doesManagedObjectExist(exchangeObjectName)); + } + + /** + * Checks that setting {@value ClientProperties#QPID_DECLARE_EXCHANGES_PROP_NAME} false results in + * disabling implicit ExchangeDeclares during producer creation when using a {@link BindingURL} + */ + public void testExchangeNotDeclaredDuringProducerCreation() throws Exception + { + Connection connection = getConnection(); + Session session1 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + String exchangeName1 = getTestQueueName() + "1"; + + + Queue queue = session1.createQueue("direct://" + exchangeName1 + "/queue/queue"); + session1.createProducer(queue); + + //close the session to ensure any previous commands were fully processed by + //the broker before observing their effect + session1.close(); + + //verify the exchange was declared + String exchangeObjectName = _jmxUtils.getExchangeObjectName("test", exchangeName1); + assertTrue("exchange should exist", _jmxUtils.doesManagedObjectExist(exchangeObjectName)); + + //Now disable the implicit exchange declares and try again + setSystemProperty(ClientProperties.QPID_DECLARE_EXCHANGES_PROP_NAME, "false"); + + Session session2 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + String exchangeName2 = getTestQueueName() + "2"; + + Queue queue2 = session2.createQueue("direct://" + exchangeName2 + "/queue/queue"); + session2.createProducer(queue2); + + //close the session to ensure any previous commands were fully processed by + //the broker before observing their effect + session2.close(); + + //verify the exchange was not declared + String exchangeObjectName2 = _jmxUtils.getExchangeObjectName("test", exchangeName2); + assertFalse("exchange should not exist", _jmxUtils.doesManagedObjectExist(exchangeObjectName2)); + } + + public void testQueueNotBoundDuringConsumerCreation() throws Exception + { + setSystemProperty(ClientProperties.QPID_BIND_QUEUES_PROP_NAME, "false"); + setSystemProperty(ClientProperties.VERIFY_QUEUE_ON_SEND, "true"); + + Connection connection = getConnection(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Queue queue = session.createQueue(getTestQueueName()); + session.createConsumer(queue); + + try + { + session.createProducer(queue).send(session.createMessage()); + fail("JMSException should be thrown as the queue does not exist"); + } + catch (InvalidDestinationException ide) + { + //PASS + } + } + private void checkExceptionErrorCode(JMSException original, AMQConstant code) + { + Exception linked = original.getLinkedException(); + assertNotNull("Linked exception should have been set", linked); + assertTrue("Linked exception should be an AMQException", linked instanceof AMQException); + assertEquals("Error code should be " + code.getCode(), code, ((AMQException) linked).getErrorCode()); + } + + /* + * Tests to validate that the custom exchanges declared by the client during + * consumer and producer creation have the expected properties. + */ + + public void testPropertiesOfCustomExchangeDeclaredDuringProducerCreation() throws Exception + { + implTestPropertiesOfCustomExchange(true, false); + } + + public void testPropertiesOfCustomExchangeDeclaredDuringConsumerCreation() throws Exception + { + implTestPropertiesOfCustomExchange(false, true); + } + + private void implTestPropertiesOfCustomExchange(boolean createProducer, boolean createConsumer) throws Exception + { + Connection connection = getConnection(); + + Session session1 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + String exchangeName1 = getTestQueueName() + "1"; + String queueName1 = getTestQueueName() + "1"; + + Queue queue = session1.createQueue("direct://" + exchangeName1 + "/" + queueName1 + "/" + queueName1 + "?" + BindingURL.OPTION_EXCHANGE_AUTODELETE + "='true'"); + if(createProducer) + { + session1.createProducer(queue); + } + + if(createConsumer) + { + session1.createConsumer(queue); + } + session1.close(); + + //verify the exchange was declared to expectation + verifyDeclaredExchange(exchangeName1, true, false); + + Session session2 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + String exchangeName2 = getTestQueueName() + "2"; + String queueName2 = getTestQueueName() + "2"; + + Queue queue2 = session2.createQueue("direct://" + exchangeName2 + "/" + queueName2 + "/" + queueName2 + "?" + BindingURL.OPTION_EXCHANGE_DURABLE + "='true'"); + if(createProducer) + { + session2.createProducer(queue2); + } + + if(createConsumer) + { + session2.createConsumer(queue2); + } + session2.close(); + + //verify the exchange was declared to expectation + verifyDeclaredExchange(exchangeName2, false, true); + } + + private void verifyDeclaredExchange(String exchangeName, boolean isAutoDelete, boolean isDurable) throws IOException + { + String exchangeObjectName = _jmxUtils.getExchangeObjectName("test", exchangeName); + assertTrue("exchange should exist", _jmxUtils.doesManagedObjectExist(exchangeObjectName)); + ManagedExchange exchange = _jmxUtils.getManagedExchange(exchangeName); + assertEquals(isAutoDelete, exchange.isAutoDelete()); + assertEquals(isDurable,exchange.isDurable()); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/MaxDeliveryCountTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/MaxDeliveryCountTest.java new file mode 100644 index 0000000000..5e1e38106a --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/MaxDeliveryCountTest.java @@ -0,0 +1,660 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.client; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +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.TextMessage; +import javax.jms.Topic; + +import org.apache.log4j.Logger; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.RejectBehaviour; +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.server.virtualhost.AbstractVirtualHost; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +/** + * Test that the MaxRedelivery feature works as expected, allowing the client to reject + * messages during rollback/recover whilst specifying they not be requeued if delivery + * to an application has been attempted a specified number of times. + * + * General approach: specify a set of messages which will cause the test client to then + * deliberately rollback/recover the session after consuming, and monitor that they are + * re-delivered the specified number of times before the client rejects them without requeue + * and then verify that they are not subsequently redelivered. + * + * Additionally, the queue used in the test is configured for DLQ'ing, and the test verifies + * that the messages rejected without requeue are then present on the appropriate DLQ. + */ +public class MaxDeliveryCountTest extends QpidBrokerTestCase +{ + private static final Logger _logger = Logger.getLogger(MaxDeliveryCountTest.class); + private boolean _failed; + private String _failMsg; + private static final int MSG_COUNT = 15; + private static final int MAX_DELIVERY_COUNT = 2; + private CountDownLatch _awaitCompletion; + + /** index numbers of messages to be redelivered */ + private final List _redeliverMsgs = Arrays.asList(1, 2, 5, 14); + + public void setUp() throws Exception + { + //enable DLQ/maximumDeliveryCount support for all queues at the vhost level + + TestBrokerConfiguration brokerConfiguration = getBrokerConfiguration(); + setTestSystemProperty("queue.deadLetterQueueEnabled","true"); + setTestSystemProperty("queue.maximumDeliveryAttempts", String.valueOf(MAX_DELIVERY_COUNT)); + + //Ensure management is on + brokerConfiguration.addJmxManagementConfiguration(); + + // Set client-side flag to allow the server to determine if messages + // dead-lettered or requeued. + if (!isBroker010()) + { + setTestClientSystemProperty(ClientProperties.REJECT_BEHAVIOUR_PROP_NAME, RejectBehaviour.SERVER.toString()); + } + super.setUp(); + + boolean durableSub = isDurSubTest(); + + //declare the test queue + Connection consumerConnection = getConnection(); + Session consumerSession = consumerConnection.createSession(false,Session.AUTO_ACKNOWLEDGE); + Destination destination = getDestination(consumerSession, durableSub); + if(durableSub) + { + consumerSession.createDurableSubscriber((Topic)destination, getName()).close(); + } + else + { + consumerSession.createConsumer(destination).close(); + } + + consumerConnection.close(); + + //Create Producer put some messages on the queue + Connection producerConnection = getConnection(); + producerConnection.start(); + Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer producer = producerSession.createProducer(getDestination(producerSession, durableSub)); + + for (int count = 1; count <= MSG_COUNT; count++) + { + Message msg = producerSession.createTextMessage(generateContent(count)); + msg.setIntProperty("count", count); + producer.send(msg); + } + + producerConnection.close(); + + _failed = false; + _awaitCompletion = new CountDownLatch(1); + } + + private Destination getDestination(Session consumerSession, boolean durableSub) throws JMSException + { + if(durableSub) + { + return consumerSession.createTopic(getTestQueueName()); + } + else + { + return consumerSession.createQueue(getTestQueueName()); + } + } + + private String generateContent(int count) + { + return "Message " + count + " content."; + } + + /** + * Test that Max Redelivery is enforced when using onMessage() on a + * Client-Ack session. + */ + public void testAsynchronousClientAckSession() throws Exception + { + doTest(Session.CLIENT_ACKNOWLEDGE, _redeliverMsgs, false, false); + } + + /** + * Test that Max Redelivery is enforced when using onMessage() on a + * transacted session. + */ + public void testAsynchronousTransactedSession() throws Exception + { + doTest(Session.SESSION_TRANSACTED, _redeliverMsgs, false, false); + } + + /** + * Test that Max Redelivery is enforced when using onMessage() on an + * Auto-Ack session. + */ + public void testAsynchronousAutoAckSession() throws Exception + { + doTest(Session.AUTO_ACKNOWLEDGE, _redeliverMsgs, false, false); + } + + /** + * Test that Max Redelivery is enforced when using onMessage() on a + * Dups-OK session. + */ + public void testAsynchronousDupsOkSession() throws Exception + { + doTest(Session.DUPS_OK_ACKNOWLEDGE, _redeliverMsgs, false, false); + } + + /** + * Test that Max Redelivery is enforced when using recieve() on a + * Client-Ack session. + */ + public void testSynchronousClientAckSession() throws Exception + { + doTest(Session.CLIENT_ACKNOWLEDGE, _redeliverMsgs, true, false); + } + + /** + * Test that Max Redelivery is enforced when using recieve() on a + * transacted session. + */ + public void testSynchronousTransactedSession() throws Exception + { + doTest(Session.SESSION_TRANSACTED, _redeliverMsgs, true, false); + } + + public void testDurableSubscription() throws Exception + { + doTest(Session.SESSION_TRANSACTED, _redeliverMsgs, false, true); + } + + public void testWhenBrokerIsRestartedAfterEnqeuingMessages() throws Exception + { + restartBroker(); + + doTest(Session.SESSION_TRANSACTED, _redeliverMsgs, true, false); + } + + private void doTest(final int deliveryMode, final List redeliverMsgs, final boolean synchronous, final boolean durableSub) throws Exception + { + final Connection clientConnection = getConnection(); + + final boolean transacted = deliveryMode == Session.SESSION_TRANSACTED ? true : false; + final Session clientSession = clientConnection.createSession(transacted, deliveryMode); + + MessageConsumer consumer; + Destination dest = getDestination(clientSession, durableSub); + AMQQueue checkQueue; + if(durableSub) + { + consumer = clientSession.createDurableSubscriber((Topic)dest, getName()); + checkQueue = new AMQQueue("amq.topic", "clientid" + ":" + getName()); + } + else + { + consumer = clientSession.createConsumer(dest); + checkQueue = (AMQQueue) dest; + } + + assertEquals("The queue should have " + MSG_COUNT + " msgs at start", + MSG_COUNT, ((AMQSession) clientSession).getQueueDepth(checkQueue)); + + clientConnection.start(); + + int expectedDeliveries = MSG_COUNT + ((MAX_DELIVERY_COUNT -1) * redeliverMsgs.size()); + + if(synchronous) + { + doSynchronousTest(clientSession, consumer, clientSession.getAcknowledgeMode(), + MAX_DELIVERY_COUNT, expectedDeliveries, redeliverMsgs); + } + else + { + addMessageListener(clientSession, consumer, clientSession.getAcknowledgeMode(), + MAX_DELIVERY_COUNT, expectedDeliveries, redeliverMsgs); + + try + { + if (!_awaitCompletion.await(20, TimeUnit.SECONDS)) + { + fail("Test did not complete in 20 seconds."); + } + } + catch (InterruptedException e) + { + fail("Unable to wait for test completion"); + throw e; + } + + if(_failed) + { + fail(_failMsg); + } + } + consumer.close(); + + //check the source queue is now empty + assertEquals("The queue should have 0 msgs left", 0, ((AMQSession) clientSession).getQueueDepth(checkQueue, true)); + + //check the DLQ has the required number of rejected-without-requeue messages + verifyDLQdepth(redeliverMsgs.size(), clientSession, durableSub); + + if(isBrokerStorePersistent()) + { + //restart the broker to verify persistence of the DLQ and the messages on it + clientConnection.close(); + + restartBroker(); + + final Connection clientConnection2 = getConnection(); + clientConnection2.start(); + + //verify the messages on the DLQ + verifyDLQcontent(clientConnection2, redeliverMsgs, getTestQueueName(), durableSub); + clientConnection2.close(); + } + else + { + + //verify the messages on the DLQ + verifyDLQcontent(clientConnection, redeliverMsgs, getTestQueueName(), durableSub); + clientConnection.close(); + } + + } + + private void verifyDLQdepth(int expected, Session clientSession, boolean durableSub) throws AMQException + { + AMQDestination checkQueueDLQ; + if(durableSub) + { + checkQueueDLQ = new AMQQueue("amq.topic", "clientid" + ":" + getName() + AbstractVirtualHost.DEFAULT_DLQ_NAME_SUFFIX); + } + else + { + checkQueueDLQ = new AMQQueue("amq.direct", getTestQueueName() + AbstractVirtualHost.DEFAULT_DLQ_NAME_SUFFIX); + } + + assertEquals("The DLQ should have " + expected + " msgs on it", expected, + ((AMQSession) clientSession).getQueueDepth(checkQueueDLQ, true)); + } + + private void verifyDLQcontent(Connection clientConnection, List redeliverMsgs, String destName, boolean durableSub) throws JMSException + { + Session clientSession = clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageConsumer consumer; + if(durableSub) + { + consumer = clientSession.createConsumer(clientSession.createQueue("clientid:" +getName() + AbstractVirtualHost.DEFAULT_DLQ_NAME_SUFFIX)); + } + else + { + consumer = clientSession.createConsumer( + clientSession.createQueue(destName + AbstractVirtualHost.DEFAULT_DLQ_NAME_SUFFIX)); + } + + //keep track of the message we expect to still be on the DLQ + List outstandingMessages = new ArrayList(redeliverMsgs); + int numMsg = outstandingMessages.size(); + + for(int i = 0; i < numMsg; i++) + { + Message message = consumer.receive(250); + + assertNotNull("failed to consume expected message " + i + " from DLQ", message); + assertTrue("message " + i + " was the wrong type", message instanceof TextMessage); + + //using Integer here to allow removing the value from the list, using int + //would instead result in removal of the element at that index + Integer msgId = message.getIntProperty("count"); + + TextMessage txt = (TextMessage) message; + _logger.info("Received message " + msgId + " at " + i + " from the DLQ: " + txt.getText()); + + assertTrue("message " + i + " was not one of those which should have been on the DLQ", + redeliverMsgs.contains(msgId)); + assertTrue("message " + i + " was not one of those expected to still be on the DLQ", + outstandingMessages.contains(msgId)); + assertEquals("Message " + i + " content was not as expected", generateContent(msgId), txt.getText()); + + //remove from the list of outstanding msgs + outstandingMessages.remove(msgId); + } + + if(outstandingMessages.size() > 0) + { + String failures = ""; + for(Integer msg : outstandingMessages) + { + failures = failures.concat(msg + " "); + } + fail("some DLQ'd messages were not found on the DLQ: " + failures); + } + } + + private void addMessageListener(final Session session, final MessageConsumer consumer, final int deliveryMode, final int maxDeliveryCount, + final int expectedTotalNumberOfDeliveries, final List redeliverMsgs) throws JMSException + { + if(deliveryMode == org.apache.qpid.jms.Session.NO_ACKNOWLEDGE + || deliveryMode == org.apache.qpid.jms.Session.PRE_ACKNOWLEDGE) + { + failAsyncTest("Max Delivery feature is not supported with this acknowledgement mode" + + "when using asynchronous message delivery."); + } + + consumer.setMessageListener(new MessageListener() + { + private int _deliveryAttempts = 0; //number of times given message(s) have been seen + private int _numMsgsToBeRedelivered = 0; //number of messages to rollback/recover + private int _totalNumDeliveries = 0; + private int _expectedMessage = 1; + + public void onMessage(Message message) + { + if(_failed || _awaitCompletion.getCount() == 0L) + { + //don't process anything else + return; + } + + _totalNumDeliveries++; + + if (message == null) + { + failAsyncTest("Should not get null messages"); + return; + } + + try + { + int msgId = message.getIntProperty("count"); + + _logger.info("Received message: " + msgId); + + //check the message is the one we expected + if(_expectedMessage != msgId) + { + failAsyncTest("Expected message " + _expectedMessage + " , got message " + msgId); + return; + } + + _expectedMessage++; + + //keep track of the overall deliveries to ensure we don't see more than expected + if(_totalNumDeliveries > expectedTotalNumberOfDeliveries) + { + failAsyncTest("Expected total of " + expectedTotalNumberOfDeliveries + + " message deliveries, reached " + _totalNumDeliveries); + } + + //check if this message is one chosen to be rolled back / recovered + if(redeliverMsgs.contains(msgId)) + { + _numMsgsToBeRedelivered++; + + //check if next message is going to be rolled back / recovered too + if(redeliverMsgs.contains(msgId +1)) + { + switch(deliveryMode) + { + case Session.SESSION_TRANSACTED: + //skip on to next message immediately + return; + case Session.CLIENT_ACKNOWLEDGE: + //skip on to next message immediately + return; + case Session.DUPS_OK_ACKNOWLEDGE: + //fall through + case Session.AUTO_ACKNOWLEDGE: + //must recover session now or onMessage will ack, so + //just fall through the if + break; + } + } + + _deliveryAttempts++; //increment count of times the current rolled back/recovered message(s) have been seen + + _logger.debug("ROLLBACK/RECOVER"); + switch(deliveryMode) + { + case Session.SESSION_TRANSACTED: + session.rollback(); + break; + case Session.CLIENT_ACKNOWLEDGE: + //fall through + case Session.DUPS_OK_ACKNOWLEDGE: + //fall through + case Session.AUTO_ACKNOWLEDGE: + session.recover(); + break; + } + + if( _deliveryAttempts >= maxDeliveryCount) + { + //the client should have rejected the latest messages upon then + //above recover/rollback, adjust counts to compensate + _deliveryAttempts = 0; + } + else + { + //the message(s) should be redelivered, adjust expected message + _expectedMessage -= _numMsgsToBeRedelivered; + } + _logger.debug("XXX _expectedMessage: " + _expectedMessage + " _deliveryAttempts : " + _deliveryAttempts + " _numMsgsToBeRedelivered=" + _numMsgsToBeRedelivered); + //reset count of messages expected to be redelivered + _numMsgsToBeRedelivered = 0; + } + else + { + //consume the message + switch(deliveryMode) + { + case Session.SESSION_TRANSACTED: + session.commit(); + break; + case Session.CLIENT_ACKNOWLEDGE: + message.acknowledge(); + break; + case Session.DUPS_OK_ACKNOWLEDGE: + //fall-through + case Session.AUTO_ACKNOWLEDGE: + //do nothing, onMessage will ack on exit. + break; + } + } + + if (msgId == MSG_COUNT) + { + //if this is the last message let the test complete. + if (expectedTotalNumberOfDeliveries == _totalNumDeliveries) + { + _awaitCompletion.countDown(); + } + else + { + failAsyncTest("Last message received, but we have not had the " + + "expected number of total delivieres. Received " + _totalNumDeliveries + " Expecting : " + expectedTotalNumberOfDeliveries); + } + } + } + catch (JMSException e) + { + failAsyncTest(e.getMessage()); + } + } + }); + } + + private void failAsyncTest(String msg) + { + _logger.error("Failing test because: " + msg); + _failMsg = msg; + _failed = true; + _awaitCompletion.countDown(); + } + + private void doSynchronousTest(final Session session, final MessageConsumer consumer, final int deliveryMode, final int maxDeliveryCount, + final int expectedTotalNumberOfDeliveries, final List redeliverMsgs) throws JMSException, AMQException, InterruptedException + { + if(deliveryMode == Session.AUTO_ACKNOWLEDGE + || deliveryMode == Session.DUPS_OK_ACKNOWLEDGE + || deliveryMode == org.apache.qpid.jms.Session.PRE_ACKNOWLEDGE + || deliveryMode == org.apache.qpid.jms.Session.NO_ACKNOWLEDGE) + { + fail("Max Delivery feature is not supported with this acknowledgement mode" + + "when using synchronous message delivery."); + } + + int _deliveryAttempts = 0; //number of times given message(s) have been seen + int _numMsgsToBeRedelivered = 0; //number of messages to rollback/recover + int _totalNumDeliveries = 0; + int _expectedMessage = 1; + + while(!_failed) + { + Message message = consumer.receive(1000); + + _totalNumDeliveries++; + + if (message == null) + { + fail("Should not get null messages"); + return; + } + + try + { + int msgId = message.getIntProperty("count"); + + _logger.info("Received message: " + msgId); + + //check the message is the one we expected + assertEquals("Unexpected message.", _expectedMessage, msgId); + + _expectedMessage++; + + //keep track of the overall deliveries to ensure we don't see more than expected + assertTrue("Exceeded expected total number of deliveries.", + _totalNumDeliveries <= expectedTotalNumberOfDeliveries ); + + //check if this message is one chosen to be rolled back / recovered + if(redeliverMsgs.contains(msgId)) + { + //keep track of the number of messages we will have redelivered + //upon rollback/recover + _numMsgsToBeRedelivered++; + + if(redeliverMsgs.contains(msgId +1)) + { + //next message is going to be rolled back / recovered too. + //skip ahead to it + continue; + } + + _deliveryAttempts++; //increment count of times the current rolled back/recovered message(s) have been seen + + switch(deliveryMode) + { + case Session.SESSION_TRANSACTED: + session.rollback(); + break; + case Session.CLIENT_ACKNOWLEDGE: + session.recover(); + + //sleep then do a synchronous op to give the broker + //time to resend all the messages + Thread.sleep(500); + ((AMQSession) session).sync(); + break; + } + + if( _deliveryAttempts >= maxDeliveryCount) + { + //the client should have rejected the latest messages upon then + //above recover/rollback, adjust counts to compensate + _deliveryAttempts = 0; + } + else + { + //the message(s) should be redelivered, adjust expected message + _expectedMessage -= _numMsgsToBeRedelivered; + } + + //As we just rolled back / recovered, we must reset the + //count of messages expected to be redelivered + _numMsgsToBeRedelivered = 0; + } + else + { + //consume the message + switch(deliveryMode) + { + case Session.SESSION_TRANSACTED: + session.commit(); + break; + case Session.CLIENT_ACKNOWLEDGE: + message.acknowledge(); + break; + } + } + + if (msgId == MSG_COUNT) + { + //if this is the last message let the test complete. + assertTrue("Last message received, but we have not had the " + + "expected number of total delivieres", + expectedTotalNumberOfDeliveries == _totalNumDeliveries); + + break; + } + } + catch (JMSException e) + { + fail(e.getMessage()); + } + } + } + + private boolean isDurSubTest() + { + return getTestQueueName().contains("DurableSubscription"); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/QueueSessionFactoryTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/QueueSessionFactoryTest.java new file mode 100644 index 0000000000..370e44b3d5 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/QueueSessionFactoryTest.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.test.unit.client; + +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.QueueConnection; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicSession; + +/** + * Ensures that queue specific session factory method {@link QueueConnection#createQueueSession()} create sessions + * of type {@link QueueSession} and that those sessions correctly restrict the available JMS operations + * operations to exclude those applicable to only topics. + * + * @see TopicSessionFactoryTest + */ +public class QueueSessionFactoryTest extends QpidBrokerTestCase +{ + public void testQueueSessionIsNotATopicSession() throws Exception + { + QueueSession queueSession = getQueueSession(); + assertFalse(queueSession instanceof TopicSession); + } + + public void testQueueSessionCannotCreateTemporaryTopics() throws Exception + { + QueueSession queueSession = getQueueSession(); + try + { + queueSession.createTemporaryTopic(); + fail("expected exception did not occur"); + } + catch (javax.jms.IllegalStateException s) + { + // PASS + assertEquals("Cannot call createTemporaryTopic from QueueSession", s.getMessage()); + } + } + + public void testQueueSessionCannotCreateTopics() throws Exception + { + QueueSession queueSession = getQueueSession(); + try + { + queueSession.createTopic("abc"); + fail("expected exception did not occur"); + } + catch (javax.jms.IllegalStateException s) + { + // PASS + assertEquals("Cannot call createTopic from QueueSession", s.getMessage()); + } + } + + public void testQueueSessionCannotCreateDurableSubscriber() throws Exception + { + QueueSession queueSession = getQueueSession(); + Topic topic = getTestTopic(); + + try + { + queueSession.createDurableSubscriber(topic, "abc"); + fail("expected exception did not occur"); + } + catch (javax.jms.IllegalStateException s) + { + // PASS + assertEquals("Cannot call createDurableSubscriber from QueueSession", s.getMessage()); + } + } + + public void testQueueSessionCannoutUnsubscribe() throws Exception + { + QueueSession queueSession = getQueueSession(); + try + { + queueSession.unsubscribe("abc"); + fail("expected exception did not occur"); + } + catch (javax.jms.IllegalStateException s) + { + // PASS + assertEquals("Cannot call unsubscribe from QueueSession", s.getMessage()); + } + } + + private QueueSession getQueueSession() throws Exception + { + QueueConnection queueConnection = (QueueConnection)getConnection(); + return queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/TopicSessionFactoryTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/TopicSessionFactoryTest.java new file mode 100644 index 0000000000..ce15d452ab --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/TopicSessionFactoryTest.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.test.unit.client; + +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Queue; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.TopicConnection; +import javax.jms.TopicSession; + +/** + * Ensures that topic specific session factory method {@link TopicConnection#createTopicSession()} create sessions + * of type {@link TopicSession} and that those sessions correctly restrict the available JMS operations + * operations to exclude those applicable to only queues. + * + * @see QueueSessionFactoryTest + */ +public class TopicSessionFactoryTest extends QpidBrokerTestCase +{ + public void testTopicSessionIsNotAQueueSession() throws Exception + { + TopicSession topicSession = getTopicSession(); + assertFalse(topicSession instanceof QueueSession); + } + + public void testTopicSessionCannotCreateCreateBrowser() throws Exception + { + TopicSession topicSession = getTopicSession(); + Queue queue = getTestQueue(); + try + { + topicSession.createBrowser(queue); + fail("expected exception did not occur"); + } + catch (javax.jms.IllegalStateException s) + { + // PASS + assertEquals("Cannot call createBrowser from TopicSession", s.getMessage()); + } + } + + public void testTopicSessionCannotCreateQueues() throws Exception + { + TopicSession topicSession = getTopicSession(); + try + { + topicSession.createQueue("abc"); + fail("expected exception did not occur"); + } + catch (javax.jms.IllegalStateException s) + { + // PASS + assertEquals("Cannot call createQueue from TopicSession", s.getMessage()); + } + } + + public void testTopicSessionCannotCreateTemporaryQueues() throws Exception + { + TopicSession topicSession = getTopicSession(); + try + { + topicSession.createTemporaryQueue(); + fail("expected exception did not occur"); + } + catch (javax.jms.IllegalStateException s) + { + // PASS + assertEquals("Cannot call createTemporaryQueue from TopicSession", s.getMessage()); + } + } + + private TopicSession getTopicSession() throws Exception + { + TopicConnection topicConnection = (TopicConnection)getConnection(); + return topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/channelclose/CloseWithBlockingReceiveTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/channelclose/CloseWithBlockingReceiveTest.java new file mode 100644 index 0000000000..58f1bfe372 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/channelclose/CloseWithBlockingReceiveTest.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.test.unit.client.channelclose; + +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.Session; + +/** + * @author Apache Software Foundation + */ +public class CloseWithBlockingReceiveTest extends QpidBrokerTestCase +{ + + + public void testReceiveReturnsNull() throws Exception + { + final Connection connection = getConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Destination destination = session.createQueue(getTestQueueName()); + MessageConsumer consumer = session.createConsumer(destination); + connection.start(); + + Runnable r = new Runnable() + { + + public void run() + { + try + { + Thread.sleep(1000); + connection.close(); + } + catch (Exception e) + { + } + } + }; + long startTime = System.currentTimeMillis(); + Thread thread = new Thread(r); + thread.start(); + try + { + consumer.receive(10000); + assertTrue(System.currentTimeMillis() - startTime < 10000); + } + finally + { + thread.join(); + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/BrokerClosesClientConnectionTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/BrokerClosesClientConnectionTest.java new file mode 100644 index 0000000000..4a92728d82 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/BrokerClosesClientConnectionTest.java @@ -0,0 +1,215 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.client.connection; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.naming.NamingException; +import org.apache.qpid.AMQConnectionClosedException; +import org.apache.qpid.AMQDisconnectedException; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.transport.ConnectionException; + +import javax.jms.Connection; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Session; + +/** + * Tests the behaviour of the client when the Broker terminates client connection + * by the Broker being shutdown gracefully or otherwise. + * + * @see ManagedConnectionMBeanTest + */ +public class BrokerClosesClientConnectionTest extends QpidBrokerTestCase +{ + private Connection _connection; + private boolean _isExternalBroker; + private final RecordingExceptionListener _recordingExceptionListener = new RecordingExceptionListener(); + private Session _session; + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + _connection = getConnection(); + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _connection.setExceptionListener(_recordingExceptionListener); + + _isExternalBroker = isExternalBroker(); + } + + public void testClientCloseOnNormalBrokerShutdown() throws Exception + { + final Class expectedLinkedException = isBroker010() ? ConnectionException.class : AMQConnectionClosedException.class; + + assertConnectionOpen(); + + stopBroker(); + + JMSException exception = _recordingExceptionListener.awaitException(10000); + assertConnectionCloseWasReported(exception, expectedLinkedException); + assertConnectionClosed(); + + ensureCanCloseWithoutException(); + } + + public void testClientCloseOnBrokerKill() throws Exception + { + final Class expectedLinkedException = isBroker010() ? ConnectionException.class : AMQDisconnectedException.class; + + if (!_isExternalBroker) + { + return; + } + + assertConnectionOpen(); + + killBroker(); + + JMSException exception = _recordingExceptionListener.awaitException(10000); + assertConnectionCloseWasReported(exception, expectedLinkedException); + assertConnectionClosed(); + + ensureCanCloseWithoutException(); + } + + private void ensureCanCloseWithoutException() + { + try + { + _connection.close(); + } + catch (JMSException e) + { + fail("Connection should close without exception" + e.getMessage()); + } + } + + private void assertConnectionCloseWasReported(JMSException exception, Class linkedExceptionClass) + { + assertNotNull("Broker shutdown should be reported to the client via the ExceptionListener", exception); + assertNotNull("JMXException should have linked exception", exception.getLinkedException()); + + assertEquals("Unexpected linked exception", linkedExceptionClass, exception.getLinkedException().getClass()); + } + + private void assertConnectionClosed() + { + assertTrue("Connection should be marked as closed", ((AMQConnection)_connection).isClosed()); + } + + private void assertConnectionOpen() + { + assertFalse("Connection should not be marked as closed", ((AMQConnection)_connection).isClosed()); + } + + private final class RecordingExceptionListener implements ExceptionListener + { + private final CountDownLatch _exceptionReceivedLatch = new CountDownLatch(1); + private volatile JMSException _exception; + + @Override + public void onException(JMSException exception) + { + _exception = exception; + } + + public JMSException awaitException(long timeoutInMillis) throws InterruptedException + { + _exceptionReceivedLatch.await(timeoutInMillis, TimeUnit.MILLISECONDS); + return _exception; + } + } + + + private class Listener implements MessageListener + { + int _messageCount; + + @Override + public synchronized void onMessage(Message message) + { + _messageCount++; + } + + public synchronized int getCount() + { + return _messageCount; + } + } + + public void testNoDeliveryAfterBrokerClose() throws JMSException, NamingException, InterruptedException + { + + Listener listener = new Listener(); + + Session session = _connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer1 = session.createConsumer(getTestQueue()); + consumer1.setMessageListener(listener); + + MessageProducer producer = _session.createProducer(getTestQueue()); + producer.send(_session.createTextMessage("test message")); + + _connection.start(); + + + synchronized (listener) + { + long currentTime = System.currentTimeMillis(); + long until = currentTime + 2000l; + while(listener.getCount() == 0 && currentTime < until) + { + listener.wait(until - currentTime); + currentTime = System.currentTimeMillis(); + } + } + assertEquals(1, listener.getCount()); + + Connection connection2 = getConnection(); + Session session2 = connection2.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer2 = session2.createConsumer(getTestQueue()); + consumer2.setMessageListener(listener); + connection2.start(); + + + Connection connection3 = getConnection(); + Session session3 = connection3.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageConsumer consumer3 = session3.createConsumer(getTestQueue()); + consumer3.setMessageListener(listener); + connection3.start(); + + assertEquals(1, listener.getCount()); + + stopBroker(); + + assertEquals(1, listener.getCount()); + + + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionFactoryTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionFactoryTest.java new file mode 100644 index 0000000000..bf1fbbf1a3 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionFactoryTest.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.test.unit.client.connection; + +import javax.jms.Connection; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQConnectionFactory; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class ConnectionFactoryTest extends QpidBrokerTestCase +{ + + /** + * The username & password specified should not override the default + * specified in the URL. + */ + public void testCreateConnectionWithUsernamePassword() throws Exception + { + + String brokerUrl = getBroker().toString(); + String URL = "amqp://guest:guest@clientID/test?brokerlist='" + brokerUrl + "'"; + AMQConnectionFactory factory = new AMQConnectionFactory(URL); + + AMQConnection con = (AMQConnection)factory.createConnection(); + assertEquals("Usernames used is different from the one in URL","guest",con.getConnectionURL().getUsername()); + assertEquals("Password used is different from the one in URL","guest",con.getConnectionURL().getPassword()); + + try + { + AMQConnection con2 = (AMQConnection)factory.createConnection("user","pass"); + assertEquals("Usernames used is different from the one in URL","user",con2.getConnectionURL().getUsername()); + assertEquals("Password used is different from the one in URL","pass",con2.getConnectionURL().getPassword()); + } + catch(Exception e) + { + // ignore + } + + AMQConnection con3 = (AMQConnection)factory.createConnection(); + assertEquals("Usernames used is different from the one in URL","guest",con3.getConnectionURL().getUsername()); + assertEquals("Password used is different from the one in URL","guest",con3.getConnectionURL().getPassword()); + } + + /** + * Verifies that a connection can be made using an instance of AMQConnectionFactory created with the + * default constructor and provided with the connection url via setter. + */ + public void testCreatingConnectionWithInstanceMadeUsingDefaultConstructor() throws Exception + { + String broker = getBroker().toString(); + String url = "amqp://guest:guest@clientID/test?brokerlist='" + broker + "'"; + + AMQConnectionFactory factory = new AMQConnectionFactory(); + factory.setConnectionURLString(url); + + Connection con = factory.createConnection(); + con.close(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.java new file mode 100644 index 0000000000..6ea1582bb8 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.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.test.unit.client.connection; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +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.TextMessage; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class ConnectionStartTest extends QpidBrokerTestCase +{ + + private String _broker = "vm://:1"; + + private AMQConnection _connection; + private Session _consumerSess; + private MessageConsumer _consumer; + + protected void setUp() throws Exception + { + super.setUp(); + try + { + + + AMQConnection pubCon = (AMQConnection) getConnection("guest", "guest"); + + AMQQueue queue = new AMQQueue(pubCon,"ConnectionStartTest"); + + Session pubSess = pubCon.createSession(false, AMQSession.AUTO_ACKNOWLEDGE); + + MessageProducer pub = pubSess.createProducer(queue); + + _connection = (AMQConnection) getConnection("guest", "guest"); + + _consumerSess = _connection.createSession(false, AMQSession.AUTO_ACKNOWLEDGE); + + _consumer = _consumerSess.createConsumer(queue); + + //publish after queue is created to ensure it can be routed as expected + pub.send(pubSess.createTextMessage("Initial Message")); + + pubCon.close(); + + } + catch (Exception e) + { + _logger.error("Connection to " + _broker + " should succeed.", e); + fail("Connection to " + _broker + " should succeed. Reason: " + e); + } + } + + protected void tearDown() throws Exception + { + _connection.close(); + super.tearDown(); + } + + public void testSimpleReceiveConnection() + { + try + { + assertTrue("Connection should not be started", !_connection.started()); + //Note that this next line will start the dispatcher in the session + // should really not be called before _connection start + //assertTrue("There should not be messages waiting for the consumer", _consumer.receiveNoWait() == null); + _connection.start(); + assertTrue("There should be messages waiting for the consumer", _consumer.receive(10*1000) != null); + assertTrue("Connection should be started", _connection.started()); + + } + catch (JMSException e) + { + fail("An error occured during test because:" + e); + } + + } + + public void testMessageListenerConnection() + { + final CountDownLatch _gotMessage = new CountDownLatch(1); + + try + { + assertTrue("Connection should not be started", !_connection.started()); + _consumer.setMessageListener(new MessageListener() + { + public void onMessage(Message message) + { + try + { + assertTrue("Connection should be started", _connection.started()); + assertEquals("Mesage Received", "Initial Message", ((TextMessage) message).getText()); + _gotMessage.countDown(); + } + catch (JMSException e) + { + fail("Couldn't get message text because:" + e.getCause()); + } + } + }); + + assertTrue("Connection should not be started", !_connection.started()); + _connection.start(); + assertTrue("Connection should be started", _connection.started()); + + try + { + assertTrue("Listener was never called", _gotMessage.await(10 * 1000, TimeUnit.MILLISECONDS)); + } + catch (InterruptedException e) + { + fail("Timed out awaiting message via onMessage"); + } + + } + catch (JMSException e) + { + fail("Failed because:" + e.getCause()); + } + + } + + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(ConnectionStartTest.class); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java new file mode 100644 index 0000000000..ed03e83292 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java @@ -0,0 +1,378 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.client.connection; + +import javax.jms.Connection; +import javax.jms.QueueSession; +import javax.jms.TopicSession; + +import org.apache.qpid.AMQConnectionFailureException; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQUnresolvedAddressException; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQConnectionURL; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.jms.BrokerDetails; +import org.apache.qpid.jms.ConnectionURL; +import org.apache.qpid.jms.Session; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class ConnectionTest extends QpidBrokerTestCase +{ + + private String _broker_NotRunning = "tcp://localhost:" + findFreePort(); + + private String _broker_BadDNS = "tcp://hg3sgaaw4lgihjs"; + + public void testSimpleConnection() throws Exception + { + AMQConnection conn = null; + try + { + conn = new AMQConnection(getBroker().toString(), "guest", "guest", "fred", "test"); + } + catch (Exception e) + { + fail("Connection to " + getBroker() + " should succeed. Reason: " + e); + } + finally + { + if(conn != null) + { + conn.close(); + } + } + } + + public void testDefaultExchanges() throws Exception + { + AMQConnection conn = null; + try + { + BrokerDetails broker = getBroker(); + broker.setProperty(BrokerDetails.OPTIONS_RETRY, "1"); + ConnectionURL url = new AMQConnectionURL("amqp://guest:guest@clientid/test?brokerlist='" + + broker + + "'&defaultQueueExchange='test.direct'" + + "&defaultTopicExchange='test.topic'" + + "&temporaryQueueExchange='tmp.direct'" + + "&temporaryTopicExchange='tmp.topic'"); + + System.err.println(url.toString()); + conn = new AMQConnection(url); + + + AMQSession sess = (AMQSession) conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + + sess.declareExchange(new AMQShortString("test.direct"), + AMQShortString.valueOf(ExchangeDefaults.DIRECT_EXCHANGE_CLASS), false); + + sess.declareExchange(new AMQShortString("tmp.direct"), + AMQShortString.valueOf(ExchangeDefaults.DIRECT_EXCHANGE_CLASS), false); + + sess.declareExchange(new AMQShortString("tmp.topic"), + AMQShortString.valueOf(ExchangeDefaults.TOPIC_EXCHANGE_CLASS), false); + + sess.declareExchange(new AMQShortString("test.topic"), + AMQShortString.valueOf(ExchangeDefaults.TOPIC_EXCHANGE_CLASS), false); + + QueueSession queueSession = conn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + + AMQQueue queue = (AMQQueue) queueSession.createQueue("MyQueue"); + + assertEquals(queue.getExchangeName().toString(), "test.direct"); + + AMQQueue tempQueue = (AMQQueue) queueSession.createTemporaryQueue(); + + assertEquals(tempQueue.getExchangeName().toString(), "tmp.direct"); + + queueSession.close(); + + TopicSession topicSession = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + + AMQTopic topic = (AMQTopic) topicSession.createTopic("silly.topic"); + + assertEquals(topic.getExchangeName().toString(), "test.topic"); + + AMQTopic tempTopic = (AMQTopic) topicSession.createTemporaryTopic(); + + assertEquals(tempTopic.getExchangeName().toString(), "tmp.topic"); + + topicSession.close(); + + } + catch (Exception e) + { + fail("Connection to " + getBroker() + " should succeed. Reason: " + e); + } + finally + { + conn.close(); + } + } + + public void testPasswordFailureConnection() throws Exception + { + AMQConnection conn = null; + try + { + BrokerDetails broker = getBroker(); + broker.setProperty(BrokerDetails.OPTIONS_RETRY, "0"); + conn = new AMQConnection("amqp://guest:rubbishpassword@clientid/test?brokerlist='" + broker + "'"); + fail("Connection should not be established password is wrong."); + } + catch (AMQConnectionFailureException amqe) + { + assertNotNull("No cause set:" + amqe.getMessage(), amqe.getCause()); + assertTrue("Exception was wrong type", amqe.getCause() instanceof AMQException); + } + finally + { + if (conn != null) + { + conn.close(); + } + } + } + + public void testConnectionFailure() throws Exception + { + AMQConnection conn = null; + try + { + conn = new AMQConnection("amqp://guest:guest@clientid/testpath?brokerlist='" + _broker_NotRunning + "?retries='0''"); + fail("Connection should not be established"); + } + catch (AMQException amqe) + { + if (!(amqe instanceof AMQConnectionFailureException)) + { + fail("Correct exception not thrown. Excpected 'AMQConnectionException' got: " + amqe); + } + } + finally + { + if (conn != null) + { + conn.close(); + } + } + + } + + public void testUnresolvedHostFailure() throws Exception + { + AMQConnection conn = null; + try + { + conn = new AMQConnection("amqp://guest:guest@clientid/testpath?brokerlist='" + _broker_BadDNS + "?retries='0''"); + fail("Connection should not be established"); + } + catch (AMQException amqe) + { + if (!(amqe instanceof AMQUnresolvedAddressException)) + { + fail("Correct exception not thrown. Excpected 'AMQUnresolvedAddressException' got: " + amqe); + } + } + finally + { + if (conn != null) + { + conn.close(); + } + } + + } + + public void testUnresolvedVirtualHostFailure() throws Exception + { + AMQConnection conn = null; + try + { + BrokerDetails broker = getBroker(); + broker.setProperty(BrokerDetails.OPTIONS_RETRY, "0"); + conn = new AMQConnection("amqp://guest:guest@clientid/rubbishhost?brokerlist='" + broker + "'"); + fail("Connection should not be established"); + } + catch (AMQException amqe) + { + if (!(amqe instanceof AMQConnectionFailureException)) + { + fail("Correct exception not thrown. Excpected 'AMQConnectionFailureException' got: " + amqe); + } + } + finally + { + if (conn != null) + { + conn.close(); + } + } + } + + public void testClientIdCannotBeChanged() throws Exception + { + Connection connection = new AMQConnection(getBroker().toString(), "guest", "guest", + "fred", "test"); + try + { + connection.setClientID("someClientId"); + fail("No IllegalStateException thrown when resetting clientid"); + } + catch (javax.jms.IllegalStateException e) + { + // PASS + } + finally + { + if (connection != null) + { + connection.close(); + } + } + } + + public void testClientIdIsPopulatedAutomatically() throws Exception + { + Connection connection = new AMQConnection(getBroker().toString(), "guest", "guest", + null, "test"); + try + { + assertNotNull(connection.getClientID()); + } + finally + { + connection.close(); + } + connection.close(); + } + + public void testUnsupportedSASLMechanism() throws Exception + { + BrokerDetails broker = getBroker(); + broker.setProperty(BrokerDetails.OPTIONS_SASL_MECHS, "MY_MECH"); + + try + { + Connection connection = new AMQConnection(broker.toString(), "guest", "guest", + null, "test"); + connection.close(); + fail("The client should throw a ConnectionException stating the" + + " broker does not support the SASL mech specified by the client"); + } + catch (Exception e) + { + assertTrue("Unexpected exception message : " + e.getMessage(), + e.getMessage().contains("Client and broker have no SASL mechanisms in common.")); + assertTrue("Unexpected exception message : " + e.getMessage(), + e.getMessage().contains("Client restricted itself to : MY_MECH")); + + } + } + + /** + * Tests that when the same user connects twice with same clientid, the second connection + * fails if the clientid verification feature is enabled (which uses a dummy 0-10 Session + * with the clientid as its name to detect the previous usage of the clientid by the user) + */ + public void testClientIDVerificationForSameUser() throws Exception + { + setTestSystemProperty(ClientProperties.QPID_VERIFY_CLIENT_ID, "true"); + + BrokerDetails broker = getBroker(); + try + { + Connection con = new AMQConnection(broker.toString(), "guest", "guest", + "client_id", "test"); + + Connection con2 = new AMQConnection(broker.toString(), "guest", "guest", + "client_id", "test"); + + fail("The client should throw a ConnectionException stating the" + + " client ID is not unique"); + } + catch (Exception e) + { + assertTrue("Incorrect exception thrown: " + e.getMessage(), + e.getMessage().contains("ClientID must be unique")); + } + } + + /** + * Tests that when different users connects with same clientid, the second connection + * succeeds even though the clientid verification feature is enabled (which uses a dummy + * 0-10 Session with the clientid as its name; these are only verified unique on a + * per-principal basis) + */ + public void testClientIDVerificationForDifferentUsers() throws Exception + { + setTestSystemProperty(ClientProperties.QPID_VERIFY_CLIENT_ID, "true"); + + BrokerDetails broker = getBroker(); + try + { + Connection con = new AMQConnection(broker.toString(), "guest", "guest", + "client_id", "test"); + + Connection con2 = new AMQConnection(broker.toString(), "admin", "admin", + "client_id", "test"); + } + catch (Exception e) + { + fail("Unexpected exception thrown, client id was not unique but usernames were different! " + e.getMessage()); + } + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(ConnectionTest.class); + } + + public void testExceptionWhenUserPassIsRequired() throws Exception + { + AMQConnection conn = null; + try + { + BrokerDetails broker = getBroker(); + String url = "amqp:///test?brokerlist='" + broker + "?sasl_mechs='PLAIN%2520CRAM-MD5''"; + conn = new AMQConnection(url); + conn.close(); + fail("Exception should be thrown as user name and password is required"); + } + catch (Exception e) + { + if (!e.getMessage().contains("Username and Password is required for the selected mechanism")) + { + if (conn != null && !conn.isClosed()) + { + conn.close(); + } + fail("Incorrect Exception thrown! The exception thrown is : " + e.getMessage()); + } + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/ExceptionListenerTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/ExceptionListenerTest.java new file mode 100644 index 0000000000..141de1e5a8 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/connection/ExceptionListenerTest.java @@ -0,0 +1,244 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.test.unit.client.connection; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.Connection; +import javax.jms.ExceptionListener; +import javax.jms.IllegalStateException; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.qpid.AMQConnectionClosedException; +import org.apache.qpid.client.AMQNoRouteException; +import org.apache.qpid.jms.ConnectionURL; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.transport.ConnectionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ExceptionListenerTest extends QpidBrokerTestCase +{ + private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionListenerTest.class); + + private volatile Throwable _lastExceptionListenerException = null; + + public void testExceptionListenerHearsBrokerShutdown() throws Exception + { + final CountDownLatch exceptionReceivedLatch = new CountDownLatch(1); + final AtomicInteger exceptionCounter = new AtomicInteger(0); + final ExceptionListener listener = new ExceptionListener() + { + public void onException(JMSException exception) + { + exceptionCounter.incrementAndGet(); + _lastExceptionListenerException = exception; + exceptionReceivedLatch.countDown(); + } + }; + + Connection connection = getConnection(); + connection.setExceptionListener(listener); + + stopBroker(); + + exceptionReceivedLatch.await(10, TimeUnit.SECONDS); + + assertEquals("Unexpected number of exceptions received", 1, exceptionCounter.intValue()); + LOGGER.debug("exception was", _lastExceptionListenerException); + assertNotNull("Exception should have cause", _lastExceptionListenerException.getCause()); + Class expectedExceptionClass = isBroker010() ? ConnectionException.class : AMQConnectionClosedException.class; + assertEquals(expectedExceptionClass, _lastExceptionListenerException.getCause().getClass()); + } + + /** + * It is reasonable for an application to perform Connection#close within the exception + * listener. This test verifies that close is allowed, and proceeds without generating + * further exceptions. + */ + public void testExceptionListenerClosesConnection_IsAllowed() throws Exception + { + final CountDownLatch exceptionReceivedLatch = new CountDownLatch(1); + final Connection connection = getConnection(); + final ExceptionListener listener = new ExceptionListener() + { + public void onException(JMSException exception) + { + try + { + connection.close(); + // PASS + } + catch (Throwable t) + { + _lastExceptionListenerException = t; + } + finally + { + exceptionReceivedLatch.countDown(); + } + } + }; + connection.setExceptionListener(listener); + + + stopBroker(); + + boolean exceptionReceived = exceptionReceivedLatch.await(10, TimeUnit.SECONDS); + assertTrue("Exception listener did not hear exception within timeout", exceptionReceived); + assertNull("Connection#close() should not have thrown exception", _lastExceptionListenerException); + } + + /** + * Spring's SingleConnectionFactory installs an ExceptionListener that calls stop() + * and ignores any IllegalStateException that result. This test serves to test this + * scenario. + */ + public void testExceptionListenerStopsConnection_ThrowsIllegalStateException() throws Exception + { + final CountDownLatch exceptionReceivedLatch = new CountDownLatch(1); + final Connection connection = getConnection(); + final ExceptionListener listener = new ExceptionListener() + { + public void onException(JMSException exception) + { + try + { + connection.stop(); + fail("Exception not thrown"); + } + catch (IllegalStateException ise) + { + // PASS + } + catch (Throwable t) + { + _lastExceptionListenerException = t; + } + finally + { + exceptionReceivedLatch.countDown(); + } + } + }; + connection.setExceptionListener(listener); + + stopBroker(); + + boolean exceptionReceived = exceptionReceivedLatch.await(10, TimeUnit.SECONDS); + assertTrue("Exception listener did not hear exception within timeout", exceptionReceived); + assertNull("Connection#stop() should not have thrown unexpected exception", _lastExceptionListenerException); + } + + /** + * This test reproduces a deadlock that was the subject of a support call. A Spring based + * application was using SingleConnectionFactory. It installed an ExceptionListener that + * stops and closes the connection in response to any exception. On receipt of a message + * the application would create a new session then send a response message (within onMessage). + * It appears that a misconfiguration in the application meant that some of these messages + * were bounced (no-route). Bounces are treated like connection exceptions and are passed + * back to the application via the ExceptionListener. The deadlock occurred between the + * ExceptionListener's call to stop() and the MessageListener's attempt to create a new + * session. + */ + public void testExceptionListenerConnectionStopDeadlock() throws Exception + { + Queue messageQueue = getTestQueue(); + + Map options = new HashMap(); + options.put(ConnectionURL.OPTIONS_CLOSE_WHEN_NO_ROUTE, Boolean.toString(false)); + + final Connection connection = getConnectionWithOptions(options); + + Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + session.createConsumer(messageQueue).close(); // Create queue by side-effect + + // Put 10 messages onto messageQueue + sendMessage(session, messageQueue, 10); + + // Install an exception listener that stops/closes the connection on receipt of 2nd AMQNoRouteException. + // (Triggering on the 2nd (rather than 1st) seems to increase the probability that the test ends in deadlock, + // at least on my machine). + final CountDownLatch exceptionReceivedLatch = new CountDownLatch(2); + final ExceptionListener listener = new ExceptionListener() + { + public void onException(JMSException exception) + { + try + { + assertNotNull("JMS Exception must have cause", exception.getCause() ); + assertEquals("JMS Exception is of wrong type", AMQNoRouteException.class, exception.getCause().getClass()); + exceptionReceivedLatch.countDown(); + if (exceptionReceivedLatch.getCount() == 0) + { + connection.stop(); // ** Deadlock + connection.close(); + } + } + catch (Throwable t) + { + _lastExceptionListenerException = t; + } + } + }; + connection.setExceptionListener(listener); + + // Create a message listener that receives from testQueue and tries to forward them to unknown queue (thus + // provoking AMQNoRouteException exceptions to be delivered to the ExceptionListener). + final Queue unknownQueue = session.createQueue(getTestQueueName() + "_unknown");; + MessageListener redirectingMessageListener = new MessageListener() + { + @Override + public void onMessage(Message msg) + { + try + { + Session mlSession = connection.createSession(true, Session.SESSION_TRANSACTED); // ** Deadlock + mlSession.createProducer(unknownQueue).send(msg); + mlSession.commit(); + } + catch (JMSException je) + { + // Connection is closed by the listener, so exceptions here are expected. + LOGGER.debug("Expected exception - message listener got exception", je); + } + } + }; + + MessageConsumer consumer = session.createConsumer(messageQueue); + consumer.setMessageListener(redirectingMessageListener); + connection.start(); + + // Await the 2nd exception + boolean exceptionReceived = exceptionReceivedLatch.await(10, TimeUnit.SECONDS); + assertTrue("Exception listener did not hear exception within timeout", exceptionReceived); + assertNull("Exception listener should not have had experienced exception", _lastExceptionListenerException); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/message/ObjectMessageTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/message/ObjectMessageTest.java new file mode 100644 index 0000000000..99dc5ff216 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/message/ObjectMessageTest.java @@ -0,0 +1,334 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.client.message; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.ObjectMessage; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; + +public class ObjectMessageTest extends QpidBrokerTestCase implements MessageListener +{ + private static final Logger _logger = LoggerFactory.getLogger(ObjectMessageTest.class); + + private AMQConnection connection; + private AMQDestination destination; + private AMQSession session; + private MessageProducer producer; + private Serializable[] data; + private volatile boolean waiting; + private int received; + private final ArrayList items = new ArrayList(); + + private String _broker = "vm://:1"; + + protected void setUp() throws Exception + { + super.setUp(); + connection = (AMQConnection) getConnection("guest", "guest"); + destination = new AMQQueue(connection, randomize("LatencyTest"), true); + session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); + + // set up a consumer + session.createConsumer(destination).setMessageListener(this); + connection.start(); + + // create a publisher + producer = session.createProducer(destination, false, false); + A a1 = new A(1, "A"); + A a2 = new A(2, "a"); + B b = new B(1, "B"); + C c = new C(); + c.put("A1", a1); + c.put("a2", a2); + c.put("B", b); + c.put("String", "String"); + + data = new Serializable[] { a1, a2, b, c, "Hello World!", new Integer(1001) }; + } + + protected void tearDown() throws Exception + { + close(); + super.tearDown(); + } + + public ObjectMessageTest() + { } + + ObjectMessageTest(String broker) throws Exception + { + _broker = broker; + } + + public void testSendAndReceive() throws Exception + { + try + { + send(); + waitUntilReceived(data.length); + check(); + _logger.info("All " + data.length + " items matched."); + } + catch (Exception e) + { + _logger.error("This Test should succeed but failed", e); + fail("This Test should succeed but failed due to: " + e); + } + } + + public void testSetObjectPropertyForString() throws Exception + { + String testStringProperty = "TestStringProperty"; + ObjectMessage msg = session.createObjectMessage(data[0]); + msg.setObjectProperty("TestStringProperty", testStringProperty); + assertEquals(testStringProperty, msg.getObjectProperty("TestStringProperty")); + } + + public void testSetObjectPropertyForBoolean() throws Exception + { + ObjectMessage msg = session.createObjectMessage(data[0]); + msg.setObjectProperty("TestBooleanProperty", Boolean.TRUE); + assertEquals(Boolean.TRUE, msg.getObjectProperty("TestBooleanProperty")); + } + + public void testSetObjectPropertyForByte() throws Exception + { + ObjectMessage msg = session.createObjectMessage(data[0]); + msg.setObjectProperty("TestByteProperty", Byte.MAX_VALUE); + assertEquals(Byte.MAX_VALUE, msg.getObjectProperty("TestByteProperty")); + } + + public void testSetObjectPropertyForShort() throws Exception + { + ObjectMessage msg = session.createObjectMessage(data[0]); + msg.setObjectProperty("TestShortProperty", Short.MAX_VALUE); + assertEquals(Short.MAX_VALUE, msg.getObjectProperty("TestShortProperty")); + } + + public void testSetObjectPropertyForInteger() throws Exception + { + ObjectMessage msg = session.createObjectMessage(data[0]); + msg.setObjectProperty("TestIntegerProperty", Integer.MAX_VALUE); + assertEquals(Integer.MAX_VALUE, msg.getObjectProperty("TestIntegerProperty")); + } + + public void testSetObjectPropertyForDouble() throws Exception + { + ObjectMessage msg = session.createObjectMessage(data[0]); + msg.setObjectProperty("TestDoubleProperty", Double.MAX_VALUE); + assertEquals(Double.MAX_VALUE, msg.getObjectProperty("TestDoubleProperty")); + } + + public void testSetObjectPropertyForFloat() throws Exception + { + ObjectMessage msg = session.createObjectMessage(data[0]); + msg.setObjectProperty("TestFloatProperty", Float.MAX_VALUE); + assertEquals(Float.MAX_VALUE, msg.getObjectProperty("TestFloatProperty")); + } + + public void testSetObjectPropertyForByteArray() throws Exception + { + byte[] array = { 1, 2, 3, 4, 5 }; + ObjectMessage msg = session.createObjectMessage(data[0]); + msg.setObjectProperty("TestByteArrayProperty", array); + assertTrue(Arrays.equals(array, (byte[]) msg.getObjectProperty("TestByteArrayProperty"))); + } + + public void testSetObjectForNull() throws Exception + { + ObjectMessage msg = session.createObjectMessage(); + msg.setObject(null); + assertNull(msg.getObject()); + } + + private void send() throws Exception + { + for (int i = 0; i < data.length; i++) + { + ObjectMessage msg; + if ((i % 2) == 0) + { + msg = session.createObjectMessage(data[i]); + } + else + { + msg = session.createObjectMessage(); + msg.setObject(data[i]); + } + + producer.send(msg); + } + } + + public void check() throws Exception + { + Object[] actual = (Object[]) items.toArray(); + if (actual.length != data.length) + { + throw new Exception("Expected " + data.length + " objects, got " + actual.length); + } + + for (int i = 0; i < data.length; i++) + { + if (actual[i] instanceof Exception) + { + throw new Exception("Error on receive of " + data[i], ((Exception) actual[i])); + } + + if (actual[i] == null) + { + throw new Exception("Expected " + data[i] + " got null"); + } + + if (!data[i].equals(actual[i])) + { + throw new Exception("Expected " + data[i] + " got " + actual[i]); + } + } + } + + private void close() throws Exception + { + session.close(); + connection.close(); + } + + private synchronized void waitUntilReceived(int count) throws InterruptedException + { + waiting = true; + while (received < count) + { + wait(); + } + + waiting = false; + } + + public void onMessage(Message message) + { + + try + { + if (message instanceof ObjectMessage) + { + items.add(((ObjectMessage) message).getObject()); + } + else + { + _logger.error("ERROR: Got " + message.getClass().getName() + " not ObjectMessage"); + items.add(message); + } + } + catch (JMSException e) + { + _logger.error("Error getting object from message", e); + items.add(e); + } + + synchronized (this) + { + received++; + notify(); + } + } + + public static void main(String[] argv) throws Exception + { + String broker = (argv.length > 0) ? argv[0] : "vm://:1"; + if ("-help".equals(broker)) + { + System.out.println("Usage: "); + } + + new ObjectMessageTest(broker).testSendAndReceive(); + } + + private static class A implements Serializable + { + private String sValue; + private int iValue; + + A(int i, String s) + { + sValue = s; + iValue = i; + } + + public int hashCode() + { + return iValue; + } + + public boolean equals(Object o) + { + return (o instanceof A) && equals((A) o); + } + + protected boolean equals(A a) + { + return areEqual(a.sValue, sValue) && (a.iValue == iValue); + } + } + + private static class B extends A + { + private long time; + + B(int i, String s) + { + super(i, s); + time = System.currentTimeMillis(); + } + + protected boolean equals(A a) + { + return super.equals(a) && (a instanceof B) && (time == ((B) a).time); + } + } + + private static class C extends HashMap implements Serializable + { } + + private static boolean areEqual(Object a, Object b) + { + return (a == null) ? (b == null) : a.equals(b); + } + + private static String randomize(String in) + { + return in + System.currentTimeMillis(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.java new file mode 100644 index 0000000000..3ffa73b9b7 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.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.test.unit.client.protocol; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.security.Principal; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.protocol.AMQProtocolHandler; +import org.apache.qpid.client.protocol.AMQProtocolSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.transport.Sender; +import org.apache.qpid.transport.network.NetworkConnection; + +public class AMQProtocolSessionTest extends QpidBrokerTestCase +{ + private static class TestProtocolSession extends AMQProtocolSession + { + + public TestProtocolSession(AMQProtocolHandler protocolHandler, AMQConnection connection) + { + super(protocolHandler,connection); + } + + public TestNetworkConnection getNetworkConnection() + { + return (TestNetworkConnection) getProtocolHandler().getNetworkConnection(); + } + + public AMQShortString genQueueName() + { + return generateQueueName(); + } + } + + private TestProtocolSession _testSession; + + protected void setUp() throws Exception + { + super.setUp(); + + AMQConnection con = (AMQConnection) getConnection("guest", "guest"); + AMQProtocolHandler protocolHandler = new AMQProtocolHandler(con); + protocolHandler.setNetworkConnection(new TestNetworkConnection()); + + //don't care about the values set here apart from the dummy IoSession + _testSession = new TestProtocolSession(protocolHandler , con); + } + + public void testTemporaryQueueWildcard() throws UnknownHostException + { + checkTempQueueName(new InetSocketAddress(1234), "tmp_0_0_0_0_0_0_0_0_1234_1"); + } + + public void testTemporaryQueueLocalhostAddr() throws UnknownHostException + { + checkTempQueueName(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 1234), "tmp_127_0_0_1_1234_1"); + } + + public void testTemporaryQueueLocalhostName() throws UnknownHostException + { + checkTempQueueName(new InetSocketAddress(InetAddress.getByName("localhost"), 1234), "tmp_localhost_127_0_0_1_1234_1"); + } + + public void testTemporaryQueueInet4() throws UnknownHostException + { + checkTempQueueName(new InetSocketAddress(InetAddress.getByName("192.168.1.2"), 1234), "tmp_192_168_1_2_1234_1"); + } + + public void testTemporaryQueueInet6() throws UnknownHostException + { + checkTempQueueName(new InetSocketAddress(InetAddress.getByName("1080:0:0:0:8:800:200C:417A"), 1234), "tmp_1080_0_0_0_8_800_200c_417a_1234_1"); + } + + private void checkTempQueueName(SocketAddress address, String queueName) + { + _testSession.getNetworkConnection().setLocalAddress(address); + assertEquals("Wrong queue name", queueName, _testSession.genQueueName().asString()); + } + + private static class TestNetworkConnection implements NetworkConnection + { + private String _remoteHost = "127.0.0.1"; + private String _localHost = "127.0.0.1"; + private int _port = 1; + private SocketAddress _localAddress = null; + private final Sender _sender; + + public TestNetworkConnection() + { + _sender = new Sender() + { + + public void setIdleTimeout(int i) + { + + } + + public void send(ByteBuffer msg) + { + + } + + public void flush() + { + + } + + public void close() + { + + } + }; + } + + @Override + public SocketAddress getLocalAddress() + { + return (_localAddress != null) ? _localAddress : new InetSocketAddress(_localHost, _port); + } + + @Override + public SocketAddress getRemoteAddress() + { + return new InetSocketAddress(_remoteHost, _port); + } + + @Override + public void setMaxReadIdle(int idleTime) + { + } + + @Override + public Principal getPeerPrincipal() + { + return null; + } + + @Override + public int getMaxReadIdle() + { + return 0; + } + + @Override + public int getMaxWriteIdle() + { + return 0; + } + + @Override + public void setMaxWriteIdle(int idleTime) + { + } + + @Override + public void close() + { + } + + public void setLocalAddress(SocketAddress address) + { + _localAddress = address; + } + + public Sender getSender() + { + return _sender; + } + + public void start() + { + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java new file mode 100644 index 0000000000..41ab35f233 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java @@ -0,0 +1,166 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.test.unit.client.temporaryqueue; + +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TemporaryQueue; +import javax.jms.TextMessage; + +/** + * Tests the behaviour of {@link TemporaryQueue}. + */ +public class TemporaryQueueTest extends QpidBrokerTestCase +{ + /** + * Tests the basic produce/consume behaviour of a temporary queue. + */ + public void testMessageDeliveryUsingTemporaryQueue() throws Exception + { + final Connection conn = getConnection(); + final Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final TemporaryQueue queue = session.createTemporaryQueue(); + assertNotNull(queue); + final MessageProducer producer = session.createProducer(queue); + final MessageConsumer consumer = session.createConsumer(queue); + conn.start(); + producer.send(session.createTextMessage("hello")); + TextMessage tm = (TextMessage) consumer.receive(2000); + assertNotNull("Message not received", tm); + assertEquals("hello", tm.getText()); + } + + /** + * Tests that a temporary queue cannot be used by another {@link Session}. + */ + public void testUseFromAnotherSessionProhibited() throws Exception + { + final Connection conn = getConnection(); + final Session session1 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Session session2 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final TemporaryQueue queue = session1.createTemporaryQueue(); + assertNotNull(queue); + + try + { + session2.createConsumer(queue); + fail("Expected a JMSException when subscribing to a temporary queue created on a different session"); + } + catch (JMSException je) + { + //pass + assertEquals("Cannot consume from a temporary destination created on another session", je.getMessage()); + } + } + + /** + * Tests that the client is able to explicitly delete a temporary queue using + * {@link TemporaryQueue#delete()} and is prevented from deleting one that + * still has consumers. + * + * Note: Under < 0-10 {@link TemporaryQueue#delete()} only marks the queue as deleted + * on the client. 0-10 causes the queue to be deleted from the Broker. + */ + public void testExplictTemporaryQueueDeletion() throws Exception + { + final Connection conn = getConnection(); + final Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final AMQSession amqSession = (AMQSession)session; // Required to observe the queue binding on the Broker + final TemporaryQueue queue = session.createTemporaryQueue(); + assertNotNull(queue); + final MessageConsumer consumer = session.createConsumer(queue); + conn.start(); + + assertTrue("Queue should be bound", amqSession.isQueueBound((AMQDestination)queue)); + + try + { + queue.delete(); + fail("Expected JMSException : should not be able to delete while there are active consumers"); + } + catch (JMSException je) + { + //pass + assertEquals("Temporary Queue has consumers so cannot be deleted", je.getMessage()); + } + consumer.close(); + + // Now deletion should succeed. + queue.delete(); + + try + { + session.createConsumer(queue); + fail("Exception not thrown"); + } + catch (JMSException je) + { + //pass + assertEquals("Cannot consume from a deleted destination", je.getMessage()); + } + + if (isBroker010()) + { + assertFalse("Queue should no longer be bound", amqSession.isQueueBound((AMQDestination)queue)); + } + } + + /** + * Tests that a temporary queue remains available for reuse even after its initial + * consumer has disconnected. + * + * This test would fail under < 0-10 as their temporary queues are deleted automatically + * (broker side) after the last consumer disconnects (so message2 would be lost). For this + * reason this test is excluded from those profiles. + */ + public void testTemporaryQueueReused() throws Exception + { + final Connection conn = getConnection(); + final Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final TemporaryQueue queue = session.createTemporaryQueue(); + assertNotNull(queue); + + final MessageProducer producer1 = session.createProducer(queue); + final MessageConsumer consumer1 = session.createConsumer(queue); + conn.start(); + producer1.send(session.createTextMessage("message1")); + producer1.send(session.createTextMessage("message2")); + TextMessage tm = (TextMessage) consumer1.receive(2000); + assertNotNull("Message not received by first consumer", tm); + assertEquals("message1", tm.getText()); + consumer1.close(); + + final MessageConsumer consumer2 = session.createConsumer(queue); + conn.start(); + tm = (TextMessage) consumer2.receive(2000); + assertNotNull("Message not received by second consumer", tm); + assertEquals("message2", tm.getText()); + consumer2.close(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/close/JavaServerCloseRaceConditionTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/close/JavaServerCloseRaceConditionTest.java new file mode 100644 index 0000000000..b43fe35a09 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/close/JavaServerCloseRaceConditionTest.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.test.unit.close; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQSession_0_8; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.ExchangeDeclareBody; +import org.apache.qpid.framing.ExchangeDeclareOkBody; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Session; + +/** QPID-1809 + * + * Race condition on error handling and close logic. + * + * See most often with SimpleACLTest as this test is the expects the server to + * shut the connection/channels. This sort of testing is not performed by many, + * if any, of the other system tests. + * + * The problem is that we have two threads + * + * MainThread Exception(Mina)Thread + * | | + * Performs | + * ACtion | + * | Receives Server + * | Close + * Blocks for | + * Response | + * | Starts To Notify + * | client + * | | + * | <----- Notify Main Thread + * Notification | + * wakes client | + * | | + * Client then | + * processes Error. | + * | | + * Potentially Attempting Close Channel/Connection + * Connection Close + * + * The two threads both attempt to close the connection but the main thread does + * so assuming that the connection is open and valid. + * + * The Exception thread must modify the connection so that no furter syncWait + * commands are performed. + * + * This test sends an ExchangeDeclare that is Asynchronous and will fail and + * so cause a ChannelClose error but we perform a syncWait so that we can be + * sure to test that the BlockingWaiter is correctly awoken. + * + */ +public class JavaServerCloseRaceConditionTest extends QpidBrokerTestCase +{ + private static final String EXCHANGE_NAME = "NewExchangeNametoFailLookup"; + + public void test() throws Exception + { + + AMQConnection connection = (AMQConnection) getConnection(); + + AMQSession_0_8 session = (AMQSession_0_8) connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // Set no wait true so that we block the connection + // Also set a different exchange class string so the attempt to declare + // the exchange causes an exchange. + ExchangeDeclareBody body = session.getMethodRegistry().createExchangeDeclareBody(session.getTicket(), new AMQShortString(EXCHANGE_NAME), null, + true, false, false, false, true, null); + + AMQFrame exchangeDeclare = body.generateFrame(session.getChannelId()); + + try + { + // block our thread so that can times out + connection.getProtocolHandler().syncWrite(exchangeDeclare, ExchangeDeclareOkBody.class); + } + catch (Exception e) + { + assertTrue("Exception should say the exchange is not known.", e.getMessage().contains("Unknown exchange: " + EXCHANGE_NAME)); + } + + try + { + // Depending on if the notification thread has closed the connection + // or not we may get an exception here when we attempt to close the + // connection. If we do get one then it should be the same as above + // an AMQAuthenticationException. + connection.close(); + } + catch (Exception e) + { + assertTrue("Exception should say the exchange is not known.", e.getMessage().contains("Unknown exchange: " + EXCHANGE_NAME)); + } + + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/close/MessageConsumerCloseTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/close/MessageConsumerCloseTest.java new file mode 100644 index 0000000000..df32bd7858 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/close/MessageConsumerCloseTest.java @@ -0,0 +1,77 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.close; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.Session; + +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class MessageConsumerCloseTest extends QpidBrokerTestCase +{ + Exception _exception; + + public void testConsumerCloseAndSessionRollback() throws Exception + { + Connection connection = getConnection(); + final CountDownLatch receiveLatch = new CountDownLatch(1); + final Session session = connection.createSession(true, Session.SESSION_TRANSACTED); + Destination destination = getTestQueue(); + MessageConsumer consumer = session.createConsumer(destination); + sendMessage(session, destination, 2); + connection.start(); + consumer.setMessageListener(new MessageListener() + { + @Override + public void onMessage(Message message) + { + try + { + receiveLatch.countDown(); + session.rollback(); + } + catch (JMSException e) + { + _exception = e; + } + } + }); + boolean messageReceived = receiveLatch.await(1l, TimeUnit.SECONDS); + consumer.close(); + + assertNull("Exception occured on rollback:" + _exception, _exception); + assertTrue("Message is not received", messageReceived); + + consumer = session.createConsumer(destination); + Message message1 = consumer.receive(1000l); + assertNotNull("message1 is not received", message1); + Message message2 = consumer.receive(1000l); + assertNotNull("message2 is not received", message2); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java new file mode 100644 index 0000000000..5895d670a7 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java @@ -0,0 +1,371 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.test.unit.close; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.message.AbstractJMSMessage; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.test.utils.QpidClientConnection; +import org.apache.qpid.url.URLSyntaxException; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Queue; +import javax.jms.Session; +import java.util.concurrent.atomic.AtomicInteger; + +public class MessageRequeueTest extends QpidBrokerTestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(MessageRequeueTest.class); + + protected static AtomicInteger consumerIds = new AtomicInteger(0); + protected final Integer numTestMessages = 150; + + protected final int consumeTimeout = 3000; + + protected final String queue = "direct://amq.direct//message-requeue-test-queue"; + protected String payload = "Message:"; + + protected final String BROKER = "tcp://127.0.0.1:5672"; + private boolean testReception = true; + + private long[] receieved = new long[numTestMessages + 1]; + private boolean passed = false; + private QpidClientConnection conn; + + + protected void setUp() throws Exception + { + super.setUp(); + + conn = new QpidClientConnection(BROKER); + + conn.connect(); + // clear queue + conn.consume(queue, consumeTimeout); + // load test data + _logger.info("creating test data, " + numTestMessages + " messages"); + conn.put(queue, payload, numTestMessages); + // close this connection + conn.disconnect(); + } + + protected void tearDown() throws Exception + { + + if (!passed) // clean up + { + QpidClientConnection conn = new QpidClientConnection(BROKER); + + conn.connect(); + // clear queue + conn.consume(queue, consumeTimeout); + + conn.disconnect(); + } + + super.tearDown(); + } + + /** + * multiple consumers + * + * @throws javax.jms.JMSException if a JMS problem occurs + * @throws InterruptedException on timeout + */ + public void testDrain() throws Exception + { + QpidClientConnection conn = new QpidClientConnection(BROKER); + + conn.connect(); + + _logger.info("consuming queue " + queue); + Queue q = conn.getSession().createQueue(queue); + + final MessageConsumer consumer = conn.getSession().createConsumer(q); + int messagesReceived = 0; + + long[] messageLog = new long[numTestMessages + 1]; + + _logger.info("consuming..."); + Message msg = consumer.receive(1000); + while (msg != null) + { + messagesReceived++; + + long dt = ((AbstractJMSMessage) msg).getDeliveryTag(); + + int msgindex = msg.getIntProperty("index"); + if (messageLog[msgindex] != 0) + { + _logger.error("Received Message(" + msgindex + ":" + ((AbstractJMSMessage) msg).getDeliveryTag() + + ") more than once."); + } + + if (_logger.isInfoEnabled()) + { + _logger.info("Received Message(" + System.identityHashCode(msgindex) + ") " + "DT:" + dt + "IN:" + msgindex); + } + + if (dt == 0) + { + _logger.error("DT is zero for msg:" + msgindex); + } + + messageLog[msgindex] = dt; + + // get Next message + msg = consumer.receive(1000); + } + + _logger.info("consuming done."); + conn.getSession().commit(); + consumer.close(); + + int index = 0; + StringBuilder list = new StringBuilder(); + list.append("Failed to receive:"); + int failed = 0; + + _logger.info("consumed: " + messagesReceived); + + assertEquals("number of consumed messages does not match initial data", (int) numTestMessages, messagesReceived); + // with 0_10 we can have a delivery tag of 0 + if (!conn.isBroker010()) + { + for (long b : messageLog) + { + if ((b == 0) && (index != 0)) // delivery tag of zero shouldn't exist + { + _logger.error("Index: " + index + " was not received."); + list.append(" "); + list.append(index); + list.append(":"); + list.append(b); + failed++; + } + + index++; + } + + assertEquals(list.toString(), 0, failed); + } + + conn.disconnect(); + passed = true; + } + + /** multiple consumers + * Based on code subbmitted by client FT-304 + */ + public void testTwoCompetingConsumers() + { + Consumer c1 = new Consumer(); + Consumer c2 = new Consumer(); + Consumer c3 = new Consumer(); + Consumer c4 = new Consumer(); + + Thread t1 = new Thread(c1); + Thread t2 = new Thread(c2); + Thread t3 = new Thread(c3); + Thread t4 = new Thread(c4); + + t1.start(); + t2.start(); + t3.start(); + // t4.start(); + + try + { + t1.join(); + t2.join(); + t3.join(); + t4.join(); + } + catch (InterruptedException e) + { + fail("Unable to join to Consumer theads"); + } + + _logger.info("consumer 1 count is " + c1.getCount()); + _logger.info("consumer 2 count is " + c2.getCount()); + _logger.info("consumer 3 count is " + c3.getCount()); + _logger.info("consumer 4 count is " + c4.getCount()); + + Integer totalConsumed = c1.getCount() + c2.getCount() + c3.getCount() + c4.getCount(); + + // Check all messages were correctly delivered + int index = 0; + StringBuilder list = new StringBuilder(); + list.append("Failed to receive:"); + int failed = 0; + if (!conn.isBroker010()) + { + for (long b : receieved) + { + if ((b == 0) && (index != 0)) // delivery tag of zero shouldn't exist (and we don't have msg 0) + { + _logger.error("Index: " + index + " was not received."); + list.append(" "); + list.append(index); + list.append(":"); + list.append(b); + failed++; + } + + index++; + } + + assertEquals(list.toString() + "-" + numTestMessages + "-" + totalConsumed, 0, failed); + } + assertEquals("number of consumed messages does not match initial data", numTestMessages, totalConsumed); + passed = true; + } + + class Consumer implements Runnable + { + private Integer count = 0; + private Integer id; + + public Consumer() + { + id = consumerIds.addAndGet(1); + } + + public void run() + { + try + { + _logger.info("consumer-" + id + ": starting"); + QpidClientConnection conn = new QpidClientConnection(BROKER); + + conn.connect(); + + _logger.info("consumer-" + id + ": connected, consuming..."); + Message result; + do + { + result = conn.getNextMessage(queue, consumeTimeout); + if (result != null) + { + + long dt = ((AbstractJMSMessage) result).getDeliveryTag(); + + if (testReception) + { + int msgindex = result.getIntProperty("index"); + if (receieved[msgindex] != 0) + { + _logger.error("Received Message(" + msgindex + ":" + + ((AbstractJMSMessage) result).getDeliveryTag() + ") more than once."); + } + + if (_logger.isInfoEnabled()) + { + _logger.info("Received Message(" + System.identityHashCode(msgindex) + ") " + "DT:" + dt + + "IN:" + msgindex); + } + + if (dt == 0) + { + _logger.error("DT is zero for msg:" + msgindex); + } + + receieved[msgindex] = dt; + } + + count++; + if ((count % 100) == 0) + { + _logger.info("consumer-" + id + ": got " + result + ", new count is " + count); + } + } + } + while (result != null); + + _logger.info("consumer-" + id + ": complete"); + conn.disconnect(); + + } + catch (Exception e) + { + _logger.error("Consumer run error",e); + } + } + + public Integer getCount() + { + return count; + } + + public Integer getId() + { + return id; + } + } + + public void testRequeue() throws JMSException, AMQException, URLSyntaxException + { + int run = 0; + // while (run < 10) + { + run++; + + if (_logger.isInfoEnabled()) + { + _logger.info("testRequeue run " + run); + } + + String virtualHost = "/test"; + String brokerlist = BROKER; + String brokerUrl = "amqp://guest:guest@" + virtualHost + "?brokerlist='" + brokerlist + "'"; + QpidClientConnection qpc = new QpidClientConnection(BROKER); + qpc.connect(); + Connection conn = qpc. getConnection(); + + Session session = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Queue q = session.createQueue(queue); + + _logger.debug("Create Consumer"); + MessageConsumer consumer = session.createConsumer(q); + + conn.start(); + + _logger.debug("Receiving msg"); + Message msg = consumer.receive(2000); + + assertNotNull("Message should not be null", msg); + + // As we have not ack'd message will be requeued. + _logger.debug("Close Consumer"); + consumer.close(); + + _logger.debug("Close Connection"); + conn.close(); + } + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/close/TopicPublisherCloseTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/close/TopicPublisherCloseTest.java new file mode 100644 index 0000000000..957063b2e1 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/close/TopicPublisherCloseTest.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.test.unit.close; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicPublisher; +import javax.jms.TopicSession; + +/** + * @author Apache Software Foundation + */ +public class TopicPublisherCloseTest extends QpidBrokerTestCase +{ + + protected void setUp() throws Exception + { + super.setUp(); + } + + + protected void tearDown() throws Exception + { + super.tearDown(); + } + + public void testAllMethodsThrowAfterConnectionClose() throws Exception + { + // give external brokers a chance to start up + Thread.sleep(3000); + + AMQConnection connection = (AMQConnection) getConnection("guest", "guest"); + + Topic destination1 = new AMQTopic(connection, "t1"); + TopicSession session1 = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + TopicPublisher pub = session1.createPublisher(destination1); + connection.close(); + try + { + pub.getDeliveryMode(); + fail("Expected exception not thrown"); + } + catch (javax.jms.IllegalStateException e) + { + // PASS + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ct/DurableSubscriberTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ct/DurableSubscriberTest.java new file mode 100644 index 0000000000..c292c718bb --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/ct/DurableSubscriberTest.java @@ -0,0 +1,503 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.test.unit.ct; + +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.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.jms.TopicConnection; +import javax.jms.TopicConnectionFactory; +import javax.jms.TopicPublisher; +import javax.jms.TopicSession; +import javax.jms.TopicSubscriber; + +/** + * Crash Recovery tests for durable subscription + * + */ +public class DurableSubscriberTest extends QpidBrokerTestCase +{ + private final String _topicName = "durableSubscriberTopic"; + + /** + * test strategy: + * create and register a durable subscriber then close it + * create a publisher and send a persistant message followed by a non persistant message + * crash and restart the broker + * recreate the durable subscriber and check that only the first message is received + */ + public void testDurSubRestoredAfterNonPersistentMessageSent() throws Exception + { + if (isBrokerStorePersistent()) + { + TopicConnectionFactory factory = getConnectionFactory(); + Topic topic = (Topic) getInitialContext().lookup(_topicName); + //create and register a durable subscriber then close it + TopicConnection durConnection = factory.createTopicConnection("guest", "guest"); + TopicSession durSession = durConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber durSub1 = durSession.createDurableSubscriber(topic, "dursub"); + durConnection.start(); + durSub1.close(); + durSession.close(); + durConnection.stop(); + + //create a publisher and send a persistant message followed by a non persistant message + TopicConnection pubConnection = factory.createTopicConnection("guest", "guest"); + TopicSession pubSession = pubConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + TopicPublisher publisher = pubSession.createPublisher(topic); + Message message = pubSession.createMessage(); + message.setIntProperty("count", 1); + publisher.publish(message, javax.jms.DeliveryMode.PERSISTENT, javax.jms.Message.DEFAULT_PRIORITY, + javax.jms.Message.DEFAULT_TIME_TO_LIVE); + message.setIntProperty("count", 2); + publisher.publish(message, javax.jms.DeliveryMode.NON_PERSISTENT, javax.jms.Message.DEFAULT_PRIORITY, + javax.jms.Message.DEFAULT_TIME_TO_LIVE); + publisher.close(); + pubSession.close(); + //now stop the server + try + { + restartBroker(); + } + catch (Exception e) + { + _logger.error("problems restarting broker: " + e); + throw e; + } + //now recreate the durable subscriber and check the received messages + factory = getConnectionFactory(); + topic = (Topic) getInitialContext().lookup(_topicName); + TopicConnection durConnection2 = factory.createTopicConnection("guest", "guest"); + TopicSession durSession2 = durConnection2.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber durSub2 = durSession2.createDurableSubscriber(topic, "dursub"); + durConnection2.start(); + Message m1 = durSub2.receive(1000); + if (m1 == null) + { + assertTrue("testDurSubRestoredAfterNonPersistentMessageSent test failed. no message was returned", + false); + } + assertTrue("testDurSubRestoredAfterNonPersistentMessageSent test failed. Wrong message was returned.", + m1.getIntProperty("count") == 1); + durSession2.unsubscribe("dursub"); + durConnection2.close(); + } + } + + /** + * create and register a durable subscriber with a message selector and then close it + * crash the broker + * create a publisher and send 5 right messages and 5 wrong messages + * recreate the durable subscriber and check we receive the 5 expected messages + */ + public void testDurSubRestoresMessageSelector() throws Exception + { + if (isBrokerStorePersistent()) + { + TopicConnectionFactory factory = getConnectionFactory(); + Topic topic = (Topic) getInitialContext().lookup(_topicName); + //create and register a durable subscriber with a message selector and then close it + TopicConnection durConnection = factory.createTopicConnection("guest", "guest"); + TopicSession durSession = durConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber durSub1 = durSession.createDurableSubscriber(topic, "dursub", "testprop='true'", false); + durConnection.start(); + durSub1.close(); + durSession.close(); + durConnection.stop(); + //now stop the server + try + { + restartBroker(); + } + catch (Exception e) + { + _logger.error("problems restarting broker: " + e); + throw e; + } + topic = (Topic) getInitialContext().lookup(_topicName); + factory = getConnectionFactory(); + TopicConnection pubConnection = factory.createTopicConnection("guest", "guest"); + TopicSession pubSession = pubConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + TopicPublisher publisher = pubSession.createPublisher(topic); + for (int i = 0; i < 5; i++) + { + Message message = pubSession.createMessage(); + message.setStringProperty("testprop", "true"); + publisher.publish(message); + message = pubSession.createMessage(); + message.setStringProperty("testprop", "false"); + publisher.publish(message); + } + publisher.close(); + pubSession.close(); + + //now recreate the durable subscriber and check the received messages + TopicConnection durConnection2 = factory.createTopicConnection("guest", "guest"); + TopicSession durSession2 = durConnection2.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber durSub2 = durSession2.createDurableSubscriber(topic, "dursub", "testprop='true'", false); + durConnection2.start(); + for (int i = 0; i < 5; i++) + { + Message message = durSub2.receive(1000); + if (message == null) + { + assertTrue("testDurSubRestoresMessageSelector test failed. no message was returned", false); + } + else + { + assertTrue("testDurSubRestoresMessageSelector test failed. message selector not reset", + message.getStringProperty("testprop").equals("true")); + } + } + durSession2.unsubscribe("dursub"); + durConnection2.close(); + } + } + + /** + * create and register a durable subscriber without a message selector and then unsubscribe it + * create and register a durable subscriber with a message selector and then close it + * restart the broker + * send matching and non matching messages + * recreate and register the durable subscriber with a message selector + * verify only the matching messages are received + */ + public void testDurSubChangedToHaveSelectorThenRestart() throws Exception + { + if (! isBrokerStorePersistent()) + { + _logger.warn("Test skipped due to requirement of a persistent store"); + return; + } + + final String SUB_NAME=getTestQueueName(); + + TopicConnectionFactory factory = getConnectionFactory(); + Topic topic = (Topic) getInitialContext().lookup(_topicName); + + //create and register a durable subscriber then unsubscribe it + TopicConnection durConnection = factory.createTopicConnection("guest", "guest"); + TopicSession durSession = durConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber durSub1 = durSession.createDurableSubscriber(topic, SUB_NAME); + durConnection.start(); + durSub1.close(); + durSession.unsubscribe(SUB_NAME); + durSession.close(); + durConnection.close(); + + //create and register a durable subscriber with a message selector and then close it + TopicConnection durConnection2 = factory.createTopicConnection("guest", "guest"); + TopicSession durSession2 = durConnection2.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber durSub2 = durSession2.createDurableSubscriber(topic, SUB_NAME, "testprop='true'", false); + durConnection2.start(); + durSub2.close(); + durSession2.close(); + durConnection2.close(); + + //now restart the server + try + { + restartBroker(); + } + catch (Exception e) + { + _logger.error("problems restarting broker: " + e); + throw e; + } + + //send messages matching and not matching the selector + TopicConnection pubConnection = factory.createTopicConnection("guest", "guest"); + TopicSession pubSession = pubConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + TopicPublisher publisher = pubSession.createPublisher(topic); + for (int i = 0; i < 5; i++) + { + Message message = pubSession.createMessage(); + message.setStringProperty("testprop", "true"); + publisher.publish(message); + message = pubSession.createMessage(); + message.setStringProperty("testprop", "false"); + publisher.publish(message); + } + publisher.close(); + pubSession.close(); + + //now recreate the durable subscriber with selector to check there are no exceptions generated + //and then verify the messages are received correctly + TopicConnection durConnection3 = (TopicConnection) factory.createConnection("guest", "guest"); + TopicSession durSession3 = (TopicSession) durConnection3.createSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber durSub3 = durSession3.createDurableSubscriber(topic, SUB_NAME, "testprop='true'", false); + durConnection3.start(); + + for (int i = 0; i < 5; i++) + { + Message message = durSub3.receive(2000); + if (message == null) + { + fail("testDurSubChangedToHaveSelectorThenRestart test failed. Expected message " + i + " was not returned"); + } + else + { + assertTrue("testDurSubChangedToHaveSelectorThenRestart test failed. Got message not matching selector", + message.getStringProperty("testprop").equals("true")); + } + } + + durSub3.close(); + durSession3.unsubscribe(SUB_NAME); + durSession3.close(); + durConnection3.close(); + } + + + /** + * create and register a durable subscriber with a message selector and then unsubscribe it + * create and register a durable subscriber without a message selector and then close it + * restart the broker + * send matching and non matching messages + * recreate and register the durable subscriber without a message selector + * verify ALL the sent messages are received + */ + public void testDurSubChangedToNotHaveSelectorThenRestart() throws Exception + { + if (! isBrokerStorePersistent()) + { + _logger.warn("Test skipped due to requirement of a persistent store"); + return; + } + + final String SUB_NAME=getTestQueueName(); + + TopicConnectionFactory factory = getConnectionFactory(); + Topic topic = (Topic) getInitialContext().lookup(_topicName); + + //create and register a durable subscriber with selector then unsubscribe it + TopicConnection durConnection = factory.createTopicConnection("guest", "guest"); + TopicSession durSession = durConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber durSub1 = durSession.createDurableSubscriber(topic, SUB_NAME, "testprop='true'", false); + durConnection.start(); + durSub1.close(); + durSession.unsubscribe(SUB_NAME); + durSession.close(); + durConnection.close(); + + //create and register a durable subscriber without the message selector and then close it + TopicConnection durConnection2 = factory.createTopicConnection("guest", "guest"); + TopicSession durSession2 = durConnection2.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber durSub2 = durSession2.createDurableSubscriber(topic, SUB_NAME); + durConnection2.start(); + durSub2.close(); + durSession2.close(); + durConnection2.close(); + + //now restart the server + try + { + restartBroker(); + } + catch (Exception e) + { + _logger.error("problems restarting broker: " + e); + throw e; + } + + //send messages matching and not matching the original used selector + TopicConnection pubConnection = factory.createTopicConnection("guest", "guest"); + TopicSession pubSession = pubConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + TopicPublisher publisher = pubSession.createPublisher(topic); + for (int i = 1; i <= 5; i++) + { + Message message = pubSession.createMessage(); + message.setStringProperty("testprop", "true"); + publisher.publish(message); + message = pubSession.createMessage(); + message.setStringProperty("testprop", "false"); + publisher.publish(message); + } + publisher.close(); + pubSession.close(); + + //now recreate the durable subscriber without selector to check there are no exceptions generated + //then verify ALL messages sent are received + TopicConnection durConnection3 = (TopicConnection) factory.createConnection("guest", "guest"); + TopicSession durSession3 = (TopicSession) durConnection3.createSession(false, Session.AUTO_ACKNOWLEDGE); + TopicSubscriber durSub3 = durSession3.createDurableSubscriber(topic, SUB_NAME); + durConnection3.start(); + + for (int i = 1; i <= 10; i++) + { + Message message = durSub3.receive(2000); + if (message == null) + { + fail("testDurSubChangedToNotHaveSelectorThenRestart test failed. Expected message " + i + " was not received"); + } + } + + durSub3.close(); + durSession3.unsubscribe(SUB_NAME); + durSession3.close(); + durConnection3.close(); + } + + + public void testResubscribeWithChangedSelectorAndRestart() throws Exception + { + if (! isBrokerStorePersistent()) + { + _logger.warn("Test skipped due to requirement of a persistent store"); + return; + } + + Connection conn = getConnection(); + conn.start(); + Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + AMQTopic topic = new AMQTopic((AMQConnection) conn, "testResubscribeWithChangedSelectorAndRestart"); + MessageProducer producer = session.createProducer(topic); + + // Create durable subscriber that matches A + TopicSubscriber subA = session.createDurableSubscriber(topic, + "testResubscribeWithChangedSelectorAndRestart", + "Match = True", false); + + // Send 1 matching message and 1 non-matching message + TextMessage msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart1"); + msg.setBooleanProperty("Match", true); + producer.send(msg); + msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart2"); + msg.setBooleanProperty("Match", false); + producer.send(msg); + + Message rMsg = subA.receive(1000); + assertNotNull(rMsg); + assertEquals("Content was wrong", + "testResubscribeWithChangedSelectorAndRestart1", + ((TextMessage) rMsg).getText()); + + // Queue has no messages left + AMQQueue subQueue = new AMQQueue("amq.topic", "clientid" + ":" + "testResubscribeWithChangedSelectorAndRestart"); + assertEquals("Msg count should be 0", 0, ((AMQSession) session).getQueueDepth(subQueue, true)); + + rMsg = subA.receive(1000); + assertNull(rMsg); + + // Send another 1 matching message and 1 non-matching message + msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart1"); + msg.setBooleanProperty("Match", true); + producer.send(msg); + msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart2"); + msg.setBooleanProperty("Match", false); + producer.send(msg); + + // Disconnect subscriber without receiving the message to + //leave it on the underlying queue + subA.close(); + + // Reconnect with new selector that matches B + TopicSubscriber subB = session.createDurableSubscriber(topic, + "testResubscribeWithChangedSelectorAndRestart", + "Match = false", false); + + //verify no messages are now present on the queue as changing selector should have issued + //an unsubscribe and thus deleted the previous durable backing queue for the subscription. + //check the dur sub's underlying queue now has msg count 0 + assertEquals("Msg count should be 0", 0, ((AMQSession) session).getQueueDepth(subQueue, true)); + + // Check that new messages are received properly + msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart1"); + msg.setBooleanProperty("Match", true); + producer.send(msg); + msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart2"); + msg.setBooleanProperty("Match", false); + producer.send(msg); + + rMsg = subB.receive(1000); + assertNotNull(rMsg); + assertEquals("Content was wrong", + "testResubscribeWithChangedSelectorAndRestart2", + ((TextMessage) rMsg).getText()); + + rMsg = subB.receive(1000); + assertNull(rMsg); + + //check the dur sub's underlying queue now has msg count 0 + assertEquals("Msg count should be 0", 0, ((AMQSession) session).getQueueDepth(subQueue, true)); + conn.close(); + + //now restart the server + try + { + restartBroker(); + } + catch (Exception e) + { + _logger.error("problems restarting broker: " + e); + throw e; + } + + // Reconnect to broker + Connection connection = getConnectionFactory().createConnection("guest", "guest"); + connection.start(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + topic = new AMQTopic((AMQConnection) connection, "testResubscribeWithChangedSelectorAndRestart"); + producer = session.createProducer(topic); + + //verify no messages now present on the queue after we restart the broker + //check the dur sub's underlying queue now has msg count 0 + assertEquals("Msg count should be 0", 0, ((AMQSession) session).getQueueDepth(subQueue, true)); + + // Reconnect with new selector that matches B + TopicSubscriber subC = session.createDurableSubscriber(topic, + "testResubscribeWithChangedSelectorAndRestart", + "Match = False", false); + + // Check that new messages are still sent and recieved properly + msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart1"); + msg.setBooleanProperty("Match", true); + producer.send(msg); + msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart2"); + msg.setBooleanProperty("Match", false); + producer.send(msg); + + //check the dur sub's underlying queue now has msg count 1 + assertEquals("Msg count should be 1", 1, ((AMQSession) session).getQueueDepth(subQueue, true)); + + rMsg = subC.receive(1000); + assertNotNull(rMsg); + assertEquals("Content was wrong", + "testResubscribeWithChangedSelectorAndRestart2", + ((TextMessage) rMsg).getText()); + + rMsg = subC.receive(1000); + assertNull(rMsg); + + session.unsubscribe("testResubscribeWithChangedSelectorAndRestart"); + + subC.close(); + session.close(); + connection.close(); + } +} + diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java new file mode 100644 index 0000000000..3f2d6f92ab --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java @@ -0,0 +1,206 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.message; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.AMQPInvalidClassException; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.message.NonQpidObjectMessage; +import org.apache.qpid.client.message.QpidMessageProperties; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageFormatException; +import javax.jms.MessageProducer; +import javax.jms.ObjectMessage; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.Topic; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Apache Software Foundation + */ +public class JMSPropertiesTest extends QpidBrokerTestCase +{ + + private static final Logger _logger = LoggerFactory.getLogger(JMSPropertiesTest.class); + + public String _connectionString = "vm://:1"; + + public static final String JMS_CORR_ID = "QPIDID_01"; + public static final int JMS_DELIV_MODE = 1; + public static final String JMS_TYPE = "test.jms.type"; + protected static final String NULL_OBJECT_PROPERTY = "NullObject"; + protected static final String INVALID_OBJECT_PROPERTY = "InvalidObject"; + + protected void setUp() throws Exception + { + super.setUp(); + } + + protected void tearDown() throws Exception + { + super.tearDown(); + } + + public void testJMSProperties() throws Exception + { + AMQConnection con = (AMQConnection) getConnection("guest", "guest"); + AMQSession consumerSession = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Queue queue = + new AMQQueue(con.getDefaultQueueExchangeName(), new AMQShortString("someQ"), new AMQShortString("someQ"), false, + true); + MessageConsumer consumer = consumerSession.createConsumer(queue); + + AMQConnection con2 = (AMQConnection) getConnection("guest", "guest"); + Session producerSession = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageProducer producer = producerSession.createProducer(queue); + Destination JMS_REPLY_TO = new AMQQueue(con2, "my.replyto"); + // create a test message to send + ObjectMessage sentMsg = new NonQpidObjectMessage(producerSession); + sentMsg.setJMSCorrelationID(JMS_CORR_ID); + sentMsg.setJMSDeliveryMode(JMS_DELIV_MODE); + sentMsg.setJMSType(JMS_TYPE); + sentMsg.setJMSReplyTo(JMS_REPLY_TO); + + String JMSXGroupID_VALUE = "group"; + sentMsg.setStringProperty("JMSXGroupID", JMSXGroupID_VALUE); + + int JMSXGroupSeq_VALUE = 1; + sentMsg.setIntProperty("JMSXGroupSeq", JMSXGroupSeq_VALUE); + + try + { + sentMsg.setObjectProperty(NULL_OBJECT_PROPERTY, null); + fail("Null Object Property value set"); + } + catch (MessageFormatException mfe) + { + // Check the error message + assertEquals("Incorrect error message", AMQPInvalidClassException.INVALID_OBJECT_MSG + "null", mfe.getMessage()); + } + + try + { + sentMsg.setObjectProperty(INVALID_OBJECT_PROPERTY, new Exception()); + fail("Non primitive Object Property value set"); + } + catch (MessageFormatException mfe) + { + // Check the error message + assertEquals("Incorrect error message: " + mfe.getMessage(), AMQPInvalidClassException.INVALID_OBJECT_MSG + Exception.class, mfe.getMessage()); + } + + // send it + producer.send(sentMsg); + + con2.close(); + + con.start(); + + // get message and check JMS properties + ObjectMessage rm = (ObjectMessage) consumer.receive(2000); + assertNotNull(rm); + + assertEquals("JMS Correlation ID mismatch", sentMsg.getJMSCorrelationID(), rm.getJMSCorrelationID()); + // TODO: Commented out as always overwritten by send delivery mode value - prob should not set in conversion + // assertEquals("JMS Delivery Mode mismatch",sentMsg.getJMSDeliveryMode(),rm.getJMSDeliveryMode()); + assertEquals("JMS Type mismatch", sentMsg.getJMSType(), rm.getJMSType()); + assertEquals("JMS Reply To mismatch", sentMsg.getJMSReplyTo(), rm.getJMSReplyTo()); + assertTrue("JMSMessageID Does not start ID:", rm.getJMSMessageID().startsWith("ID:")); + assertEquals("JMS Default priority should be 4",Message.DEFAULT_PRIORITY,rm.getJMSPriority()); + + //Validate that the JMSX values are correct + assertEquals("JMSXGroupID is not as expected:", JMSXGroupID_VALUE, rm.getStringProperty("JMSXGroupID")); + assertEquals("JMSXGroupSeq is not as expected:", JMSXGroupSeq_VALUE, rm.getIntProperty("JMSXGroupSeq")); + + boolean JMSXGroupID_Available = false; + boolean JMSXGroupSeq_Available = false; + Enumeration props = con.getMetaData().getJMSXPropertyNames(); + while (props.hasMoreElements()) + { + String name = (String) props.nextElement(); + if (name.equals("JMSXGroupID")) + { + JMSXGroupID_Available = true; + } + if (name.equals("JMSXGroupSeq")) + { + JMSXGroupSeq_Available = true; + } + } + + assertTrue("JMSXGroupID not available.",JMSXGroupID_Available); + assertTrue("JMSXGroupSeq not available.",JMSXGroupSeq_Available); + + // Check that the NULL_OBJECT_PROPERTY was not set or transmitted. + assertFalse(NULL_OBJECT_PROPERTY + " was not set.", rm.propertyExists(NULL_OBJECT_PROPERTY)); + + con.close(); + } + + /** + * Test Goal : Test if custom message properties can be set and retrieved properly with out an error. + * Also test if unsupported properties are filtered out. See QPID-2930. + */ + public void testQpidExtensionProperties() throws Exception + { + Connection con = getConnection("guest", "guest"); + Session ssn = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE); + con.start(); + + Topic topic = ssn.createTopic("test"); + MessageConsumer consumer = ssn.createConsumer(topic); + MessageProducer prod = ssn.createProducer(topic); + Message m = ssn.createMessage(); + m.setObjectProperty("foo-bar", "foobar".getBytes()); + m.setObjectProperty(QpidMessageProperties.AMQP_0_10_APP_ID, "my-app-id"); + prod.send(m); + + Message msg = consumer.receive(1000); + assertNotNull(msg); + + Enumeration enu = msg.getPropertyNames(); + Map map = new HashMap(); + while (enu.hasMoreElements()) + { + String name = enu.nextElement(); + String value = msg.getStringProperty(name); + map.put(name, value); + } + + assertFalse("Property 'foo-bar' should have been filtered out",map.containsKey("foo-bar")); + assertEquals("Property "+ QpidMessageProperties.AMQP_0_10_APP_ID + " should be present","my-app-id",msg.getStringProperty(QpidMessageProperties.AMQP_0_10_APP_ID)); + assertEquals("Property "+ QpidMessageProperties.AMQP_0_10_ROUTING_KEY + " should be present","test",msg.getStringProperty(QpidMessageProperties.AMQP_0_10_ROUTING_KEY)); + + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/message/StreamMessageTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/message/StreamMessageTest.java new file mode 100644 index 0000000000..f8ab593c88 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/message/StreamMessageTest.java @@ -0,0 +1,165 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.message; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQHeadersExchange; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.url.AMQBindingURL; +import org.apache.qpid.url.BindingURL; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageEOFException; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.StreamMessage; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +/** + * @author Apache Software Foundation + */ +public class StreamMessageTest extends QpidBrokerTestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(StreamMessageTest.class); + + public void testStreamMessageEOF() throws Exception + { + AMQConnection con = (AMQConnection) getConnection("guest", "guest"); + AMQSession consumerSession = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + AMQHeadersExchange queue = + new AMQHeadersExchange(new AMQBindingURL( + ExchangeDefaults.HEADERS_EXCHANGE_CLASS + "://" + ExchangeDefaults.HEADERS_EXCHANGE_NAME + + "/test/queue1?" + BindingURL.OPTION_ROUTING_KEY + "='F0000=1'")); + + FieldTable ft = new FieldTable(); + ft.setString("x-match", "any"); + ft.setString("F1000", "1"); + consumerSession.declareAndBind(queue, ft); + MessageConsumer consumer = consumerSession.createConsumer(queue); + // force synch to ensure the consumer has resulted in a bound queue + // ((AMQSession) consumerSession).declareExchangeSynch(ExchangeDefaults.HEADERS_EXCHANGE_NAME, ExchangeDefaults.HEADERS_EXCHANGE_CLASS); + // This is the default now + + Connection con2 = (AMQConnection) getConnection("guest", "guest"); + + AMQSession producerSession = (AMQSession) con2.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + // Need to start the "producer" connection in order to receive bounced messages + _logger.info("Starting producer connection"); + con2.start(); + + MessageProducer mandatoryProducer = producerSession.createProducer(queue); + + // Third test - should be routed + _logger.info("Sending isBound message"); + StreamMessage msg = producerSession.createStreamMessage(); + + msg.setStringProperty("F1000", "1"); + + msg.writeByte((byte) 42); + + mandatoryProducer.send(msg); + + _logger.info("Starting consumer connection"); + con.start(); + + StreamMessage msg2 = (StreamMessage) consumer.receive(2000); + assertNotNull(msg2); + + msg2.readByte(); + try + { + msg2.readByte(); + fail("Expected exception not thrown"); + } + catch (Exception e) + { + assertTrue("Expected MessageEOFException: " + e, e instanceof MessageEOFException); + } + con.close(); + con2.close(); + } + + public void testModifyReceivedMessageExpandsBuffer() throws Exception + { + final CountDownLatch awaitMessages = new CountDownLatch(1); + final AtomicReference listenerCaughtException = new AtomicReference(); + + AMQConnection con = (AMQConnection) getConnection("guest", "guest"); + AMQSession consumerSession = (AMQSession) con.createSession(false, Session.CLIENT_ACKNOWLEDGE); + AMQQueue queue = new AMQQueue(con.getDefaultQueueExchangeName(), new AMQShortString("testQ")); + MessageConsumer consumer = consumerSession.createConsumer(queue); + consumer.setMessageListener(new MessageListener() + { + + public void onMessage(Message message) + { + final StreamMessage sm = (StreamMessage) message; + try + { + sm.clearBody(); + // it is legal to extend a stream message's content + sm.writeString("dfgjshfslfjshflsjfdlsjfhdsljkfhdsljkfhsd"); + } + catch (Throwable t) + { + listenerCaughtException.set(t); + } + finally + { + awaitMessages.countDown(); + } + } + }); + + Connection con2 = (AMQConnection) getConnection("guest", "guest"); + AMQSession producerSession = (AMQSession) con2.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageProducer producer = producerSession.createProducer(queue); + con.start(); + StreamMessage sm = producerSession.createStreamMessage(); + sm.writeInt(42); + producer.send(sm); + + // Allow up to five seconds for the message to arrive with the consumer + final boolean completed = awaitMessages.await(5, TimeUnit.SECONDS); + assertTrue("Message did not arrive with consumer within a reasonable time", completed); + final Throwable listenerException = listenerCaughtException.get(); + assertNull("No exception should be caught by listener : " + listenerException, listenerException); + + con.close(); + con2.close(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/message/UTF8Test.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/message/UTF8Test.java new file mode 100644 index 0000000000..cc95afafa2 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/message/UTF8Test.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.test.unit.message; + +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.naming.InitialContext; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Properties; + + +/** + * This test makes sure that utf8 characters can be used for + * specifying exchange, queue name and routing key. + * + * those tests are related to qpid-1384 + */ +public class UTF8Test extends QpidBrokerTestCase +{ + public void testPlainEn() throws Exception + { + invoke("UTF8En"); + } + + + public void testUTF8Jp() throws Exception + { + invoke("UTF8Jp"); + } + + private void invoke(String name) throws Exception + { + InputStream stream = getClass().getClassLoader().getResourceAsStream("org/apache/qpid/test/unit/message/" + name); + + BufferedReader in = new BufferedReader(new InputStreamReader(stream, "UTF8")); + runTest(in.readLine(), in.readLine(), in.readLine(), in.readLine()); + in.close(); + } + + private void runTest(String exchangeName, String queueName, String routingKey, String data) throws Exception + { + Connection con = getConnection(); + Session sess = con.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); + final Destination dest = getDestination(exchangeName, routingKey, queueName); + + final MessageConsumer msgCons = sess.createConsumer(dest); + con.start(); + + // Send data + MessageProducer msgProd = sess.createProducer(dest); + TextMessage message = sess.createTextMessage(data); + msgProd.send(message); + + // consume data + TextMessage m = (TextMessage) msgCons.receive(RECEIVE_TIMEOUT); + assertNotNull(m); + assertEquals(m.getText(), data); + } + + private Destination getDestination(String exch, String routkey, String qname) throws Exception + { + Properties props = new Properties(); + props.setProperty("destination.directUTF8Queue", + "direct://" + exch + "//" + qname + "?autodelete='false'&durable='false'" + + "&routingkey='" + routkey + "'"); + + // Get our connection context + InitialContext ctx = new InitialContext(props); + return (Destination) ctx.lookup("directUTF8Queue"); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java new file mode 100644 index 0000000000..cc8bfb9433 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java @@ -0,0 +1,1063 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.topic; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQNoRouteException; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.management.common.JMXConnnectionFactory; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.ExceptionListener; +import javax.jms.InvalidDestinationException; +import javax.jms.InvalidSelectorException; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.jms.TopicSubscriber; +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; +import java.io.IOException; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * @todo Code to check that a consumer gets only one particular method could be factored into a re-usable method (as + * a static on a base test helper class, e.g. TestUtils. + * + * @todo Code to create test end-points using session per connection, or all sessions on one connection, to be factored + * out to make creating this test variation simpler. Want to make this variation available through LocalCircuit, + * driven by the test model. + */ +public class DurableSubscriptionTest extends QpidBrokerTestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(DurableSubscriptionTest.class); + + private static final String MY_TOPIC = "MyTopic"; + + private static final String MY_SUBSCRIPTION = "MySubscription"; + + /** Timeout for receive() if we are expecting a message */ + private static final long POSITIVE_RECEIVE_TIMEOUT = 2000; + + /** Timeout for receive() if we are not expecting a message */ + private static final long NEGATIVE_RECEIVE_TIMEOUT = 1000; + + private JMXConnector _jmxc; + private MBeanServerConnection _mbsc; + private static final String USER = "admin"; + private static final String PASSWORD = "admin"; + private boolean _jmxConnected; + + public void setUp() throws Exception + { + getBrokerConfiguration().addJmxManagementConfiguration(); + _jmxConnected=false; + super.setUp(); + } + + public void tearDown() throws Exception + { + try + { + if(_jmxConnected) + { + try + { + _jmxc.close(); + } + catch (IOException e) + { + _logger.error("Error closing JMX connection", e); + } + } + } + finally + { + super.tearDown(); + } + } + + public void testUnsubscribe() throws Exception + { + AMQConnection con = (AMQConnection) getConnection(); + AMQTopic topic = new AMQTopic(con, "MyDurableSubscriptionTestTopic"); + _logger.info("Create Session 1"); + Session session1 = con.createSession(false, AMQSession.NO_ACKNOWLEDGE); + _logger.info("Create Consumer on Session 1"); + MessageConsumer consumer1 = session1.createConsumer(topic); + _logger.info("Create Producer on Session 1"); + MessageProducer producer = session1.createProducer(topic); + + _logger.info("Create Session 2"); + Session session2 = con.createSession(false, AMQSession.NO_ACKNOWLEDGE); + _logger.info("Create Durable Subscriber on Session 2"); + TopicSubscriber consumer2 = session2.createDurableSubscriber(topic, MY_SUBSCRIPTION); + + _logger.info("Starting connection"); + con.start(); + + _logger.info("Producer sending message A"); + producer.send(session1.createTextMessage("A")); + + //check the dur sub's underlying queue now has msg count 1 + AMQQueue subQueue = new AMQQueue("amq.topic", "clientid" + ":" + MY_SUBSCRIPTION); + assertEquals("Msg count should be 1", 1, ((AMQSession) session1).getQueueDepth(subQueue, true)); + + Message msg; + _logger.info("Receive message on consumer 1:expecting A"); + msg = consumer1.receive(POSITIVE_RECEIVE_TIMEOUT); + assertNotNull("Message should have been received",msg); + assertEquals("A", ((TextMessage) msg).getText()); + _logger.info("Receive message on consumer 1 :expecting null"); + msg = consumer1.receive(NEGATIVE_RECEIVE_TIMEOUT); + assertEquals(null, msg); + + _logger.info("Receive message on consumer 2:expecting A"); + msg = consumer2.receive(POSITIVE_RECEIVE_TIMEOUT); + assertNotNull("Message should have been received",msg); + assertEquals("A", ((TextMessage) msg).getText()); + msg = consumer2.receive(NEGATIVE_RECEIVE_TIMEOUT); + _logger.info("Receive message on consumer 1 :expecting null"); + assertEquals(null, msg); + + //check the dur sub's underlying queue now has msg count 0 + assertEquals("Msg count should be 0", 0, ((AMQSession) session2).getQueueDepth(subQueue, true)); + + consumer2.close(); + _logger.info("Unsubscribe session2/consumer2"); + session2.unsubscribe(MY_SUBSCRIPTION); + + ((AMQSession) session2).sync(); + + if(isJavaBroker()) + { + //Verify that the queue was deleted by querying for its JMX MBean + _jmxc = JMXConnnectionFactory.getJMXConnection(5000, "127.0.0.1", + getManagementPort(getPort()), USER, PASSWORD); + + _jmxConnected = true; + _mbsc = _jmxc.getMBeanServerConnection(); + + //must replace the occurrence of ':' in queue name with '-' + String queueObjectNameText = "clientid" + "-" + MY_SUBSCRIPTION; + + ObjectName objName = new ObjectName("org.apache.qpid:type=VirtualHost.Queue,name=" + + queueObjectNameText + ",*"); + + Set objectInstances = _mbsc.queryNames(objName, null); + + if(objectInstances.size() != 0) + { + fail("Queue MBean was found. Expected queue to have been deleted"); + } + else + { + _logger.info("Underlying dueue for the durable subscription was confirmed deleted."); + } + } + + //verify unsubscribing the durable subscriber did not affect the non-durable one + _logger.info("Producer sending message B"); + producer.send(session1.createTextMessage("B")); + + _logger.info("Receive message on consumer 1 :expecting B"); + msg = consumer1.receive(POSITIVE_RECEIVE_TIMEOUT); + assertNotNull("Message should have been received",msg); + assertEquals("B", ((TextMessage) msg).getText()); + _logger.info("Receive message on consumer 1 :expecting null"); + msg = consumer1.receive(NEGATIVE_RECEIVE_TIMEOUT); + assertEquals(null, msg); + + _logger.info("Close connection"); + con.close(); + } + + + /** + * Specifically uses a subscriber with a selector because QPID-4731 found that selectors + * can prevent queue removal. + */ + public void testUnsubscribeWhenUsingSelectorMakesTopicUnreachable() throws Exception + { + setTestClientSystemProperty("qpid.default_mandatory_topic","true"); + + // set up subscription + AMQConnection connection = (AMQConnection) getConnection(); + connection.start(); + + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = new AMQTopic(connection, MY_TOPIC); + MessageProducer producer = session.createProducer(topic); + + TopicSubscriber subscriber = session.createDurableSubscriber(topic, MY_SUBSCRIPTION, "1 = 1", false); + StoringExceptionListener exceptionListener = new StoringExceptionListener(); + connection.setExceptionListener(exceptionListener); + + // send message and verify it was consumed + producer.send(session.createTextMessage("message1")); + assertNotNull("Message should have been successfully received", subscriber.receive(POSITIVE_RECEIVE_TIMEOUT)); + assertEquals(null, exceptionListener.getException()); + session.unsubscribe(MY_SUBSCRIPTION); + + // send another message and verify that the connection exception listener was fired. + StoringExceptionListener exceptionListener2 = new StoringExceptionListener(); + connection.setExceptionListener(exceptionListener2); + + producer.send(session.createTextMessage("message that should be unroutable")); + ((AMQSession) session).sync(); + + JMSException exception = exceptionListener2.awaitException(); + assertNotNull("Expected exception as message should no longer be routable", exception); + + Throwable linkedException = exception.getLinkedException(); + assertNotNull("The linked exception of " + exception + " should be the 'no route' exception", linkedException); + assertEquals(AMQNoRouteException.class, linkedException.getClass()); + } + + private final class StoringExceptionListener implements ExceptionListener + { + private volatile JMSException _exception; + private CountDownLatch _latch = new CountDownLatch(1); + + @Override + public void onException(JMSException exception) + { + _exception = exception; + _logger.info("Exception listener received: " + exception); + _latch.countDown(); + } + + public JMSException awaitException() throws InterruptedException + { + _latch.await(POSITIVE_RECEIVE_TIMEOUT, TimeUnit.MILLISECONDS); + return _exception; + } + + public JMSException getException() + { + return _exception; + } + } + + public void testDurabilityNOACK() throws Exception + { + durabilityImpl(AMQSession.NO_ACKNOWLEDGE, false); + } + + public void testDurabilityAUTOACK() throws Exception + { + durabilityImpl(Session.AUTO_ACKNOWLEDGE, false); + } + + public void testDurabilityAUTOACKwithRestartIfPersistent() throws Exception + { + if(!isBrokerStorePersistent()) + { + _logger.warn("The broker store is not persistent, skipping this test"); + return; + } + + durabilityImpl(Session.AUTO_ACKNOWLEDGE, true); + } + + public void testDurabilityNOACKSessionPerConnection() throws Exception + { + durabilityImplSessionPerConnection(AMQSession.NO_ACKNOWLEDGE); + } + + public void testDurabilityAUTOACKSessionPerConnection() throws Exception + { + durabilityImplSessionPerConnection(Session.AUTO_ACKNOWLEDGE); + } + + private void durabilityImpl(int ackMode, boolean restartBroker) throws Exception + { + AMQConnection con = (AMQConnection) getConnection(); + AMQTopic topic = new AMQTopic(con, MY_TOPIC); + Session session1 = con.createSession(false, ackMode); + MessageConsumer consumer1 = session1.createConsumer(topic); + + Session sessionProd = con.createSession(false, ackMode); + MessageProducer producer = sessionProd.createProducer(topic); + + Session session2 = con.createSession(false, ackMode); + TopicSubscriber consumer2 = session2.createDurableSubscriber(topic, MY_SUBSCRIPTION); + + con.start(); + + //send message A and check both consumers receive + producer.send(session1.createTextMessage("A")); + + Message msg; + _logger.info("Receive message on consumer 1 :expecting A"); + msg = consumer1.receive(POSITIVE_RECEIVE_TIMEOUT); + assertNotNull("Message should have been received",msg); + assertEquals("A", ((TextMessage) msg).getText()); + msg = consumer1.receive(NEGATIVE_RECEIVE_TIMEOUT); + assertEquals(null, msg); + + _logger.info("Receive message on consumer 2 :expecting A"); + msg = consumer2.receive(POSITIVE_RECEIVE_TIMEOUT); + assertNotNull("Message should have been received",msg); + assertEquals("A", ((TextMessage) msg).getText()); + msg = consumer2.receive(NEGATIVE_RECEIVE_TIMEOUT); + assertEquals(null, msg); + + //send message B, receive with consumer 1, and disconnect consumer 2 to leave the message behind (if not NO_ACK) + producer.send(session1.createTextMessage("B")); + + _logger.info("Receive message on consumer 1 :expecting B"); + msg = consumer1.receive(POSITIVE_RECEIVE_TIMEOUT); + assertNotNull("Consumer 1 should get message 'B'.", msg); + assertEquals("Incorrect Message received on consumer1.", "B", ((TextMessage) msg).getText()); + _logger.info("Receive message on consumer 1 :expecting null"); + msg = consumer1.receive(500); + assertNull("There should be no more messages for consumption on consumer1.", msg); + + consumer2.close(); + session2.close(); + + //Send message C, then connect consumer 3 to durable subscription and get + //message B if not using NO_ACK, then receive C with consumer 1 and 3 + producer.send(session1.createTextMessage("C")); + + Session session3 = con.createSession(false, ackMode); + MessageConsumer consumer3 = session3.createDurableSubscriber(topic, MY_SUBSCRIPTION); + + if(ackMode == AMQSession.NO_ACKNOWLEDGE) + { + //Do nothing if NO_ACK was used, as prefetch means the message was dropped + //when we didn't call receive() to get it before closing consumer 2 + } + else + { + _logger.info("Receive message on consumer 3 :expecting B"); + msg = consumer3.receive(POSITIVE_RECEIVE_TIMEOUT); + assertNotNull("Consumer 3 should get message 'B'.", msg); + assertEquals("Incorrect Message received on consumer3.", "B", ((TextMessage) msg).getText()); + } + + _logger.info("Receive message on consumer 1 :expecting C"); + msg = consumer1.receive(POSITIVE_RECEIVE_TIMEOUT); + assertNotNull("Consumer 1 should get message 'C'.", msg); + assertEquals("Incorrect Message received on consumer1.", "C", ((TextMessage) msg).getText()); + _logger.info("Receive message on consumer 1 :expecting null"); + msg = consumer1.receive(500); + assertNull("There should be no more messages for consumption on consumer1.", msg); + + _logger.info("Receive message on consumer 3 :expecting C"); + msg = consumer3.receive(POSITIVE_RECEIVE_TIMEOUT); + assertNotNull("Consumer 3 should get message 'C'.", msg); + assertEquals("Incorrect Message received on consumer3.", "C", ((TextMessage) msg).getText()); + _logger.info("Receive message on consumer 3 :expecting null"); + msg = consumer3.receive(500); + assertNull("There should be no more messages for consumption on consumer3.", msg); + + consumer1.close(); + consumer3.close(); + + session3.unsubscribe(MY_SUBSCRIPTION); + + con.close(); + + if(restartBroker) + { + try + { + restartBroker(); + } + catch (Exception e) + { + fail("Error restarting the broker"); + } + } + } + + private void durabilityImplSessionPerConnection(int ackMode) throws Exception + { + Message msg; + // Create producer. + AMQConnection con0 = (AMQConnection) getConnection(); + con0.start(); + Session session0 = con0.createSession(false, ackMode); + + AMQTopic topic = new AMQTopic(con0, MY_TOPIC); + + Session sessionProd = con0.createSession(false, ackMode); + MessageProducer producer = sessionProd.createProducer(topic); + + // Create consumer 1. + AMQConnection con1 = (AMQConnection) getConnection(); + con1.start(); + Session session1 = con1.createSession(false, ackMode); + + MessageConsumer consumer1 = session1.createConsumer(topic); + + // Create consumer 2. + AMQConnection con2 = (AMQConnection) getConnection(); + con2.start(); + Session session2 = con2.createSession(false, ackMode); + + TopicSubscriber consumer2 = session2.createDurableSubscriber(topic, MY_SUBSCRIPTION); + + // Send message and check that both consumers get it and only it. + producer.send(session0.createTextMessage("A")); + + msg = consumer1.receive(POSITIVE_RECEIVE_TIMEOUT); + assertNotNull("Message should be available", msg); + assertEquals("Message Text doesn't match", "A", ((TextMessage) msg).getText()); + msg = consumer1.receive(500); + assertNull("There should be no more messages for consumption on consumer1.", msg); + + msg = consumer2.receive(POSITIVE_RECEIVE_TIMEOUT); + assertNotNull("Message should have been received",msg); + assertEquals("Consumer 2 should also received the first msg.", "A", ((TextMessage) msg).getText()); + msg = consumer2.receive(NEGATIVE_RECEIVE_TIMEOUT); + assertNull("There should be no more messages for consumption on consumer2.", msg); + + // Send message and receive on consumer 1. + producer.send(session0.createTextMessage("B")); + + _logger.info("Receive message on consumer 1 :expecting B"); + msg = consumer1.receive(POSITIVE_RECEIVE_TIMEOUT); + assertEquals("B", ((TextMessage) msg).getText()); + _logger.info("Receive message on consumer 1 :expecting null"); + msg = consumer1.receive(NEGATIVE_RECEIVE_TIMEOUT); + assertEquals(null, msg); + + // Detach the durable subscriber. + consumer2.close(); + session2.close(); + con2.close(); + + // Send message C and receive on consumer 1 + producer.send(session0.createTextMessage("C")); + + _logger.info("Receive message on consumer 1 :expecting C"); + msg = consumer1.receive(POSITIVE_RECEIVE_TIMEOUT); + assertEquals("C", ((TextMessage) msg).getText()); + _logger.info("Receive message on consumer 1 :expecting null"); + msg = consumer1.receive(NEGATIVE_RECEIVE_TIMEOUT); + assertEquals(null, msg); + + // Re-attach a new consumer to the durable subscription, and check that it gets message B it left (if not NO_ACK) + // and also gets message C sent after it was disconnected. + AMQConnection con3 = (AMQConnection) getConnection(); + con3.start(); + Session session3 = con3.createSession(false, ackMode); + + TopicSubscriber consumer3 = session3.createDurableSubscriber(topic, MY_SUBSCRIPTION); + + if(ackMode == AMQSession.NO_ACKNOWLEDGE) + { + //Do nothing if NO_ACK was used, as prefetch means the message was dropped + //when we didn't call receive() to get it before closing consumer 2 + } + else + { + _logger.info("Receive message on consumer 3 :expecting B"); + msg = consumer3.receive(POSITIVE_RECEIVE_TIMEOUT); + assertNotNull(msg); + assertEquals("B", ((TextMessage) msg).getText()); + } + + _logger.info("Receive message on consumer 3 :expecting C"); + msg = consumer3.receive(POSITIVE_RECEIVE_TIMEOUT); + assertNotNull("Consumer 3 should get message 'C'.", msg); + assertEquals("Incorrect Message recevied on consumer3.", "C", ((TextMessage) msg).getText()); + _logger.info("Receive message on consumer 3 :expecting null"); + msg = consumer3.receive(NEGATIVE_RECEIVE_TIMEOUT); + assertNull("There should be no more messages for consumption on consumer3.", msg); + + consumer1.close(); + consumer3.close(); + + session3.unsubscribe(MY_SUBSCRIPTION); + + con0.close(); + con1.close(); + con3.close(); + } + + /** + * This tests the fix for QPID-1085 + * Creates a durable subscriber with an invalid selector, checks that the + * exception is thrown correctly and that the subscription is not created. + * @throws Exception + */ + public void testDurableWithInvalidSelector() throws Exception + { + Connection conn = getConnection(); + conn.start(); + Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + AMQTopic topic = new AMQTopic((AMQConnection) conn, "MyTestDurableWithInvalidSelectorTopic"); + MessageProducer producer = session.createProducer(topic); + producer.send(session.createTextMessage("testDurableWithInvalidSelector1")); + try + { + TopicSubscriber deadSubscriber = session.createDurableSubscriber(topic, "testDurableWithInvalidSelectorSub", + "=TEST 'test", true); + assertNull("Subscriber should not have been created", deadSubscriber); + } + catch (JMSException e) + { + assertTrue("Wrong type of exception thrown", e instanceof InvalidSelectorException); + } + TopicSubscriber liveSubscriber = session.createDurableSubscriber(topic, "testDurableWithInvalidSelectorSub"); + assertNotNull("Subscriber should have been created", liveSubscriber); + + producer.send(session.createTextMessage("testDurableWithInvalidSelector2")); + + Message msg = liveSubscriber.receive(POSITIVE_RECEIVE_TIMEOUT); + assertNotNull ("Message should have been received", msg); + assertEquals ("testDurableWithInvalidSelector2", ((TextMessage) msg).getText()); + assertNull("Should not receive subsequent message", liveSubscriber.receive(200)); + liveSubscriber.close(); + session.unsubscribe("testDurableWithInvalidSelectorSub"); + } + + /** + * This tests the fix for QPID-1085 + * Creates a durable subscriber with an invalid destination, checks that the + * exception is thrown correctly and that the subscription is not created. + * @throws Exception + */ + public void testDurableWithInvalidDestination() throws Exception + { + Connection conn = getConnection(); + conn.start(); + Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + AMQTopic topic = new AMQTopic((AMQConnection) conn, "testDurableWithInvalidDestinationTopic"); + try + { + TopicSubscriber deadSubscriber = session.createDurableSubscriber(null, "testDurableWithInvalidDestinationsub"); + assertNull("Subscriber should not have been created", deadSubscriber); + } + catch (InvalidDestinationException e) + { + // This was expected + } + MessageProducer producer = session.createProducer(topic); + producer.send(session.createTextMessage("testDurableWithInvalidSelector1")); + + TopicSubscriber liveSubscriber = session.createDurableSubscriber(topic, "testDurableWithInvalidDestinationsub"); + assertNotNull("Subscriber should have been created", liveSubscriber); + + producer.send(session.createTextMessage("testDurableWithInvalidSelector2")); + Message msg = liveSubscriber.receive(POSITIVE_RECEIVE_TIMEOUT); + assertNotNull ("Message should have been received", msg); + assertEquals ("testDurableWithInvalidSelector2", ((TextMessage) msg).getText()); + assertNull("Should not receive subsequent message", liveSubscriber.receive(200)); + + session.unsubscribe("testDurableWithInvalidDestinationsub"); + } + + /** + * Creates a durable subscription with a selector, then changes that selector on resubscription + *

+ * QPID-1202, QPID-2418 + */ + public void testResubscribeWithChangedSelector() throws Exception + { + Connection conn = getConnection(); + conn.start(); + Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + AMQTopic topic = new AMQTopic((AMQConnection) conn, "testResubscribeWithChangedSelector"); + MessageProducer producer = session.createProducer(topic); + + // Create durable subscriber that matches A + TopicSubscriber subA = session.createDurableSubscriber(topic, + "testResubscribeWithChangedSelector", + "Match = True", false); + + // Send 1 matching message and 1 non-matching message + sendMatchingAndNonMatchingMessage(session, producer); + + Message rMsg = subA.receive(NEGATIVE_RECEIVE_TIMEOUT); + assertNotNull(rMsg); + assertEquals("Content was wrong", + "testResubscribeWithChangedSelector1", + ((TextMessage) rMsg).getText()); + + rMsg = subA.receive(NEGATIVE_RECEIVE_TIMEOUT); + assertNull(rMsg); + + // Disconnect subscriber + subA.close(); + + // Reconnect with new selector that matches B + TopicSubscriber subB = session.createDurableSubscriber(topic, + "testResubscribeWithChangedSelector","Match = False", false); + + //verify no messages are now received. + rMsg = subB.receive(NEGATIVE_RECEIVE_TIMEOUT); + assertNull("Should not have received message as the selector was changed", rMsg); + + // Check that new messages are received properly + sendMatchingAndNonMatchingMessage(session, producer); + rMsg = subB.receive(POSITIVE_RECEIVE_TIMEOUT); + + assertNotNull("Message should have been received", rMsg); + assertEquals("Content was wrong", + "testResubscribeWithChangedSelector2", + ((TextMessage) rMsg).getText()); + + + rMsg = subB.receive(NEGATIVE_RECEIVE_TIMEOUT); + assertNull("Message should not have been received",rMsg); + session.unsubscribe("testResubscribeWithChangedSelector"); + } + + public void testDurableSubscribeWithTemporaryTopic() throws Exception + { + Connection conn = getConnection(); + conn.start(); + Session ssn = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = ssn.createTemporaryTopic(); + try + { + ssn.createDurableSubscriber(topic, "test"); + fail("expected InvalidDestinationException"); + } + catch (InvalidDestinationException ex) + { + // this is expected + } + try + { + ssn.createDurableSubscriber(topic, "test", null, false); + fail("expected InvalidDestinationException"); + } + catch (InvalidDestinationException ex) + { + // this is expected + } + } + + private void sendMatchingAndNonMatchingMessage(Session session, MessageProducer producer) throws JMSException + { + TextMessage msg = session.createTextMessage("testResubscribeWithChangedSelector1"); + msg.setBooleanProperty("Match", true); + producer.send(msg); + msg = session.createTextMessage("testResubscribeWithChangedSelector2"); + msg.setBooleanProperty("Match", false); + producer.send(msg); + } + + + /** + * create and register a durable subscriber with a message selector and then close it + * create a publisher and send 5 right messages and 5 wrong messages + * create another durable subscriber with the same selector and name + * check messages are still there + *

+ * QPID-2418 + */ + public void testDurSubSameMessageSelector() throws Exception + { + Connection conn = getConnection(); + conn.start(); + Session session = conn.createSession(true, Session.SESSION_TRANSACTED); + AMQTopic topic = new AMQTopic((AMQConnection) conn, "sameMessageSelector"); + + //create and register a durable subscriber with a message selector and then close it + TopicSubscriber subOne = session.createDurableSubscriber(topic, "sameMessageSelector", "testprop = TRUE", false); + subOne.close(); + + MessageProducer producer = session.createProducer(topic); + for (int i = 0; i < 5; i++) + { + Message message = session.createMessage(); + message.setBooleanProperty("testprop", true); + producer.send(message); + message = session.createMessage(); + message.setBooleanProperty("testprop", false); + producer.send(message); + } + session.commit(); + producer.close(); + + // should be 5 or 10 messages on queue now + // (5 for the java broker due to use of server side selectors, and 10 for the cpp broker due to client side selectors only) + AMQQueue queue = new AMQQueue("amq.topic", "clientid" + ":" + "sameMessageSelector"); + assertEquals("Queue depth is wrong", isJavaBroker() ? 5 : 10, ((AMQSession) session).getQueueDepth(queue, true)); + + // now recreate the durable subscriber and check the received messages + TopicSubscriber subTwo = session.createDurableSubscriber(topic, "sameMessageSelector", "testprop = TRUE", false); + + for (int i = 0; i < 5; i++) + { + Message message = subTwo.receive(1000); + if (message == null) + { + fail("sameMessageSelector test failed. no message was returned"); + } + else + { + assertEquals("sameMessageSelector test failed. message selector not reset", + "true", message.getStringProperty("testprop")); + } + } + + session.commit(); + + // Check queue has no messages + if (isJavaBroker()) + { + assertEquals("Queue should be empty", 0, ((AMQSession) session).getQueueDepth(queue)); + } + else + { + assertTrue("At most the queue should have only 1 message", ((AMQSession) session).getQueueDepth(queue) <= 1); + } + + // Unsubscribe + session.unsubscribe("sameMessageSelector"); + + conn.close(); + } + + /** + *

    + *
  • create and register a durable subscriber with a message selector + *
  • create another durable subscriber with a different selector and same name + *
  • check first subscriber is now closed + *
  • create a publisher and send messages + *
  • check messages are received correctly + *
+ *

+ * QPID-2418 + */ + public void testResubscribeWithChangedSelectorNoClose() throws Exception + { + Connection conn = getConnection(); + conn.start(); + Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + AMQTopic topic = new AMQTopic((AMQConnection) conn, "testResubscribeWithChangedSelectorNoClose"); + + // Create durable subscriber that matches A + TopicSubscriber subA = session.createDurableSubscriber(topic, + "testResubscribeWithChangedSelectorNoClose", + "Match = True", false); + + // Reconnect with new selector that matches B + TopicSubscriber subB = session.createDurableSubscriber(topic, + "testResubscribeWithChangedSelectorNoClose", + "Match = false", false); + + // First subscription has been closed + try + { + subA.receive(1000); + fail("First subscription was not closed"); + } + catch (Exception e) + { + _logger.error("Receive error",e); + } + + conn.stop(); + + // Send 1 matching message and 1 non-matching message + MessageProducer producer = session.createProducer(topic); + TextMessage msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart1"); + msg.setBooleanProperty("Match", true); + producer.send(msg); + msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart2"); + msg.setBooleanProperty("Match", false); + producer.send(msg); + + // should be 1 or 2 messages on queue now + // (1 for the java broker due to use of server side selectors, and 2 for the cpp broker due to client side selectors only) + AMQQueue queue = new AMQQueue("amq.topic", "clientid" + ":" + "testResubscribeWithChangedSelectorNoClose"); + assertEquals("Queue depth is wrong", isJavaBroker() ? 1 : 2, ((AMQSession) session).getQueueDepth(queue, true)); + + conn.start(); + + Message rMsg = subB.receive(POSITIVE_RECEIVE_TIMEOUT); + assertNotNull(rMsg); + assertEquals("Content was wrong", + "testResubscribeWithChangedSelectorAndRestart2", + ((TextMessage) rMsg).getText()); + + rMsg = subB.receive(1000); + assertNull(rMsg); + + // Check queue has no messages + assertEquals("Queue should be empty", 0, ((AMQSession) session).getQueueDepth(queue, true)); + + conn.close(); + } + + /** + *

    + *
  • create and register a durable subscriber with no message selector + *
  • create another durable subscriber with a selector and same name + *
  • check first subscriber is now closed + *
  • create a publisher and send messages + *
  • check messages are received correctly + *
+ *

+ * QPID-2418 + */ + public void testDurSubAddMessageSelectorNoClose() throws Exception + { + Connection conn = getConnection(); + conn.start(); + Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + AMQTopic topic = new AMQTopic((AMQConnection) conn, "subscriptionName"); + + // create and register a durable subscriber with no message selector + TopicSubscriber subOne = session.createDurableSubscriber(topic, "subscriptionName", null, false); + + // now create a durable subscriber with a selector + TopicSubscriber subTwo = session.createDurableSubscriber(topic, "subscriptionName", "testprop = TRUE", false); + + // First subscription has been closed + try + { + subOne.receive(1000); + fail("First subscription was not closed"); + } + catch (Exception e) + { + _logger.error("Receive error",e); + } + + conn.stop(); + + // Send 1 matching message and 1 non-matching message + MessageProducer producer = session.createProducer(topic); + TextMessage msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart1"); + msg.setBooleanProperty("testprop", true); + producer.send(msg); + msg = session.createTextMessage("testResubscribeWithChangedSelectorAndRestart2"); + msg.setBooleanProperty("testprop", false); + producer.send(msg); + + // should be 1 or 2 messages on queue now + // (1 for the java broker due to use of server side selectors, and 2 for the cpp broker due to client side selectors only) + AMQQueue queue = new AMQQueue("amq.topic", "clientid" + ":" + "subscriptionName"); + assertEquals("Queue depth is wrong", isJavaBroker() ? 1 : 2, ((AMQSession) session).getQueueDepth(queue, true)); + + conn.start(); + + Message rMsg = subTwo.receive(POSITIVE_RECEIVE_TIMEOUT); + assertNotNull(rMsg); + assertEquals("Content was wrong", + "testResubscribeWithChangedSelectorAndRestart1", + ((TextMessage) rMsg).getText()); + + rMsg = subTwo.receive(1000); + assertNull(rMsg); + + // Check queue has no messages + assertEquals("Queue should be empty", 0, ((AMQSession) session).getQueueDepth(queue, true)); + + conn.close(); + } + + /** + *

    + *
  • create and register a durable subscriber with no message selector + *
  • try to create another durable with the same name, should fail + *
+ *

+ * QPID-2418 + */ + public void testDurSubNoSelectorResubscribeNoClose() throws Exception + { + Connection conn = getConnection(); + conn.start(); + Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + AMQTopic topic = new AMQTopic((AMQConnection) conn, "subscriptionName"); + + // create and register a durable subscriber with no message selector + session.createDurableSubscriber(topic, "subscriptionName", null, false); + + // try to recreate the durable subscriber + try + { + session.createDurableSubscriber(topic, "subscriptionName", null, false); + fail("Subscription should not have been created"); + } + catch (Exception e) + { + _logger.error("Error creating durable subscriber",e); + } + } + + /** + * Tests that a subscriber created on a same session as producer with + * no local true does not receive messages. + */ + public void testNoLocalOnSameSession() throws Exception + { + Connection connection = getConnection(); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = session.createTopic(getTestQueueName()); + MessageProducer producer = session.createProducer(topic); + TopicSubscriber subscriber = null; + try + { + subscriber = session.createDurableSubscriber(topic, getTestName(), null, true); + connection.start(); + + producer.send(createNextMessage(session, 1)); + + Message m = subscriber.receive(NEGATIVE_RECEIVE_TIMEOUT); + assertNull("Unexpected message received", m); + } + finally + { + session.unsubscribe(getTestName()); + } + } + + + /** + * Tests that a subscriber created on a same connection but separate + * sessionM as producer with no local true does not receive messages. + */ + public void testNoLocalOnSameConnection() throws Exception + { + Connection connection = getConnection(); + + Session consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Session producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = consumerSession.createTopic(getTestQueueName()); + MessageProducer producer = producerSession.createProducer(topic); + + TopicSubscriber subscriber = null; + try + { + subscriber = consumerSession.createDurableSubscriber(topic, getTestName(), null, true); + connection.start(); + + producer.send(createNextMessage(producerSession, 1)); + + Message m = subscriber.receive(NEGATIVE_RECEIVE_TIMEOUT); + assertNull("Unexpected message received", m); + } + finally + { + consumerSession.unsubscribe(getTestName()); + } + } + + /** + * Tests that if no-local is in use, that the messages are delivered when + * the client reconnects. + * + * Currently fails on the Java Broker due to QPID-3605. + */ + public void testNoLocalMessagesNotDeliveredAfterReconnection() throws Exception + { + Connection connection = getConnection(); + + Session consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Session producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = consumerSession.createTopic(getTestQueueName()); + MessageProducer producer = producerSession.createProducer(topic); + + TopicSubscriber subscriber = null; + try + { + subscriber = consumerSession.createDurableSubscriber(topic, getTestName(), null, true); + connection.start(); + + producer.send(createNextMessage(producerSession, 1)); + + Message m = subscriber.receive(NEGATIVE_RECEIVE_TIMEOUT); + assertNull("Unexpected message received", m); + + connection.close(); + + connection = getConnection(); + + consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + subscriber = consumerSession.createDurableSubscriber(topic, getTestName(), null, true); + connection.start(); + m = subscriber.receive(NEGATIVE_RECEIVE_TIMEOUT); + assertNull("Message should not be received on a new connection", m); + } + finally + { + consumerSession.unsubscribe(getTestName()); + } + } + + /** + * Tests that messages are delivered normally to a subscriber on a separate connection despite + * the use of durable subscriber with no-local on the first connection. + */ + public void testNoLocalSubscriberAndSubscriberOnSeparateConnection() throws Exception + { + Connection noLocalConnection = getConnection(); + Connection connection = getConnection(); + + String noLocalSubId1 = getTestName() + "subId1"; + String subId = getTestName() + "subId2"; + + Session noLocalSession = noLocalConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic noLocalTopic = noLocalSession.createTopic(getTestQueueName()); + + Session consumerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + Topic topic = consumerSession.createTopic(getTestQueueName()); + + TopicSubscriber noLocalSubscriber = null; + TopicSubscriber subscriber = null; + try + { + MessageProducer producer = noLocalSession.createProducer(noLocalTopic); + noLocalSubscriber = noLocalSession.createDurableSubscriber(noLocalTopic, noLocalSubId1, null, true); + subscriber = consumerSession.createDurableSubscriber(topic, subId, null, true); + noLocalConnection.start(); + connection.start(); + + producer.send(createNextMessage(noLocalSession, 1)); + + Message m1 = noLocalSubscriber.receive(NEGATIVE_RECEIVE_TIMEOUT); + assertNull("Subscriber on nolocal connection should not receive message", m1); + + Message m2 = subscriber.receive(NEGATIVE_RECEIVE_TIMEOUT); + assertNotNull("Subscriber on non-nolocal connection should receive message", m2); + } + finally + { + noLocalSession.unsubscribe(noLocalSubId1); + consumerSession.unsubscribe(subId); + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/topic/TemporaryTopicTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/topic/TemporaryTopicTest.java new file mode 100644 index 0000000000..a5b9ce8365 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/topic/TemporaryTopicTest.java @@ -0,0 +1,182 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.topic; + +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TemporaryTopic; +import javax.jms.TextMessage; + + +/** + * Tests the behaviour of {@link TemporaryTopic}. + */ +public class TemporaryTopicTest extends QpidBrokerTestCase +{ + /** + * Tests the basic publish/subscribe behaviour of a temporary topic. Single + * message is sent to two subscribers. + */ + public void testMessageDeliveryUsingTemporaryTopic() throws Exception + { + final Connection conn = getConnection(); + final Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final TemporaryTopic topic = session.createTemporaryTopic(); + assertNotNull(topic); + final MessageProducer producer = session.createProducer(topic); + final MessageConsumer consumer1 = session.createConsumer(topic); + final MessageConsumer consumer2 = session.createConsumer(topic); + conn.start(); + producer.send(session.createTextMessage("hello")); + + final TextMessage tm1 = (TextMessage) consumer1.receive(2000); + final TextMessage tm2 = (TextMessage) consumer2.receive(2000); + + assertNotNull("Message not received by subscriber1", tm1); + assertEquals("hello", tm1.getText()); + assertNotNull("Message not received by subscriber2", tm2); + assertEquals("hello", tm2.getText()); + } + + /** + * Tests that the client is able to explicitly delete a temporary topic using + * {@link TemporaryTopic#delete()} and is prevented from deleting one that + * still has consumers. + * + * Note: Under < 0-10 {@link TemporaryTopic#delete()} only marks the queue as deleted + * on the client. 0-10 causes the topic to be deleted from the Broker. + */ + public void testExplictTemporaryTopicDeletion() throws Exception + { + final Connection conn = getConnection(); + + final Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final TemporaryTopic topic = session.createTemporaryTopic(); + assertNotNull(topic); + final MessageConsumer consumer = session.createConsumer(topic); + conn.start(); + try + { + topic.delete(); + fail("Expected JMSException : should not be able to delete while there are active consumers"); + } + catch (JMSException je) + { + //pass + assertEquals("Temporary Topic has consumers so cannot be deleted", je.getMessage()); + } + + consumer.close(); + + // Now deletion should succeed. + topic.delete(); + + try + { + session.createConsumer(topic); + fail("Exception not thrown"); + } + catch (JMSException je) + { + //pass + assertEquals("Cannot consume from a deleted destination", je.getMessage()); + } + } + + /** + * Tests that a temporary topic cannot be used by another {@link Session}. + */ + public void testUseFromAnotherSessionProhibited() throws Exception + { + final Connection conn = getConnection(); + final Session session1 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Session session2 = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final TemporaryTopic topic = session1.createTemporaryTopic(); + + try + { + session2.createConsumer(topic); + fail("Expected a JMSException when subscribing to a temporary topic created on a different session"); + } + catch (JMSException je) + { + // pass + assertEquals("Cannot consume from a temporary destination created on another session", je.getMessage()); + } + } + + /** + * Tests that the client is prohibited from creating a durable subscriber for a temporary + * queue. + */ + public void testDurableSubscriptionProhibited() throws Exception + { + final Connection conn = getConnection(); + + final Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final TemporaryTopic topic = session.createTemporaryTopic(); + assertNotNull(topic); + try + { + session.createDurableSubscriber(topic, null); + fail("Expected JMSException : should not be able to create durable subscription from temp topic"); + } + catch (JMSException je) + { + //pass + assertEquals("Cannot create a durable subscription with a temporary topic: " + topic.toString(), je.getMessage()); + } + } + + /** + * Tests that a temporary topic remains available for reuse even after its initial + * subscribers have disconnected. + */ + public void testTemporaryTopicReused() throws Exception + { + final Connection conn = getConnection(); + final Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + final TemporaryTopic topic = session.createTemporaryTopic(); + assertNotNull(topic); + + final MessageProducer producer = session.createProducer(topic); + final MessageConsumer consumer1 = session.createConsumer(topic); + conn.start(); + producer.send(session.createTextMessage("message1")); + TextMessage tm = (TextMessage) consumer1.receive(2000); + assertNotNull("Message not received by first consumer", tm); + assertEquals("message1", tm.getText()); + consumer1.close(); + + final MessageConsumer consumer2 = session.createConsumer(topic); + conn.start(); + producer.send(session.createTextMessage("message2")); + tm = (TextMessage) consumer2.receive(2000); + assertNotNull("Message not received by second consumer", tm); + assertEquals("message2", tm.getText()); + consumer2.close(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/topic/TopicPublisherTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/topic/TopicPublisherTest.java new file mode 100644 index 0000000000..5fbbc7f67f --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/topic/TopicPublisherTest.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.test.unit.topic; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.MessageConsumer; +import javax.jms.TextMessage; +import javax.jms.TopicPublisher; +import javax.jms.TopicSession; + +/** + * @author Apache Software Foundation + */ +public class TopicPublisherTest extends QpidBrokerTestCase +{ + protected void setUp() throws Exception + { + super.setUp(); + } + + protected void tearDown() throws Exception + { + super.tearDown(); + } + + public void testUnidentifiedProducer() throws Exception + { + + AMQConnection con = (AMQConnection) getConnection("guest", "guest"); + AMQTopic topic = new AMQTopic(con,"MyTopic"); + TopicSession session1 = con.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE); + TopicPublisher publisher = session1.createPublisher(null); + MessageConsumer consumer1 = session1.createConsumer(topic); + con.start(); + publisher.publish(topic, session1.createTextMessage("Hello")); + TextMessage m = (TextMessage) consumer1.receive(2000); + assertNotNull(m); + try + { + publisher.publish(session1.createTextMessage("Goodbye")); + fail("Did not throw UnsupportedOperationException"); + } + catch (UnsupportedOperationException e) + { + // PASS + } + con.close(); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(TopicPublisherTest.class); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java new file mode 100644 index 0000000000..c2ea3a5695 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java @@ -0,0 +1,388 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.topic; + +import javax.jms.JMSException; +import javax.naming.NamingException; +import org.apache.qpid.AMQException; +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.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.InvalidDestinationException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.Topic; +import javax.jms.TopicPublisher; +import javax.jms.TopicSession; +import javax.jms.TopicSubscriber; +import org.apache.qpid.url.URLSyntaxException; + + +/** @author Apache Software Foundation */ +public class TopicSessionTest extends QpidBrokerTestCase +{ + public void testTopicSubscriptionUnsubscription() throws Exception + { + + AMQConnection con = (AMQConnection) getConnection("guest", "guest"); + AMQTopic topic = new AMQTopic(con.getDefaultTopicExchangeName(), "MyTopic"); + TopicSession session1 = con.createTopicSession(true, AMQSession.NO_ACKNOWLEDGE); + TopicSubscriber sub = session1.createDurableSubscriber(topic, "subscription0"); + TopicPublisher publisher = session1.createPublisher(topic); + + con.start(); + + TextMessage tm = session1.createTextMessage("Hello"); + publisher.publish(tm); + session1.commit(); + + tm = (TextMessage) sub.receive(2000); + assertNotNull(tm); + session1.commit(); + session1.unsubscribe("subscription0"); + + try + { + session1.unsubscribe("not a subscription"); + fail("expected InvalidDestinationException when unsubscribing from unknown subscription"); + } + catch (InvalidDestinationException e) + { + ; // PASS + } + catch (Exception e) + { + fail("expected InvalidDestinationException when unsubscribing from unknown subscription, got: " + e); + } + + con.close(); + } + + public void testSubscriptionNameReuseForDifferentTopicSingleConnection() throws Exception + { + subscriptionNameReuseForDifferentTopic(false); + } + + public void testSubscriptionNameReuseForDifferentTopicTwoConnections() throws Exception + { + subscriptionNameReuseForDifferentTopic(true); + } + + private void subscriptionNameReuseForDifferentTopic(boolean shutdown) throws Exception + { + AMQConnection con = (AMQConnection) getConnection("guest", "guest"); + AMQTopic topic = new AMQTopic(con, "MyTopic1" + String.valueOf(shutdown)); + AMQTopic topic2 = new AMQTopic(con, "MyOtherTopic1" + String.valueOf(shutdown)); + + TopicSession session1 = con.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE); + TopicSubscriber sub = session1.createDurableSubscriber(topic, "subscription0"); + TopicPublisher publisher = session1.createPublisher(null); + + con.start(); + + publisher.publish(topic, session1.createTextMessage("hello")); + session1.commit(); + TextMessage m = (TextMessage) sub.receive(2000); + assertNotNull(m); + session1.commit(); + + if (shutdown) + { + session1.close(); + con.close(); + con = (AMQConnection) getConnection("guest", "guest"); + con.start(); + session1 = con.createTopicSession(true, AMQSession.NO_ACKNOWLEDGE); + publisher = session1.createPublisher(null); + } + sub.close(); + TopicSubscriber sub2 = session1.createDurableSubscriber(topic2, "subscription0"); + publisher.publish(topic, session1.createTextMessage("hello")); + session1.commit(); + if (!shutdown) + { + m = (TextMessage) sub2.receive(2000); + assertNull(m); + session1.commit(); + } + publisher.publish(topic2, session1.createTextMessage("goodbye")); + session1.commit(); + m = (TextMessage) sub2.receive(2000); + assertNotNull(m); + assertEquals("goodbye", m.getText()); + session1.unsubscribe("subscription0"); + con.close(); + } + + public void testUnsubscriptionAfterConnectionClose() throws Exception + { + AMQConnection con1 = (AMQConnection) getClientConnection("guest", "guest", "clientid"); + AMQTopic topic = new AMQTopic(con1, "MyTopic3"); + + TopicSession session1 = con1.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE); + TopicPublisher publisher = session1.createPublisher(topic); + + AMQConnection con2 = (AMQConnection) getClientConnection("guest", "guest", "clientid"); + TopicSession session2 = con2.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE); + TopicSubscriber sub = session2.createDurableSubscriber(topic, "subscription0"); + + con2.start(); + + publisher.publish(session1.createTextMessage("Hello")); + session1.commit(); + TextMessage tm = (TextMessage) sub.receive(2000); + session2.commit(); + assertNotNull(tm); + con2.close(); + publisher.publish(session1.createTextMessage("Hello2")); + session1.commit(); + con2 = (AMQConnection) getClientConnection("guest", "guest", "clientid"); + session2 = con2.createTopicSession(true, AMQSession.NO_ACKNOWLEDGE); + sub = session2.createDurableSubscriber(topic, "subscription0"); + con2.start(); + tm = (TextMessage) sub.receive(2000); + session2.commit(); + assertNotNull(tm); + assertEquals("Hello2", tm.getText()); + session2.unsubscribe("subscription0"); + con1.close(); + con2.close(); + } + + public void testTextMessageCreation() throws Exception + { + + AMQConnection con = (AMQConnection) getConnection("guest", "guest"); + AMQTopic topic = new AMQTopic(con, "MyTopic4"); + TopicSession session1 = con.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE); + TopicPublisher publisher = session1.createPublisher(topic); + MessageConsumer consumer1 = session1.createConsumer(topic); + con.start(); + TextMessage tm = session1.createTextMessage("Hello"); + publisher.publish(tm); + session1.commit(); + tm = (TextMessage) consumer1.receive(10000L); + assertNotNull(tm); + String msgText = tm.getText(); + assertEquals("Hello", msgText); + tm = session1.createTextMessage(); + msgText = tm.getText(); + assertNull(msgText); + publisher.publish(tm); + session1.commit(); + tm = (TextMessage) consumer1.receive(10000L); + assertNotNull(tm); + session1.commit(); + msgText = tm.getText(); + assertNull(msgText); + tm.clearBody(); + tm.setText("Now we are not null"); + publisher.publish(tm); + session1.commit(); + tm = (TextMessage) consumer1.receive(2000); + assertNotNull(tm); + session1.commit(); + msgText = tm.getText(); + assertEquals("Now we are not null", msgText); + + tm = session1.createTextMessage(""); + msgText = tm.getText(); + assertEquals("Empty string not returned", "", msgText); + publisher.publish(tm); + session1.commit(); + tm = (TextMessage) consumer1.receive(2000); + session1.commit(); + assertNotNull(tm); + assertEquals("Empty string not returned", "", msgText); + con.close(); + } + + public void testNoLocal() throws Exception + { + + AMQConnection con = (AMQConnection) getConnection("guest", "guest"); + + AMQTopic topic = new AMQTopic(con, "testNoLocal"); + + noLocalTest(con, topic); + + + con.close(); + } + + + public void testNoLocalDirectExchange() throws Exception + { + + AMQConnection con = (AMQConnection) getConnection("guest", "guest"); + + AMQTopic topic = new AMQTopic("direct://amq.direct/testNoLocal/testNoLocal?routingkey='testNoLocal',exclusive='true',autodelete='true'"); + + noLocalTest(con, topic); + + + con.close(); + } + + + + public void testNoLocalFanoutExchange() throws Exception + { + + AMQConnection con = (AMQConnection) getConnection("guest", "guest"); + + AMQTopic topic = new AMQTopic("fanout://amq.fanout/testNoLocal/testNoLocal?routingkey='testNoLocal',exclusive='true',autodelete='true'"); + + noLocalTest(con, topic); + + con.close(); + } + + + private void noLocalTest(AMQConnection con, AMQTopic topic) + throws JMSException, URLSyntaxException, AMQException, NamingException + { + TopicSession session1 = con.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE); + TopicSubscriber noLocal = session1.createSubscriber(topic, "", true); + + TopicSubscriber select = session1.createSubscriber(topic, "Selector = 'select'", false); + TopicSubscriber normal = session1.createSubscriber(topic); + + + TopicPublisher publisher = session1.createPublisher(topic); + + con.start(); + TextMessage m; + TextMessage message; + + //send message to all consumers + publisher.publish(session1.createTextMessage("hello-new2")); + session1.commit(); + //test normal subscriber gets message + m = (TextMessage) normal.receive(1000); + assertNotNull(m); + session1.commit(); + + //test selector subscriber doesn't message + m = (TextMessage) select.receive(1000); + assertNull(m); + session1.commit(); + + //test nolocal subscriber doesn't message + m = (TextMessage) noLocal.receive(1000); + if (m != null) + { + _logger.info("Message:" + m.getText()); + } + assertNull(m); + + //send message to all consumers + message = session1.createTextMessage("hello2"); + message.setStringProperty("Selector", "select"); + + publisher.publish(message); + session1.commit(); + + //test normal subscriber gets message + m = (TextMessage) normal.receive(1000); + assertNotNull(m); + session1.commit(); + + //test selector subscriber does get message + m = (TextMessage) select.receive(1000); + assertNotNull(m); + session1.commit(); + + //test nolocal subscriber doesn't message + m = (TextMessage) noLocal.receive(100); + assertNull(m); + + AMQConnection con2 = (AMQConnection) getClientConnection("guest", "guest", "foo"); + TopicSession session2 = con2.createTopicSession(true, AMQSession.AUTO_ACKNOWLEDGE); + TopicPublisher publisher2 = session2.createPublisher(topic); + + + message = session2.createTextMessage("hello2"); + message.setStringProperty("Selector", "select"); + + publisher2.publish(message); + session2.commit(); + + //test normal subscriber gets message + m = (TextMessage) normal.receive(1000); + assertNotNull(m); + session1.commit(); + + //test selector subscriber does get message + m = (TextMessage) select.receive(1000); + assertNotNull(m); + session1.commit(); + + //test nolocal subscriber does message + m = (TextMessage) noLocal.receive(1000); + assertNotNull(m); + con2.close(); + } + + /** + * This tests was added to demonstrate QPID-3542. The Java Client when used with the CPP Broker was failing to + * ack messages received that did not match the selector. This meant the messages remained indefinitely on the Broker. + */ + public void testNonMatchingMessagesHandledCorrectly() throws Exception + { + final String topicName = getName(); + final String clientId = "clientId" + topicName; + final Connection con1 = getConnection(); + final Session session1 = con1.createSession(false, Session.AUTO_ACKNOWLEDGE); + final Topic topic1 = session1.createTopic(topicName); + final AMQQueue internalNameOnBroker = new AMQQueue("amq.topic", "clientid" + ":" + clientId); + + // Setup subscriber with selector + final TopicSubscriber subscriberWithSelector = session1.createDurableSubscriber(topic1, clientId, "Selector = 'select'", false); + final MessageProducer publisher = session1.createProducer(topic1); + + con1.start(); + + // Send non-matching message + final Message sentMessage = session1.createTextMessage("hello"); + sentMessage.setStringProperty("Selector", "nonMatch"); + publisher.send(sentMessage); + + // Try to consume non-message, expect this to fail. + final Message message1 = subscriberWithSelector.receive(1000); + assertNull("should not have received message", message1); + subscriberWithSelector.close(); + + session1.close(); + + // Now verify queue depth on broker. + final Session session2 = con1.createSession(false, Session.AUTO_ACKNOWLEDGE); + final long depth = ((AMQSession) session2).getQueueDepth(internalNameOnBroker); + assertEquals("Expected queue depth of zero", 0, depth); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java new file mode 100644 index 0000000000..4715831de6 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java @@ -0,0 +1,544 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.test.unit.transacted; + +import org.apache.qpid.client.RejectBehaviour; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +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 java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * This class tests a number of commits and roll back scenarios + * + * Assumptions; - Assumes empty Queue + * + * @see org.apache.qpid.test.client.RollbackOrderTest + */ +public class CommitRollbackTest extends QpidBrokerTestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(CommitRollbackTest.class); + private static final int POSITIVE_TIMEOUT = 2000; + private static final int NEGATIVE_TIMEOUT = 250; + + protected AMQConnection _conn; + private Session _session; + private MessageProducer _publisher; + private Session _pubSession; + private MessageConsumer _consumer; + private Queue _jmsQueue; + + private void newConnection() throws Exception + { + _logger.debug("calling newConnection()"); + _conn = (AMQConnection) getConnection(); + + _session = _conn.createSession(true, Session.SESSION_TRANSACTED); + + final String queueName = getTestQueueName(); + _jmsQueue = _session.createQueue(queueName); + _consumer = _session.createConsumer(_jmsQueue); + + _pubSession = _conn.createSession(true, Session.SESSION_TRANSACTED); + + _publisher = _pubSession.createProducer(_pubSession.createQueue(queueName)); + + _conn.start(); + } + + /** + * PUT a text message, disconnect before commit, confirm it is gone. + * + * @throws Exception On error + */ + public void testPutThenDisconnect() throws Exception + { + newConnection(); + + assertTrue("session is not transacted", _session.getTransacted()); + assertTrue("session is not transacted", _pubSession.getTransacted()); + + _logger.info("sending test message"); + String MESSAGE_TEXT = "testPutThenDisconnect"; + _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); + + _logger.info("reconnecting without commit"); + _conn.close(); + + newConnection(); + + _logger.info("receiving result"); + Message result = _consumer.receive(NEGATIVE_TIMEOUT); + + // commit to ensure message is removed from queue + _session.commit(); + + assertNull("test message was put and disconnected before commit, but is still present", result); + } + + + /** + * PUT a text message, rollback, confirm message is gone. The consumer is on the same connection but different + * session as producer + * + * @throws Exception On error + */ + public void testPutThenRollback() throws Exception + { + newConnection(); + + assertTrue("session is not transacted", _session.getTransacted()); + assertTrue("session is not transacted", _pubSession.getTransacted()); + + _logger.info("sending test message"); + String MESSAGE_TEXT = "testPutThenRollback"; + _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); + + _logger.info("rolling back"); + _pubSession.rollback(); + + _logger.info("receiving result"); + Message result = _consumer.receive(NEGATIVE_TIMEOUT); + + assertNull("test message was put and rolled back, but is still present", result); + } + + /** + * GET a text message, disconnect before commit, confirm it is still there. The consumer is on a new connection + * + * @throws Exception On error + */ + public void testGetThenDisconnect() throws Exception + { + newConnection(); + + assertTrue("session is not transacted", _session.getTransacted()); + assertTrue("session is not transacted", _pubSession.getTransacted()); + + _logger.info("sending test message"); + String MESSAGE_TEXT = "testGetThenDisconnect"; + _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); + + _pubSession.commit(); + + _logger.info("getting test message"); + + Message msg = _consumer.receive(POSITIVE_TIMEOUT); + assertNotNull("retrieved message is null", msg); + + _logger.info("closing connection"); + _conn.close(); + + newConnection(); + + _logger.info("receiving result"); + Message result = _consumer.receive(NEGATIVE_TIMEOUT); + + _session.commit(); + + assertNotNull("test message was consumed and disconnected before commit, but is gone", result); + assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) result).getText()); + } + + /** + * GET a text message, close consumer, disconnect before commit, confirm it is still there. The consumer is on the + * same connection but different session as producer + * + * @throws Exception On error + */ + public void testGetThenCloseDisconnect() throws Exception + { + newConnection(); + + assertTrue("session is not transacted", _session.getTransacted()); + assertTrue("session is not transacted", _pubSession.getTransacted()); + + _logger.info("sending test message"); + String MESSAGE_TEXT = "testGetThenCloseDisconnect"; + _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); + + _pubSession.commit(); + + _logger.info("getting test message"); + + Message msg = _consumer.receive(POSITIVE_TIMEOUT); + assertNotNull("retrieved message is null", msg); + assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) msg).getText()); + + _logger.info("reconnecting without commit"); + _consumer.close(); + _conn.close(); + + newConnection(); + + _logger.info("receiving result"); + Message result = _consumer.receive(POSITIVE_TIMEOUT); + + _session.commit(); + + assertNotNull("test message was consumed and disconnected before commit, but is gone", result); + assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) result).getText()); + } + + /** + * GET a text message, rollback, confirm it is still there. The consumer is on the same connection but differnt + * session to the producer + * + * @throws Exception On error + */ + public void testGetThenRollback() throws Exception + { + newConnection(); + + assertTrue("session is not transacted", _session.getTransacted()); + assertTrue("session is not transacted", _pubSession.getTransacted()); + + _logger.info("sending test message"); + String MESSAGE_TEXT = "testGetThenRollback"; + _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); + + _pubSession.commit(); + + _logger.info("getting test message"); + + Message msg = _consumer.receive(POSITIVE_TIMEOUT); + + assertNotNull("retrieved message is null", msg); + assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) msg).getText()); + + _logger.info("rolling back"); + + _session.rollback(); + + _logger.info("receiving result"); + + Message result = _consumer.receive(POSITIVE_TIMEOUT); + + _session.commit(); + assertNotNull("test message was consumed and rolled back, but is gone", result); + assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) result).getText()); + assertTrue("Message is not marked as redelivered", result.getJMSRedelivered()); + } + + /** + * GET a text message, close message producer, rollback, confirm it is still there. The consumer is on the same + * connection but different session as producer + * + * @throws Exception On error + */ + public void testGetThenCloseRollback() throws Exception + { + newConnection(); + + assertTrue("session is not transacted", _session.getTransacted()); + assertTrue("session is not transacted", _pubSession.getTransacted()); + + _logger.info("sending test message"); + String MESSAGE_TEXT = "testGetThenCloseRollback"; + _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); + + _pubSession.commit(); + + _logger.info("getting test message"); + + Message msg = _consumer.receive(POSITIVE_TIMEOUT); + + assertNotNull("retrieved message is null", msg); + assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) msg).getText()); + + _logger.info("Closing consumer"); + _consumer.close(); + + _logger.info("rolling back"); + _session.rollback(); + + _logger.info("receiving result"); + + _consumer = _session.createConsumer(_jmsQueue); + + Message result = _consumer.receive(POSITIVE_TIMEOUT); + + _session.commit(); + assertNotNull("test message was consumed and rolled back, but is gone", result); + assertEquals("test message was correct message", MESSAGE_TEXT, ((TextMessage) result).getText()); + assertTrue("Message is not marked as redelivered", result.getJMSRedelivered()); + } + + /** + * This test sends two messages receives one of them but doesn't ack it. + * The consumer is then closed + * the first message should be returned as redelivered. + * the second message should be delivered normally. + * @throws Exception + */ + public void testSend2ThenCloseAfter1andTryAgain() throws Exception + { + newConnection(); + + assertTrue("session is not transacted", _session.getTransacted()); + assertTrue("session is not transacted", _pubSession.getTransacted()); + + _logger.info("sending two test messages"); + _publisher.send(_pubSession.createTextMessage("1")); + _publisher.send(_pubSession.createTextMessage("2")); + _pubSession.commit(); + + _logger.info("getting test message"); + Message result = _consumer.receive(POSITIVE_TIMEOUT); + + assertNotNull("Message received should not be null", result); + assertEquals("1", ((TextMessage) result).getText()); + assertTrue("Message is marked as redelivered" + result, !result.getJMSRedelivered()); + + _logger.info("Closing Consumer"); + + _consumer.close(); + + _logger.info("Creating New consumer"); + _consumer = _session.createConsumer(_jmsQueue); + + _logger.info("receiving result"); + + + // Message 2 may be marked as redelivered if it was prefetched. + result = _consumer.receive(POSITIVE_TIMEOUT); + assertNotNull("Second message was not consumed, but is gone", result); + + // The first message back will be 2, message 1 has been received but not committed + // Closing the consumer does not commit the session. + + // if this is message 1 then it should be marked as redelivered + if("1".equals(((TextMessage) result).getText())) + { + fail("First message was received again"); + } + + result = _consumer.receive(NEGATIVE_TIMEOUT); + assertNull("test message should be null:" + result, result); + + _session.commit(); + } + + public void testPutThenRollbackThenGet() throws Exception + { + newConnection(); + + assertTrue("session is not transacted", _session.getTransacted()); + assertTrue("session is not transacted", _pubSession.getTransacted()); + + _logger.info("sending test message"); + String MESSAGE_TEXT = "testPutThenRollbackThenGet"; + + _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); + _pubSession.commit(); + + assertNotNull(_consumer.receive(POSITIVE_TIMEOUT)); + + _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); + + _logger.info("rolling back"); + _pubSession.rollback(); + + _logger.info("receiving result"); + Message result = _consumer.receive(NEGATIVE_TIMEOUT); + assertNull("test message was put and rolled back, but is still present", result); + + _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); + + _pubSession.commit(); + + assertNotNull(_consumer.receive(POSITIVE_TIMEOUT)); + + _session.commit(); + } + + /** + * Qpid-1163 + * Check that when commit is called inside onMessage then + * the last message is nor redelivered. + * + * @throws Exception + */ + public void testCommitWithinOnMessage() throws Exception + { + newConnection(); + + Queue queue = (Queue) getInitialContext().lookup("queue"); + // create a consumer + MessageConsumer cons = _session.createConsumer(queue); + MessageProducer prod = _session.createProducer(queue); + Message message = _session.createTextMessage("Message"); + message.setJMSCorrelationID("m1"); + prod.send(message); + _session.commit(); + _logger.info("Sent message to queue"); + CountDownLatch cd = new CountDownLatch(1); + cons.setMessageListener(new CommitWithinOnMessageListener(cd)); + _conn.start(); + cd.await(30, TimeUnit.SECONDS); + if( cd.getCount() > 0 ) + { + fail("Did not received message"); + } + // Check that the message has been dequeued + _session.close(); + _conn.close(); + _conn = (AMQConnection) getConnection(); + _conn.start(); + Session session = _conn.createSession(false, Session.CLIENT_ACKNOWLEDGE); + cons = session.createConsumer(queue); + message = cons.receiveNoWait(); + if(message != null) + { + if(message.getJMSCorrelationID().equals("m1")) + { + fail("received message twice"); + } + else + { + fail("queue should have been empty, received message: " + message); + } + } + } + + /** + * This test ensures that after exhausting credit (prefetch), a {@link Session#rollback()} successfully + * restores credit and allows the same messages to be re-received. + */ + public void testRollbackSessionAfterCreditExhausted() throws Exception + { + final int maxPrefetch= 5; + + // We send more messages than prefetch size. This ensure that if the 0-10 client were to + // complete the message commands before the rollback command is sent, the broker would + // send additional messages utilising the release credit. This problem would manifest itself + // as an incorrect message (or no message at all) being received at the end of the test. + + final int numMessages = maxPrefetch * 2; + + setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, String.valueOf(maxPrefetch)); + + newConnection(); + + assertEquals("Prefetch not reset", maxPrefetch, ((AMQSession)_session).getDefaultPrefetch()); + + assertTrue("session is not transacted", _session.getTransacted()); + assertTrue("session is not transacted", _pubSession.getTransacted()); + + sendMessage(_pubSession, _publisher.getDestination(), numMessages); + _pubSession.commit(); + + for (int i=0 ;i< maxPrefetch; i++) + { + final Message message = _consumer.receive(POSITIVE_TIMEOUT); + assertNotNull("Received:" + i, message); + assertEquals("Unexpected message received", i, message.getIntProperty(INDEX)); + } + + _logger.info("Rolling back"); + _session.rollback(); + + _logger.info("Receiving messages"); + + Message result = _consumer.receive(POSITIVE_TIMEOUT);; + assertNotNull("Message expected", result); + // Expect the first message + assertEquals("Unexpected message received", 0, result.getIntProperty(INDEX)); + } + + private class CommitWithinOnMessageListener implements MessageListener + { + private CountDownLatch _cd; + private CommitWithinOnMessageListener(CountDownLatch cd) + { + _cd = cd; + } + public void onMessage(Message message) + { + try + { + _logger.info("received message " + message); + assertEquals("Wrong message received", message.getJMSCorrelationID(), "m1"); + _logger.info("commit session"); + _session.commit(); + _cd.countDown(); + } + catch (JMSException e) + { + _logger.error("OnMessage error",e); + } + } + } + + + public void testResendUnseenMessagesAfterRollback() throws Exception + { + resendAfterRollback(); + } + + public void testResendUnseenMessagesAfterRollbackWithServerReject() throws Exception + { + setTestSystemProperty(ClientProperties.REJECT_BEHAVIOUR_PROP_NAME, RejectBehaviour.SERVER.toString()); + resendAfterRollback(); + } + + private void resendAfterRollback() throws Exception + { + newConnection(); + + assertTrue("session is not transacted", _session.getTransacted()); + assertTrue("session is not transacted", _pubSession.getTransacted()); + + _logger.info("sending test message"); + String MESSAGE_TEXT = "message text"; + + _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); + _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); + + _pubSession.commit(); + + assertNotNull("two messages were sent, but none has been received", _consumer.receive(POSITIVE_TIMEOUT)); + + _session.rollback(); + + _logger.info("receiving result"); + + assertNotNull("two messages were sent, but none has been received", _consumer.receive(POSITIVE_TIMEOUT)); + assertNotNull("two messages were sent, but only one has been received", _consumer.receive(POSITIVE_TIMEOUT)); + assertNull("Only two messages were sent, but more have been received", _consumer.receive(NEGATIVE_TIMEOUT)); + + _session.commit(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/TransactedTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/TransactedTest.java new file mode 100644 index 0000000000..78c76602c5 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/TransactedTest.java @@ -0,0 +1,389 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.transacted; + + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.jms.Session; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.Connection; +import javax.jms.IllegalStateException; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.TextMessage; + +public class TransactedTest extends QpidBrokerTestCase +{ + private AMQQueue queue1; + + private AMQConnection con; + private Session session; + private MessageConsumer consumer1; + private MessageProducer producer2; + + private AMQConnection prepCon; + private Session prepSession; + private MessageProducer prepProducer1; + + private AMQConnection testCon; + private Session testSession; + private MessageConsumer testConsumer1; + private MessageConsumer testConsumer2; + private static final Logger _logger = LoggerFactory.getLogger(TransactedTest.class); + + protected void setUp() throws Exception + { + try + { + super.setUp(); + _logger.info("Create Connection"); + con = (AMQConnection) getConnection("guest", "guest"); + _logger.info("Create Session"); + session = con.createSession(true, Session.SESSION_TRANSACTED); + _logger.info("Create Q1"); + queue1 = new AMQQueue(session.getDefaultQueueExchangeName(), new AMQShortString("Q1"), + new AMQShortString("Q1"), false, true); + _logger.info("Create Q2"); + AMQQueue queue2 = new AMQQueue(session.getDefaultQueueExchangeName(), new AMQShortString("Q2"), false); + + _logger.info("Create Consumer of Q1"); + consumer1 = session.createConsumer(queue1); + // Dummy just to create the queue. + _logger.info("Create Consumer of Q2"); + MessageConsumer consumer2 = session.createConsumer(queue2); + _logger.info("Close Consumer of Q2"); + consumer2.close(); + + _logger.info("Create producer to Q2"); + producer2 = session.createProducer(queue2); + + _logger.info("Start Connection"); + con.start(); + + _logger.info("Create prep connection"); + prepCon = (AMQConnection) getConnection("guest", "guest"); + + _logger.info("Create prep session"); + prepSession = prepCon.createSession(false, AMQSession.AUTO_ACKNOWLEDGE); + + _logger.info("Create prep producer to Q1"); + prepProducer1 = prepSession.createProducer(queue1); + + _logger.info("Create prep connection start"); + prepCon.start(); + + _logger.info("Create test connection"); + testCon = (AMQConnection) getConnection("guest", "guest"); + _logger.info("Create test session"); + testSession = testCon.createSession(false, AMQSession.AUTO_ACKNOWLEDGE); + _logger.info("Create test consumer of q2"); + testConsumer2 = testSession.createConsumer(queue2); + } + catch (Exception e) + { + _logger.error("setup error",e); + stopBroker(); + throw e; + } + } + + protected void tearDown() throws Exception + { + try + { + _logger.info("Close connection"); + con.close(); + _logger.info("Close test connection"); + testCon.close(); + _logger.info("Close prep connection"); + prepCon.close(); + } + catch (Exception e) + { + _logger.error("tear down error",e); + } + finally + { + super.tearDown(); + } + } + + public void testCommit() throws Exception + { + _logger.info("Send prep A"); + prepProducer1.send(prepSession.createTextMessage("A")); + _logger.info("Send prep B"); + prepProducer1.send(prepSession.createTextMessage("B")); + _logger.info("Send prep C"); + prepProducer1.send(prepSession.createTextMessage("C")); + + // send and receive some messages + _logger.info("Send X to Q2"); + producer2.send(session.createTextMessage("X")); + _logger.info("Send Y to Q2"); + producer2.send(session.createTextMessage("Y")); + _logger.info("Send Z to Q2"); + producer2.send(session.createTextMessage("Z")); + + _logger.info("Read A from Q1"); + expect("A", consumer1.receive(1000)); + _logger.info("Read B from Q1"); + expect("B", consumer1.receive(1000)); + _logger.info("Read C from Q1"); + expect("C", consumer1.receive(1000)); + + // commit + _logger.info("session commit"); + session.commit(); + _logger.info("Start test Connection"); + testCon.start(); + + // ensure sent messages can be received and received messages are gone + _logger.info("Read X from Q2"); + expect("X", testConsumer2.receive(1000)); + _logger.info("Read Y from Q2"); + expect("Y", testConsumer2.receive(1000)); + _logger.info("Read Z from Q2"); + expect("Z", testConsumer2.receive(1000)); + + _logger.info("create test session on Q1"); + testConsumer1 = testSession.createConsumer(queue1); + _logger.info("Read null from Q1"); + assertTrue(null == testConsumer1.receive(1000)); + _logger.info("Read null from Q2"); + assertTrue(null == testConsumer2.receive(1000)); + } + + public void testRollback() throws Exception + { + // add some messages + _logger.info("Send prep RB_A"); + prepProducer1.send(prepSession.createTextMessage("RB_A")); + _logger.info("Send prep RB_B"); + prepProducer1.send(prepSession.createTextMessage("RB_B")); + _logger.info("Send prep RB_C"); + prepProducer1.send(prepSession.createTextMessage("RB_C")); + + _logger.info("Sending RB_X RB_Y RB_Z"); + producer2.send(session.createTextMessage("RB_X")); + producer2.send(session.createTextMessage("RB_Y")); + producer2.send(session.createTextMessage("RB_Z")); + _logger.info("Receiving RB_A RB_B"); + expect("RB_A", consumer1.receive(1000)); + expect("RB_B", consumer1.receive(1000)); + // Don't consume 'RB_C' leave it in the prefetch cache to ensure rollback removes it. + // Quick sleep to ensure 'RB_C' gets pre-fetched + Thread.sleep(500); + + // rollback + _logger.info("rollback"); + session.rollback(); + + _logger.info("Receiving RB_A RB_B RB_C"); + // ensure sent messages are not visible and received messages are requeued + expect("RB_A", consumer1.receive(1000), true); + expect("RB_B", consumer1.receive(1000), true); + expect("RB_C", consumer1.receive(1000), isBroker010()?false:true); + _logger.info("Starting new connection"); + testCon.start(); + testConsumer1 = testSession.createConsumer(queue1); + _logger.info("Testing we have no messages left"); + assertTrue(null == testConsumer1.receive(1000)); + assertTrue(null == testConsumer2.receive(1000)); + + session.commit(); + + _logger.info("Testing we have no messages left after commit"); + assertTrue(null == testConsumer1.receive(1000)); + assertTrue(null == testConsumer2.receive(1000)); + } + + public void testResendsMsgsAfterSessionClose() throws Exception + { + AMQConnection con = (AMQConnection) getConnection("guest", "guest"); + + Session consumerSession = con.createSession(true, Session.SESSION_TRANSACTED); + AMQQueue queue3 = new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("Q3"), false); + MessageConsumer consumer = consumerSession.createConsumer(queue3); + + AMQConnection con2 = (AMQConnection) getConnection("guest", "guest"); + Session producerSession = con2.createSession(true, Session.SESSION_TRANSACTED); + MessageProducer producer = producerSession.createProducer(queue3); + + _logger.info("Sending four messages"); + producer.send(producerSession.createTextMessage("msg1")); + producer.send(producerSession.createTextMessage("msg2")); + producer.send(producerSession.createTextMessage("msg3")); + producer.send(producerSession.createTextMessage("msg4")); + + producerSession.commit(); + + _logger.info("Starting connection"); + con.start(); + TextMessage tm = (TextMessage) consumer.receive(); + assertNotNull(tm); + assertEquals("msg1", tm.getText()); + + consumerSession.commit(); + + _logger.info("Received and committed first message"); + tm = (TextMessage) consumer.receive(1000); + assertNotNull(tm); + assertEquals("msg2", tm.getText()); + + tm = (TextMessage) consumer.receive(1000); + assertNotNull(tm); + assertEquals("msg3", tm.getText()); + + tm = (TextMessage) consumer.receive(1000); + assertNotNull(tm); + assertEquals("msg4", tm.getText()); + + _logger.info("Received all four messages. Closing connection with three outstanding messages"); + + consumerSession.close(); + + consumerSession = con.createSession(true, Session.SESSION_TRANSACTED); + + consumer = consumerSession.createConsumer(queue3); + + // no ack for last three messages so when I call recover I expect to get three messages back + tm = (TextMessage) consumer.receive(3000); + assertNotNull(tm); + assertEquals("msg2", tm.getText()); + assertTrue("Message is not redelivered", tm.getJMSRedelivered()); + + tm = (TextMessage) consumer.receive(3000); + assertNotNull(tm); + assertEquals("msg3", tm.getText()); + assertTrue("Message is not redelivered", tm.getJMSRedelivered()); + + tm = (TextMessage) consumer.receive(3000); + assertNotNull(tm); + assertEquals("msg4", tm.getText()); + assertTrue("Message is not redelivered", tm.getJMSRedelivered()); + + _logger.info("Received redelivery of three messages. Committing"); + + consumerSession.commit(); + + _logger.info("Called commit"); + + tm = (TextMessage) consumer.receive(1000); + assertNull(tm); + + _logger.info("No messages redelivered as is expected"); + + con.close(); + con2.close(); + } + + public void testCommitOnClosedConnection() throws Exception + { + Connection connnection = getConnection(); + javax.jms.Session transactedSession = connnection.createSession(true, Session.SESSION_TRANSACTED); + connnection.close(); + try + { + transactedSession.commit(); + fail("Commit on closed connection should throw IllegalStateException!"); + } + catch(IllegalStateException e) + { + // passed + } + } + + public void testCommitOnClosedSession() throws Exception + { + Connection connnection = getConnection(); + javax.jms.Session transactedSession = connnection.createSession(true, Session.SESSION_TRANSACTED); + transactedSession.close(); + try + { + transactedSession.commit(); + fail("Commit on closed session should throw IllegalStateException!"); + } + catch(IllegalStateException e) + { + // passed + } + } + + public void testRollbackOnClosedSession() throws Exception + { + Connection connnection = getConnection(); + javax.jms.Session transactedSession = connnection.createSession(true, Session.SESSION_TRANSACTED); + transactedSession.close(); + try + { + transactedSession.rollback(); + fail("Rollback on closed session should throw IllegalStateException!"); + } + catch(IllegalStateException e) + { + // passed + } + } + + public void testGetTransactedOnClosedSession() throws Exception + { + Connection connnection = getConnection(); + javax.jms.Session transactedSession = connnection.createSession(true, Session.SESSION_TRANSACTED); + transactedSession.close(); + try + { + transactedSession.getTransacted(); + fail("According to Sun TCK invocation of Session#getTransacted on closed session should throw IllegalStateException!"); + } + catch(IllegalStateException e) + { + // passed + } + } + + private void expect(String text, Message msg) throws JMSException + { + expect(text, msg, false); + } + + private void expect(String text, Message msg, boolean requeued) throws JMSException + { + assertNotNull("Message should not be null", msg); + assertTrue("Message should be a text message", msg instanceof TextMessage); + assertEquals("Message content does not match expected", text, ((TextMessage) msg).getText()); + assertEquals("Message should " + (requeued ? "" : "not") + " be requeued", requeued, msg.getJMSRedelivered()); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(TransactedTest.class); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutDisabledTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutDisabledTest.java new file mode 100644 index 0000000000..e37c6cf54b --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutDisabledTest.java @@ -0,0 +1,77 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.transacted; + +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +/** + * This verifies that the default behaviour is not to time out transactions. + */ +public class TransactionTimeoutDisabledTest extends TransactionTimeoutTestCase +{ + @Override + protected void configure() throws Exception + { + // Setup housekeeping every second + TestBrokerConfiguration brokerConfiguration = getBrokerConfiguration(); + setTestSystemProperty("virtualhost.housekeepingCheckPeriod", "100"); + + // No transaction timeout configuration. + } + + public void testProducerIdleCommit() throws Exception + { + try + { + send(5, 0); + + sleep(2.0f); + + _psession.commit(); + } + catch (Exception e) + { + fail("Should have succeeded"); + } + + assertEquals("Listener should not have received exception", 0, getNumberOfDeliveredExceptions()); + + monitor(0, 0); + } + + public void testProducerOpenCommit() throws Exception + { + try + { + send(5, 0.3f); + + _psession.commit(); + } + catch (Exception e) + { + fail("Should have succeeded"); + } + + assertEquals("Listener should not have received exception", 0, getNumberOfDeliveredExceptions()); + + monitor(0, 0); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTest.java new file mode 100644 index 0000000000..b84e03972d --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTest.java @@ -0,0 +1,350 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.transacted; + +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Queue; + +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +/** + * This tests the behaviour of transactional sessions when the {@code transactionTimeout} configuration + * is set for a virtual host. + * + * A producer that is idle for too long or open for too long will have its connection/session(0-10) closed and + * any further operations will fail with a 408 resource timeout exception. Consumers will not + * be affected by the transaction timeout configuration. + */ +public class TransactionTimeoutTest extends TransactionTimeoutTestCase +{ + + protected void configure() throws Exception + { + // switch off connection close in order to test timeout on publishing of unroutable messages + getBrokerConfiguration().setBrokerAttribute(Broker.CONNECTION_CLOSE_WHEN_NO_ROUTE, false); + + // Setup housekeeping every 100ms + TestBrokerConfiguration brokerConfiguration = getBrokerConfiguration(); + setTestSystemProperty("virtualhost.housekeepingCheckPeriod","100"); + + if (getName().contains("ProducerIdle")) + { + setTestSystemProperty("virtualhost.storeTransactionOpenTimeoutWarn", "0"); + setTestSystemProperty("virtualhost.storeTransactionOpenTimeoutClose", "0"); + setTestSystemProperty("virtualhost.storeTransactionIdleTimeoutWarn", "500"); + setTestSystemProperty("virtualhost.storeTransactionIdleTimeoutClose", "1500"); + } + else if (getName().contains("ProducerOpen")) + { + setTestSystemProperty("virtualhost.storeTransactionOpenTimeoutWarn", "1000"); + setTestSystemProperty("virtualhost.storeTransactionOpenTimeoutClose", "2000"); + setTestSystemProperty("virtualhost.storeTransactionIdleTimeoutWarn", "0"); + setTestSystemProperty("virtualhost.storeTransactionIdleTimeoutClose", "0"); + } + else + { + setTestSystemProperty("virtualhost.storeTransactionOpenTimeoutWarn", "1000"); + setTestSystemProperty("virtualhost.storeTransactionOpenTimeoutClose", "2000"); + setTestSystemProperty("virtualhost.storeTransactionIdleTimeoutWarn", "500"); + setTestSystemProperty("virtualhost.storeTransactionIdleTimeoutClose", "1500"); + } + } + + public void testProducerIdle() throws Exception + { + sleep(2.0f); + + _psession.commit(); + + assertEquals("Listener should not have received exception", 0, getNumberOfDeliveredExceptions()); + + monitor(0, 0); + } + + public void testProducerIdleCommit() throws Exception + { + send(5, 0); + // Idle for more than idleClose to generate idle-warns and cause a close. + sleep(2.0f); + + try + { + _psession.commit(); + fail("Exception not thrown"); + } + catch (Exception e) + { + _exception = e; + } + + monitor(10, 0); + + check(IDLE); + } + + public void testProducerIdleCommitTwice() throws Exception + { + send(5, 0); + // Idle for less than idleClose to generate idle-warns + sleep(1.0f); + + _psession.commit(); + + send(5, 0); + // Now idle for more than idleClose to generate more idle-warns and cause a close. + sleep(2.0f); + + try + { + _psession.commit(); + fail("Exception not thrown"); + } + catch (Exception e) + { + _exception = e; + } + + monitor(15, 0); + + check(IDLE); + } + + public void testProducerIdleRollback() throws Exception + { + send(5, 0); + // Now idle for more than idleClose to generate more idle-warns and cause a close. + sleep(2.0f); + try + { + _psession.rollback(); + fail("Exception not thrown"); + } + catch (Exception e) + { + _exception = e; + } + + monitor(10, 0); + + check(IDLE); + } + + public void testProducerIdleRollbackTwice() throws Exception + { + send(5, 0); + // Idle for less than idleClose to generate idle-warns + sleep(1.0f); + _psession.rollback(); + send(5, 0); + // Now idle for more than idleClose to generate more idle-warns and cause a close. + sleep(2.0f); + try + { + _psession.rollback(); + fail("should fail"); + } + catch (Exception e) + { + _exception = e; + } + + monitor(15, 0); + + check(IDLE); + } + + public void testProducerOpenCommit() throws Exception + { + try + { + // Sleep between sends to cause open warns and then cause a close. + send(6, 0.5f); + _psession.commit(); + fail("Exception not thrown"); + } + catch (Exception e) + { + _exception = e; + } + + monitor(0, 10); + + check(OPEN); + } + + public void testProducerOpenCommitTwice() throws Exception + { + send(5, 0); + sleep(1.0f); + _psession.commit(); + + try + { + // Now sleep between sends to cause open warns and then cause a close. + send(6, 0.5f); + _psession.commit(); + fail("Exception not thrown"); + } + catch (Exception e) + { + _exception = e; + } + + monitor(0, 10); + + check(OPEN); + } + + public void testConsumerCommitClose() throws Exception + { + send(1, 0); + + _psession.commit(); + + expect(1, 0); + + _csession.commit(); + + sleep(3.0f); + + _csession.close(); + + assertEquals("Listener should not have received exception", 0, getNumberOfDeliveredExceptions()); + + monitor(0, 0); + } + + public void testConsumerIdleReceiveCommit() throws Exception + { + send(1, 0); + + _psession.commit(); + + sleep(2.0f); + + expect(1, 0); + + sleep(2.0f); + + _csession.commit(); + + assertEquals("Listener should not have received exception", 0, getNumberOfDeliveredExceptions()); + + monitor(0, 0); + } + + public void testConsumerIdleCommit() throws Exception + { + send(1, 0); + + _psession.commit(); + + expect(1, 0); + + sleep(2.0f); + + _csession.commit(); + + assertEquals("Listener should not have received exception", 0, getNumberOfDeliveredExceptions()); + + monitor(0, 0); + } + + public void testConsumerIdleRollback() throws Exception + { + send(1, 0); + + _psession.commit(); + + expect(1, 0); + + sleep(2.0f); + + _csession.rollback(); + + assertEquals("Listener should not have received exception", 0, getNumberOfDeliveredExceptions()); + + monitor(0, 0); + } + + public void testConsumerOpenCommit() throws Exception + { + send(1, 0); + + _psession.commit(); + + sleep(3.0f); + + _csession.commit(); + + assertEquals("Listener should not have received exception", 0, getNumberOfDeliveredExceptions()); + + monitor(0, 0); + } + + public void testConsumerOpenRollback() throws Exception + { + send(1, 0); + + _psession.commit(); + + sleep(3.0f); + + _csession.rollback(); + + assertEquals("Listener should not have received exception", 0, getNumberOfDeliveredExceptions()); + + monitor(0, 0); + } + + /** + * Tests that sending an unroutable persistent message does not result in a long running store transaction [warning]. + */ + public void testTransactionCommittedOnNonRoutableQueuePersistentMessage() throws Exception + { + checkTransactionCommittedOnNonRoutableQueueMessage(DeliveryMode.PERSISTENT); + } + + /** + * Tests that sending an unroutable transient message does not result in a long running store transaction [warning]. + */ + public void testTransactionCommittedOnNonRoutableQueueTransientMessage() throws Exception + { + checkTransactionCommittedOnNonRoutableQueueMessage(DeliveryMode.NON_PERSISTENT); + } + + private void checkTransactionCommittedOnNonRoutableQueueMessage(int deliveryMode) throws JMSException, Exception + { + Queue nonExisting = _psession.createQueue(getTestQueueName() + System.currentTimeMillis()); + MessageProducer producer = _psession.createProducer(nonExisting); + Message message = _psession.createMessage(); + producer.send(message, deliveryMode, Message.DEFAULT_PRIORITY, Message.DEFAULT_TIME_TO_LIVE); + _psession.commit(); + + // give time to house keeping thread to log messages + sleep(3f); + monitor(0, 0); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTestCase.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTestCase.java new file mode 100644 index 0000000000..98fe29f826 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/transacted/TransactionTimeoutTestCase.java @@ -0,0 +1,244 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.transacted; + +import junit.framework.TestCase; + +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.util.LogMonitor; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * The {@link TestCase} for transaction timeout testing. + */ +public abstract class TransactionTimeoutTestCase extends QpidBrokerTestCase implements ExceptionListener +{ + private static final int ALERT_MESSAGE_TOLERANCE = 6; + public static final String VIRTUALHOST = "test"; + public static final String TEXT = "0123456789abcdefghiforgettherest"; + public static final String CHN_OPEN_TXN = "CHN-1007"; + public static final String CHN_IDLE_TXN = "CHN-1008"; + public static final String IDLE = "Idle"; + public static final String OPEN = "Open"; + + protected LogMonitor _monitor; + protected Connection _con; + protected Session _psession, _csession; + protected Queue _queue; + protected MessageConsumer _consumer; + protected MessageProducer _producer; + protected Exception _exception; + + private final CountDownLatch _exceptionListenerLatch = new CountDownLatch(1); + private final AtomicInteger _exceptionCount = new AtomicInteger(0); + private volatile AMQConstant _linkedExceptionCode; + private volatile String _linkedExceptionMessage; + + /** + * Subclasses must implement this to configure transaction timeout parameters. + */ + protected abstract void configure() throws Exception; + + @Override + protected void setUp() throws Exception + { + // Configure timeouts + configure(); + + // Monitor log file + _monitor = new LogMonitor(_outputFile); + + // Start broker + super.setUp(); + + // Connect to broker + setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, String.valueOf(1)); + _con = getConnection(); + _con.setExceptionListener(this); + _con.start(); + + // Create queue + Session qsession = _con.createSession(true, Session.SESSION_TRANSACTED); + _queue = qsession.createQueue(getTestQueueName()); + qsession.close(); + + // Create producer and consumer + producer(); + consumer(); + } + + /** + * Create a transacted persistent message producer session. + */ + protected void producer() throws Exception + { + _psession = _con.createSession(true, Session.SESSION_TRANSACTED); + _producer = _psession.createProducer(_queue); + _producer.setDeliveryMode(DeliveryMode.PERSISTENT); + } + + /** + * Create a transacted message consumer session. + */ + protected void consumer() throws Exception + { + _csession = _con.createSession(true, Session.SESSION_TRANSACTED); + _consumer = _csession.createConsumer(_queue); + } + + /** + * Send a number of messages to the queue, optionally pausing after each. + * + * Need to sync to ensure that the Broker has received the message(s) in order + * the test and broker start timing the idle transaction from the same point in time. + */ + protected void send(int count, float delay) throws Exception + { + for (int i = 0; i < count; i++) + { + sleep(delay); + Message msg = _psession.createTextMessage(TEXT); + msg.setIntProperty("i", i); + _producer.send(msg); + } + + ((AMQSession)_psession).sync(); + } + + /** + * Sleep for a number of seconds. + */ + protected void sleep(float seconds) throws Exception + { + try + { + Thread.sleep((long) (seconds * 1000.0f)); + } + catch (InterruptedException ie) + { + throw new RuntimeException("Interrupted"); + } + } + + /** + * Check for idle and open messages. + * + * Either exactly zero messages, or +-2 error accepted around the specified number. + */ + protected void monitor(int idle, int open) throws Exception + { + List idleMsgs = _monitor.findMatches(CHN_IDLE_TXN); + List openMsgs = _monitor.findMatches(CHN_OPEN_TXN); + + String idleErr = "Expected " + idle + " but found " + idleMsgs.size() + " txn idle messages"; + String openErr = "Expected " + open + " but found " + openMsgs.size() + " txn open messages"; + + if (idle == 0) + { + assertTrue(idleErr, idleMsgs.isEmpty()); + } + else + { + assertTrue(idleErr, idleMsgs.size() >= idle - ALERT_MESSAGE_TOLERANCE && idleMsgs.size() <= idle + ALERT_MESSAGE_TOLERANCE); + } + + if (open == 0) + { + assertTrue(openErr, openMsgs.isEmpty()); + } + else + { + assertTrue(openErr, openMsgs.size() >= open - ALERT_MESSAGE_TOLERANCE && openMsgs.size() <= open + ALERT_MESSAGE_TOLERANCE); + } + } + + /** + * Receive a number of messages, optionally pausing after each. + */ + protected void expect(int count, float delay) throws Exception + { + for (int i = 0; i < count; i++) + { + sleep(delay); + Message msg = _consumer.receive(1000); + assertNotNull("Message should not be null", msg); + assertTrue("Message should be a text message", msg instanceof TextMessage); + assertEquals("Message content does not match expected", TEXT, ((TextMessage) msg).getText()); + assertEquals("Message order is incorrect", i, msg.getIntProperty("i")); + } + } + + /** + * Checks that the correct exception was thrown and was received + * by the listener with a 506 error code. + */ + protected void check(String reason) throws InterruptedException + { + assertNotNull("Should have thrown exception to client", _exception); + + assertTrue("Should have caught exception in listener", _exceptionListenerLatch.await(1, TimeUnit.SECONDS)); + assertNotNull("Linked exception message should not be null", _linkedExceptionMessage); + assertTrue("Linked exception message '" + _linkedExceptionMessage + "' should contain '" + reason + "'", + _linkedExceptionMessage.contains(reason + " transaction timed out")); + assertNotNull("Linked exception should have an error code", _linkedExceptionCode); + assertEquals("Linked exception error code should be 506", AMQConstant.RESOURCE_ERROR, _linkedExceptionCode); + } + + /** @see javax.jms.ExceptionListener#onException(javax.jms.JMSException) */ + @Override + public void onException(JMSException jmse) + { + if (jmse.getLinkedException() != null) + { + _linkedExceptionMessage = jmse.getLinkedException().getMessage(); + } + + if (jmse.getLinkedException() instanceof AMQException) + { + _linkedExceptionCode = ((AMQException) jmse.getLinkedException()).getErrorCode(); + } + _exceptionCount.incrementAndGet(); + _exceptionListenerLatch.countDown(); + } + + protected int getNumberOfDeliveredExceptions() + { + return _exceptionCount.get(); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/xa/AbstractXATestCase.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/xa/AbstractXATestCase.java new file mode 100644 index 0000000000..92df1bd331 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/xa/AbstractXATestCase.java @@ -0,0 +1,138 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.test.unit.xa; + +import org.apache.qpid.dtx.XidImpl; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.TextMessage; +import javax.jms.XASession; +import javax.transaction.xa.XAResource; +import javax.transaction.xa.Xid; +import java.util.Random; + +/** + * + * + */ +public abstract class AbstractXATestCase extends QpidBrokerTestCase +{ + protected static final String _sequenceNumberPropertyName = "seqNumber"; + + /** + * the xaResource associated with the standard session + */ + protected static XAResource _xaResource = null; + + /** + * producer registered with the standard session + */ + protected static MessageProducer _producer = null; + + /** + * consumer registered with the standard session + */ + protected static MessageConsumer _consumer = null; + + /** + * a standard message + */ + protected static TextMessage _message = null; + + /** + * xid counter + */ + private static int _xidCounter = (new Random()).nextInt(1000000); + + + protected void setUp() throws Exception + { + super.setUp(); + init(); + } + + public abstract void init() throws Exception; + + + + /** + * construct a new Xid + * + * @return a new Xid + */ + protected Xid getNewXid() + { + byte[] branchQualifier; + byte[] globalTransactionID; + int format = _xidCounter; + String branchQualifierSt = "branchQualifier" + _xidCounter; + String globalTransactionIDSt = "globalTransactionID" + _xidCounter; + branchQualifier = branchQualifierSt.getBytes(); + globalTransactionID = globalTransactionIDSt.getBytes(); + _xidCounter++; + return new XidImpl(branchQualifier, format, globalTransactionID); + } + + public void init(XASession session, Destination destination) + { + // get the xaResource + try + { + _xaResource = session.getXAResource(); + } + catch (Exception e) + { + fail("cannot access the xa resource: " + e.getMessage()); + } + // create standard producer + try + { + _producer = session.createProducer(destination); + _producer.setDeliveryMode(DeliveryMode.PERSISTENT); + } + catch (JMSException e) + { + _logger.error("Producer error",e); + fail("cannot create message producer: " + e.getMessage()); + } + // create standard consumer + try + { + _consumer = session.createConsumer(destination); + } + catch (JMSException e) + { + fail("cannot create message consumer: " + e.getMessage()); + } + // create a standard message + try + { + _message = session.createTextMessage(); + _message.setText("test XA"); + } + catch (JMSException e) + { + fail("cannot create standard message: " + e.getMessage()); + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/xa/FaultTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/xa/FaultTest.java new file mode 100644 index 0000000000..c5fa217aa9 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/xa/FaultTest.java @@ -0,0 +1,414 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.xa; + + +import junit.framework.TestSuite; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.XAQueueConnection; +import javax.jms.XAQueueConnectionFactory; +import javax.jms.XAQueueSession; +import javax.transaction.xa.XAException; +import javax.transaction.xa.XAResource; +import javax.transaction.xa.Xid; + + +public class FaultTest extends AbstractXATestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(FaultTest.class); + + /** + * the queue use by all the tests + */ + private static Queue _queue = null; + /** + * the queue connection factory used by all tests + */ + private static XAQueueConnectionFactory _queueFactory = null; + + /** + * standard xa queue connection + */ + private static XAQueueConnection _xaqueueConnection = null; + + /** + * standard xa queue connection + */ + private static QueueConnection _queueConnection = null; + + + /** + * standard queue session created from the standard connection + */ + private static QueueSession _nonXASession = null; + + /** + * the queue name + */ + private static final String QUEUENAME = "xaQueue"; + + /** ----------------------------------------------------------------------------------- **/ + /** + * ----------------------------- JUnit support ----------------------------------------- * + */ + + /** + * Gets the test suite tests + * + * @return the test suite tests + */ + public static TestSuite getSuite() + { + return new TestSuite(QueueTest.class); + } + + /** + * Run the test suite. + * + * @param args Any command line arguments specified to this class. + */ + public static void main(String args[]) + { + junit.textui.TestRunner.run(getSuite()); + } + + public void tearDown() throws Exception + { + if (!isBroker08()) + { + _xaqueueConnection.close(); + _queueConnection.close(); + } + super.tearDown(); + } + + /** + * Initialize standard actors + */ + public void init() throws Exception + { + if (!isBroker08()) + { + _queue = (Queue) getInitialContext().lookup(QUEUENAME); + _queueFactory = getConnectionFactory(); + _xaqueueConnection = _queueFactory.createXAQueueConnection("guest", "guest"); + XAQueueSession session = _xaqueueConnection.createXAQueueSession(); + _queueConnection = _queueFactory.createQueueConnection("guest","guest"); + _nonXASession = _queueConnection.createQueueSession(true, Session.AUTO_ACKNOWLEDGE); + init(session, _queue); + } + } + + /** -------------------------------------------------------------------------------------- **/ + /** ----------------------------- Test Suite -------------------------------------------- **/ + /** -------------------------------------------------------------------------------------- **/ + + /** + * Strategy: + * Invoke start twice with the same xid on an XA resource. + * Check that the second + * invocation is throwing the expected XA exception. + */ + public void testSameXID() throws Exception + { + Xid xid = getNewXid(); + _xaResource.start(xid, XAResource.TMNOFLAGS); + // we now exepct this operation to fail + try + { + _xaResource.start(xid, XAResource.TMNOFLAGS); + fail("We managed to start a transaction with the same xid"); + } + catch (XAException e) + { + assertEquals("Wrong error code: ", XAException.XAER_DUPID, e.errorCode); + } + } + + /** + * Strategy: + * Invoke start on a XA resource with flag other than TMNOFLAGS, TMJOIN, or TMRESUME. + * Check that a XA Exception is thrown. + */ + public void testWrongStartFlag() + { + Xid xid = getNewXid(); + try + { + _xaResource.start(xid, XAResource.TMONEPHASE); + fail("We managed to start a transaction with a wrong flag"); + } + catch (XAException e) + { + assertEquals("Wrong error code: ", XAException.XAER_INVAL, e.errorCode); + } + } + + /** + * Strategy: + * Check that a XA exception is thrown when: + * A non started xid is ended + */ + public void testEnd() + { + Xid xid = getNewXid(); + try + { + _xaResource.end(xid, XAResource.TMSUCCESS); + fail("We managed to end a transaction before it is started"); + } + catch (XAException e) + { + assertEquals("Wrong error code: ", XAException.XAER_PROTO, e.errorCode); + } + } + + + /** + * Strategy: + * Check that a XA exception is thrown when: + * Call forget on an unknown xid + * call forget on a started xid + * A non started xid is prepared + * A non ended xis is prepared + */ + public void testForget() + { + Xid xid = getNewXid(); + try + { + _xaResource.forget(xid); + fail("We managed to forget an unknown xid"); + } + catch (XAException e) + { + // assertEquals("Wrong error code: ", XAException.XAER_NOTA, e.errorCode); + } + xid = getNewXid(); + try + { + _xaResource.start(xid, XAResource.TMNOFLAGS); + _xaResource.forget(xid); + fail("We managed to forget a started xid"); + } + catch (XAException e) + { + assertEquals("Wrong error code: ", XAException.XAER_PROTO, e.errorCode); + } + } + + /** + * Strategy: + * Check that a XA exception is thrown when: + * A non started xid is prepared + * A non ended xid is prepared + */ + public void testPrepare() + { + Xid xid = getNewXid(); + try + { + _xaResource.prepare(xid); + fail("We managed to prepare an unknown xid"); + } + catch (XAException e) + { + assertEquals("Wrong error code: ", XAException.XAER_NOTA, e.errorCode); + } + xid = getNewXid(); + try + { + _xaResource.start(xid, XAResource.TMNOFLAGS); + _xaResource.prepare(xid); + fail("We managed to prepare a started xid"); + } + catch (XAException e) + { + assertEquals("Wrong error code: ", XAException.XAER_PROTO, e.errorCode); + } + } + + /** + * Strategy: + * Check that the expected XA exception is thrown when: + * A non started xid is committed + * A non ended xid is committed + * A non prepared xid is committed with one phase set to false. + * A prepared xid is committed with one phase set to true. + */ + public void testCommit() throws Exception + { + Xid xid = getNewXid(); + try + { + _xaResource.commit(xid, true); + fail("We managed to commit an unknown xid"); + } + catch (XAException e) + { + assertEquals("Wrong error code: ", XAException.XAER_NOTA, e.errorCode); + } + xid = getNewXid(); + try + { + _xaResource.start(xid, XAResource.TMNOFLAGS); + _xaResource.commit(xid, true); + fail("We managed to commit a not ended xid"); + } + catch (XAException e) + { + assertEquals("Wrong error code: ", XAException.XAER_PROTO, e.errorCode); + } + xid = getNewXid(); + try + { + _xaResource.start(xid, XAResource.TMNOFLAGS); + _xaResource.end(xid, XAResource.TMSUCCESS); + _xaResource.commit(xid, false); + fail("We managed to commit a not prepared xid"); + } + catch (XAException e) + { + assertEquals("Wrong error code: ", XAException.XAER_PROTO, e.errorCode); + } + xid = getNewXid(); + try + { + _xaResource.start(xid, XAResource.TMNOFLAGS); + _xaResource.end(xid, XAResource.TMSUCCESS); + _xaResource.prepare(xid); + _xaResource.commit(xid, true); + fail("We managed to commit a prepared xid"); + } + catch (XAException e) + { + assertEquals("Wrong error code: ", XAException.XAER_PROTO, e.errorCode); + } + finally + { + _xaResource.commit(xid, false); + } + } + + /** + * Strategy: + * Check that the expected XA exception is thrown when: + * A non started xid is rolled back + * A non ended xid is rolled back + */ + public void testRollback() + { + Xid xid = getNewXid(); + try + { + _xaResource.rollback(xid); + fail("We managed to rollback an unknown xid"); + } + catch (XAException e) + { + assertEquals("Wrong error code: ", XAException.XAER_NOTA, e.errorCode); + } + xid = getNewXid(); + try + { + _xaResource.start(xid, XAResource.TMNOFLAGS); + _xaResource.rollback(xid); + fail("We managed to rollback a not ended xid"); + } + catch (XAException e) + { + assertEquals("Wrong error code: ", XAException.XAER_PROTO, e.errorCode); + } + } + + /** + * Strategy: + * Check that the timeout is set correctly + */ + public void testTransactionTimeoutvalue() throws Exception + { + Xid xid = getNewXid(); + _xaResource.start(xid, XAResource.TMNOFLAGS); + assertEquals("Wrong timeout", _xaResource.getTransactionTimeout(), 0); + _xaResource.setTransactionTimeout(1000); + assertEquals("Wrong timeout", _xaResource.getTransactionTimeout(), 1000); + _xaResource.end(xid, XAResource.TMSUCCESS); + xid = getNewXid(); + _xaResource.start(xid, XAResource.TMNOFLAGS); + assertEquals("Wrong timeout", _xaResource.getTransactionTimeout(), 1000); + } + + /** + * Strategy: + * Check that a transaction timeout as expected + * - set timeout to 1s + * - sleep 1500ms + * - call end and check that the expected exception is thrown + */ + public void testTransactionTimeout() throws Exception + { + _xaResource.setTransactionTimeout(1); + + Xid xid = getNewXid(); + try + { + _xaResource.start(xid, XAResource.TMNOFLAGS); + Thread.sleep(1500); + _xaResource.end(xid, XAResource.TMSUCCESS); + fail("Timeout expected "); + } + catch (XAException e) + { + assertEquals("Wrong error code: ", XAException.XA_RBTIMEOUT, e.errorCode); + } + } + + /** + * Strategy: + * Set the transaction timeout to 1000 + */ + public void testTransactionTimeoutAfterCommit() throws Exception + { + Xid xid = getNewXid(); + + _xaResource.start(xid, XAResource.TMNOFLAGS); + _xaResource.setTransactionTimeout(1000); + assertEquals("Wrong timeout", 1000,_xaResource.getTransactionTimeout()); + + //_xaResource.prepare(xid); + _xaResource.end(xid, XAResource.TMSUCCESS); + _xaResource.commit(xid, true); + + _xaResource.setTransactionTimeout(2000); + assertEquals("Wrong timeout", 2000,_xaResource.getTransactionTimeout()); + + xid = getNewXid(); + _xaResource.start(xid, XAResource.TMNOFLAGS); + assertEquals("Wrong timeout", 2000, _xaResource.getTransactionTimeout()); + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/xa/QueueTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/xa/QueueTest.java new file mode 100644 index 0000000000..350781e970 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/xa/QueueTest.java @@ -0,0 +1,669 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.test.unit.xa; + +import junit.framework.TestSuite; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.DeliveryMode; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.QueueSession; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.XAQueueConnection; +import javax.jms.XAQueueConnectionFactory; +import javax.jms.XAQueueSession; +import javax.transaction.xa.XAException; +import javax.transaction.xa.XAResource; +import javax.transaction.xa.Xid; + +public class QueueTest extends AbstractXATestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(QueueTest.class); + + /** + * the queue use by all the tests + */ + private static Queue _queue = null; + /** + * the queue connection factory used by all tests + */ + private static XAQueueConnectionFactory _queueFactory = null; + + /** + * standard xa queue connection + */ + private static XAQueueConnection _xaqueueConnection= null; + + /** + * standard xa queue connection + */ + private static QueueConnection _queueConnection=null; + + + /** + * standard queue session created from the standard connection + */ + private static QueueSession _nonXASession = null; + + /** + * the queue name + */ + private static final String QUEUENAME = "xaQueue"; + + /** ----------------------------------------------------------------------------------- **/ + /** + * ----------------------------- JUnit support ----------------------------------------- * + */ + + /** + * Gets the test suite tests + * + * @return the test suite tests + */ + public static TestSuite getSuite() + { + return new TestSuite(QueueTest.class); + } + + /** + * Run the test suite. + * + * @param args Any command line arguments specified to this class. + */ + public static void main(String args[]) + { + junit.textui.TestRunner.run(getSuite()); + } + + public void tearDown() throws Exception + { + if (!isBroker08()) + { + try + { + _xaqueueConnection.close(); + _queueConnection.close(); + } + catch (Exception e) + { + fail("Exception thrown when cleaning standard connection: " + e.getStackTrace()); + } + } + super.tearDown(); + } + + /** + * Initialize standard actors + */ + public void init() + { + if (!isBroker08()) + { + // lookup test queue + try + { + _queue = (Queue) getInitialContext().lookup(QUEUENAME); + } + catch (Exception e) + { + fail("cannot lookup test queue " + e.getMessage()); + } + + // lookup connection factory + try + { + _queueFactory = getConnectionFactory(); + } + catch (Exception e) + { + fail("enable to lookup connection factory "); + } + // create standard connection + try + { + _xaqueueConnection= getNewQueueXAConnection(); + } + catch (JMSException e) + { + fail("cannot create queue connection: " + e.getMessage()); + } + // create xa session + XAQueueSession session = null; + try + { + session = _xaqueueConnection.createXAQueueSession(); + } + catch (JMSException e) + { + fail("cannot create queue session: " + e.getMessage()); + } + // create a standard session + try + { + _queueConnection = _queueFactory.createQueueConnection("guest", "guest"); + _nonXASession = _queueConnection.createQueueSession(true, Session.AUTO_ACKNOWLEDGE); + } + catch (JMSException e) + { + _logger.error("cannot create queue session",e); + fail("cannot create queue session: " + e.getMessage()); + } + init(session, _queue); + } + } + + /** -------------------------------------------------------------------------------------- **/ + /** ----------------------------- Test Suite -------------------------------------------- **/ + /** -------------------------------------------------------------------------------------- **/ + + /** + * Uses two transactions respectively with xid1 and xid2 that are used to send a message + * within xid1 and xid2. xid2 is committed and xid1 is used to receive the message that was sent within xid2. + * Xid is then committed and a standard transaction is used to receive the message that was sent within xid1. + */ + public void testProducer() + { + if (!isBroker08()) + { + _logger.debug("running testProducer"); + Xid xid1 = getNewXid(); + Xid xid2 = getNewXid(); + // start the xaResource for xid1 + try + { + _xaResource.start(xid1, XAResource.TMNOFLAGS); + } + catch (XAException e) + { + _logger.error("cannot start the transaction with xid1", e); + fail("cannot start the transaction with xid1: " + e.getMessage()); + } + try + { + // start the connection + _xaqueueConnection.start(); + // produce a message with sequence number 1 + _message.setLongProperty(_sequenceNumberPropertyName, 1); + _producer.send(_message); + } + catch (JMSException e) + { + fail(" cannot send persistent message: " + e.getMessage()); + } + // suspend the transaction + try + { + _xaResource.end(xid1, XAResource.TMSUSPEND); + } + catch (XAException e) + { + fail("Cannot end the transaction with xid1: " + e.getMessage()); + } + // start the xaResource for xid2 + try + { + _xaResource.start(xid2, XAResource.TMNOFLAGS); + } + catch (XAException e) + { + fail("cannot start the transaction with xid2: " + e.getMessage()); + } + try + { + // produce a message + _message.setLongProperty(_sequenceNumberPropertyName, 2); + _producer.send(_message); + } + catch (JMSException e) + { + fail(" cannot send second persistent message: " + e.getMessage()); + } + // end xid2 and start xid1 + try + { + _xaResource.end(xid2, XAResource.TMSUCCESS); + _xaResource.start(xid1, XAResource.TMRESUME); + } + catch (XAException e) + { + fail("Exception when ending and starting transactions: " + e.getMessage()); + } + // two phases commit transaction with xid2 + try + { + int resPrepare = _xaResource.prepare(xid2); + if (resPrepare != XAResource.XA_OK) + { + fail("prepare returned: " + resPrepare); + } + _xaResource.commit(xid2, false); + } + catch (XAException e) + { + fail("Exception thrown when preparing transaction with xid2: " + e.getMessage()); + } + // receive a message from queue test we expect it to be the second one + try + { + TextMessage message = (TextMessage) _consumer.receive(1000); + if (message == null) + { + fail("did not receive second message as expected "); + } + else + { + if (message.getLongProperty(_sequenceNumberPropertyName) != 2) + { + fail("receive wrong message its sequence number is: " + message + .getLongProperty(_sequenceNumberPropertyName)); + } + } + } + catch (JMSException e) + { + fail("Exception when receiving second message: " + e.getMessage()); + } + // end and one phase commit the first transaction + try + { + _xaResource.end(xid1, XAResource.TMSUCCESS); + _xaResource.commit(xid1, true); + } + catch (XAException e) + { + fail("Exception thrown when commiting transaction with xid1"); + } + // We should now be able to receive the first message + try + { + _xaqueueConnection.close(); + Session nonXASession = _nonXASession; + MessageConsumer nonXAConsumer = nonXASession.createConsumer(_queue); + _queueConnection.start(); + TextMessage message1 = (TextMessage) nonXAConsumer.receive(1000); + if (message1 == null) + { + fail("did not receive first message as expected "); + } + else + { + if (message1.getLongProperty(_sequenceNumberPropertyName) != 1) + { + fail("receive wrong message its sequence number is: " + message1 + .getLongProperty(_sequenceNumberPropertyName)); + } + } + // commit that transacted session + nonXASession.commit(); + // the queue should be now empty + message1 = (TextMessage) nonXAConsumer.receive(1000); + if (message1 != null) + { + fail("receive an unexpected message "); + } + } + catch (JMSException e) + { + fail("Exception thrown when emptying the queue: " + e.getMessage()); + } + } + } + + /** + * strategy: Produce a message within Tx1 and prepare tx1. crash the server then commit tx1 and consume the message + */ + public void testSendAndRecover() + { + if (!isBroker08()) + { + _logger.debug("running testSendAndRecover"); + Xid xid1 = getNewXid(); + // start the xaResource for xid1 + try + { + _xaResource.start(xid1, XAResource.TMNOFLAGS); + } + catch (XAException e) + { + fail("cannot start the transaction with xid1: " + e.getMessage()); + } + try + { + // start the connection + _xaqueueConnection.start(); + // produce a message with sequence number 1 + _message.setLongProperty(_sequenceNumberPropertyName, 1); + _producer.send(_message); + } + catch (JMSException e) + { + fail(" cannot send persistent message: " + e.getMessage()); + } + // suspend the transaction + try + { + _xaResource.end(xid1, XAResource.TMSUCCESS); + } + catch (XAException e) + { + fail("Cannot end the transaction with xid1: " + e.getMessage()); + } + // prepare the transaction with xid1 + try + { + _xaResource.prepare(xid1); + } + catch (XAException e) + { + fail("Exception when preparing xid1: " + e.getMessage()); + } + + /////// stop the server now !! + try + { + _logger.debug("stopping broker"); + restartBroker(); + init(); + } + catch (Exception e) + { + fail("Exception when stopping and restarting the server"); + } + + // get the list of in doubt transactions + try + { + Xid[] inDoubt = _xaResource.recover(XAResource.TMSTARTRSCAN); + if (inDoubt == null) + { + fail("the array of in doubt transactions should not be null "); + } + // At that point we expect only two indoubt transactions: + if (inDoubt.length != 1) + { + fail("in doubt transaction size is diffenrent thatn 2, there are " + inDoubt.length + "in doubt transactions"); + } + + // commit them + for (Xid anInDoubt : inDoubt) + { + if (anInDoubt.equals(xid1)) + { + _logger.info("commit xid1 "); + try + { + _xaResource.commit(anInDoubt, false); + } + catch (Exception e) + { + _logger.error("PB when aborted xid1", e); + } + } + else + { + fail("did not receive right xid "); + } + } + } + catch (XAException e) + { + _logger.error("exception thrown when recovering transactions", e); + fail("exception thrown when recovering transactions " + e.getMessage()); + } + // the queue should contain the first message! + try + { + _xaqueueConnection.close(); + Session nonXASession = _nonXASession; + MessageConsumer nonXAConsumer = nonXASession.createConsumer(_queue); + _queueConnection.start(); + TextMessage message1 = (TextMessage) nonXAConsumer.receive(1000); + + if (message1 == null) + { + fail("queue does not contain any message!"); + } + if (message1.getLongProperty(_sequenceNumberPropertyName) != 1) + { + fail("Wrong message returned! Sequence number is " + message1 + .getLongProperty(_sequenceNumberPropertyName)); + } + nonXASession.commit(); + } + catch (JMSException e) + { + fail("Exception thrown when testin that queue test is not empty: " + e.getMessage()); + } + } + } + + /** + * strategy: Produce a message within Tx1 and prepare tx1. Produce a standard message and consume + * it within tx2 and prepare tx2. Shutdown the server and get the list of in doubt transactions: + * we expect tx1 and tx2! Then, Tx1 is aborted and tx2 is committed so we expect the test's queue to be empty! + */ + public void testRecover() + { + if (!isBroker08()) + { + _logger.debug("running testRecover"); + Xid xid1 = getNewXid(); + Xid xid2 = getNewXid(); + // start the xaResource for xid1 + try + { + _xaResource.start(xid1, XAResource.TMNOFLAGS); + } + catch (XAException e) + { + fail("cannot start the transaction with xid1: " + e.getMessage()); + } + try + { + // start the connection + _xaqueueConnection.start(); + // produce a message with sequence number 1 + _message.setLongProperty(_sequenceNumberPropertyName, 1); + _producer.send(_message); + } + catch (JMSException e) + { + fail(" cannot send persistent message: " + e.getMessage()); + } + // suspend the transaction + try + { + _xaResource.end(xid1, XAResource.TMSUCCESS); + } + catch (XAException e) + { + fail("Cannot end the transaction with xid1: " + e.getMessage()); + } + // prepare the transaction with xid1 + try + { + _xaResource.prepare(xid1); + } + catch (XAException e) + { + fail("Exception when preparing xid1: " + e.getMessage()); + } + + // send a message using the standard session + try + { + Session nonXASession = _nonXASession; + MessageProducer nonXAProducer = nonXASession.createProducer(_queue); + TextMessage message2 = nonXASession.createTextMessage(); + message2.setText("non XA "); + message2.setLongProperty(_sequenceNumberPropertyName, 2); + nonXAProducer.setDeliveryMode(DeliveryMode.PERSISTENT); + nonXAProducer.send(message2); + // commit that transacted session + nonXASession.commit(); + } + catch (Exception e) + { + fail("Exception thrown when emptying the queue: " + e.getMessage()); + } + // start the xaResource for xid2 + try + { + _xaResource.start(xid2, XAResource.TMNOFLAGS); + } + catch (XAException e) + { + fail("cannot start the transaction with xid1: " + e.getMessage()); + } + // receive a message from queue test we expect it to be the second one + try + { + TextMessage message = (TextMessage) _consumer.receive(1000); + if (message == null || message.getLongProperty(_sequenceNumberPropertyName) != 2) + { + fail("did not receive second message as expected "); + } + } + catch (JMSException e) + { + fail("Exception when receiving second message: " + e.getMessage()); + } + // suspend the transaction + try + { + _xaResource.end(xid2, XAResource.TMSUCCESS); + } + catch (XAException e) + { + fail("Cannot end the transaction with xid2: " + e.getMessage()); + } + // prepare the transaction with xid1 + try + { + _xaResource.prepare(xid2); + } + catch (XAException e) + { + fail("Exception when preparing xid2: " + e.getMessage()); + } + + /////// stop the server now !! + try + { + _logger.debug("stopping broker"); + restartBroker(); + init(); + } + catch (Exception e) + { + fail("Exception when stopping and restarting the server"); + } + + // get the list of in doubt transactions + try + { + Xid[] inDoubt = _xaResource.recover(XAResource.TMSTARTRSCAN); + if (inDoubt == null) + { + fail("the array of in doubt transactions should not be null "); + } + // At that point we expect only two indoubt transactions: + if (inDoubt.length != 2) + { + fail("in doubt transaction size is diffenrent thatn 2, there are " + inDoubt.length + "in doubt transactions"); + } + + // commit them + for (Xid anInDoubt : inDoubt) + { + if (anInDoubt.equals(xid1)) + { + _logger.debug("rollback xid1 "); + try + { + _xaResource.rollback(anInDoubt); + } + catch (Exception e) + { + _logger.error("PB when aborted xid1", e); + } + } + else if (anInDoubt.equals(xid2)) + { + _logger.debug("commit xid2 "); + try + { + _xaResource.commit(anInDoubt, false); + } + catch (Exception e) + { + _logger.error("PB when commiting xid2", e); + } + } + } + } + catch (XAException e) + { + _logger.error("exception thrown when recovering transactions", e); + fail("exception thrown when recovering transactions " + e.getMessage()); + } + // the queue should be empty + try + { + _xaqueueConnection.close(); + Session nonXASession = _nonXASession; + MessageConsumer nonXAConsumer = nonXASession.createConsumer(_queue); + _queueConnection.start(); + TextMessage message1 = (TextMessage) nonXAConsumer.receive(1000); + if (message1 != null) + { + + fail("The queue is not empty! " + message1.getLongProperty(_sequenceNumberPropertyName)); + } + } + catch (JMSException e) + { + fail("Exception thrown when testin that queue test is empty: " + e.getMessage()); + } + } + } + + /** -------------------------------------------------------------------------------------- **/ + /** ----------------------------- Utility methods --------------------------------------- **/ + /** -------------------------------------------------------------------------------------- **/ + + /** + * get a new queue connection + * + * @return a new queue connection + * @throws JMSException If the JMS provider fails to create the queue connection + * due to some internal error or in case of authentication failure + */ + private XAQueueConnection getNewQueueXAConnection() throws JMSException + { + return _queueFactory.createXAQueueConnection("guest", "guest"); + } + + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/xa/TopicTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/xa/TopicTest.java new file mode 100644 index 0000000000..4d9242b8b3 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/unit/xa/TopicTest.java @@ -0,0 +1,1742 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.test.unit.xa; + +import junit.framework.TestSuite; +import org.apache.qpid.configuration.ClientProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.*; +import javax.transaction.xa.XAException; +import javax.transaction.xa.XAResource; +import javax.transaction.xa.Xid; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * + * + */ +public class TopicTest extends AbstractXATestCase +{ + /* this class logger */ + private static final Logger _logger = LoggerFactory.getLogger(TopicTest.class); + + /** + * the topic use by all the tests + */ + private static Topic _topic = null; + + /** + * the topic connection factory used by all tests + */ + private static XATopicConnectionFactory _topicFactory = null; + + /** + * standard topic connection + */ + private static XATopicConnection _topicConnection = null; + + /** + * standard topic session created from the standard connection + */ + private static XATopicSession _session = null; + + private static TopicSession _nonXASession = null; + + /** + * the topic name + */ + private static final String TOPICNAME = "xaTopic"; + + /** + * Indicate that a listenere has failed + */ + private static boolean _failure = false; + + /** -------------------------------------------------------------------------------------- **/ + /** ----------------------------- JUnit support ----------------------------------------- **/ + /** -------------------------------------------------------------------------------------- **/ + + /** + * Gets the test suite tests + * + * @return the test suite tests + */ + public static TestSuite getSuite() + { + return new TestSuite(TopicTest.class); + } + + /** + * Run the test suite. + * + * @param args Any command line arguments specified to this class. + */ + public static void main(String args[]) + { + junit.textui.TestRunner.run(getSuite()); + } + + public void tearDown() throws Exception + { + if (!isBroker08()) + { + try + { + _topicConnection.stop(); + _topicConnection.close(); + } + catch (Exception e) + { + fail("Exception thrown when cleaning standard connection: " + e); + } + } + super.tearDown(); + } + + /** + * Initialize standard actors + */ + public void init() + { + if (!isBroker08()) + { + setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, "1"); + // lookup test queue + try + { + _topic = (Topic) getInitialContext().lookup(TOPICNAME); + } + catch (Exception e) + { + fail("cannot lookup test topic " + e.getMessage()); + } + // lookup connection factory + try + { + _topicFactory = getConnectionFactory(); + } + catch (Exception e) + { + fail("enable to lookup connection factory "); + } + // create standard connection + try + { + _topicConnection = getNewTopicXAConnection(); + } + catch (JMSException e) + { + fail("cannot create queue connection: " + e.getMessage()); + } + // create standard session + try + { + _session = _topicConnection.createXATopicSession(); + } + catch (JMSException e) + { + fail("cannot create queue session: " + e.getMessage()); + } + // create a standard session + try + { + _nonXASession = _topicConnection.createTopicSession(true, Session.AUTO_ACKNOWLEDGE); + } + catch (JMSException e) + { + _logger.error("Error creating topic session", e); + } + init(_session, _topic); + } + } + + /** -------------------------------------------------------------------------------------- **/ + /** ----------------------------- Test Suite -------------------------------------------- **/ + /** -------------------------------------------------------------------------------------- **/ + + + /** + * Uses two transactions respectively with xid1 and xid2 that are use to send a message + * within xid1 and xid2. xid2 is committed and xid1 is used to receive the message that was sent within xid2. + * Xid is then committed and a standard transaction is used to receive the message that was sent within xid1. + */ + public void testProducer() + { + if (!isBroker08()) + { + _logger.debug("testProducer"); + Xid xid1 = getNewXid(); + Xid xid2 = getNewXid(); + try + { + Session nonXASession = _nonXASession; + MessageConsumer nonXAConsumer = nonXASession.createConsumer(_topic); + _producer.setDeliveryMode(DeliveryMode.PERSISTENT); + // start the xaResource for xid1 + try + { + _logger.debug("starting tx branch xid1"); + _xaResource.start(xid1, XAResource.TMNOFLAGS); + } + catch (XAException e) + { + _logger.error("cannot start the transaction with xid1", e); + fail("cannot start the transaction with xid1: " + e.getMessage()); + } + try + { + // start the connection + _topicConnection.start(); + _logger.debug("produce a message with sequence number 1"); + _message.setLongProperty(_sequenceNumberPropertyName, 1); + _producer.send(_message); + } + catch (JMSException e) + { + fail(" cannot send persistent message: " + e.getMessage()); + } + _logger.debug("suspend the transaction branch xid1"); + try + { + _xaResource.end(xid1, XAResource.TMSUSPEND); + } + catch (XAException e) + { + fail("Cannot end the transaction with xid1: " + e.getMessage()); + } + _logger.debug("start the xaResource for xid2"); + try + { + _xaResource.start(xid2, XAResource.TMNOFLAGS); + } + catch (XAException e) + { + fail("cannot start the transaction with xid2: " + e.getMessage()); + } + try + { + _logger.debug("produce a message"); + _message.setLongProperty(_sequenceNumberPropertyName, 2); + _producer.send(_message); + } + catch (JMSException e) + { + fail(" cannot send second persistent message: " + e.getMessage()); + } + _logger.debug("end xid2 and start xid1"); + try + { + _xaResource.end(xid2, XAResource.TMSUCCESS); + _xaResource.start(xid1, XAResource.TMRESUME); + } + catch (XAException e) + { + fail("Exception when ending and starting transactions: " + e.getMessage()); + } + _logger.debug("two phases commit transaction with xid2"); + try + { + int resPrepare = _xaResource.prepare(xid2); + if (resPrepare != XAResource.XA_OK) + { + fail("prepare returned: " + resPrepare); + } + _xaResource.commit(xid2, false); + } + catch (XAException e) + { + fail("Exception thrown when preparing transaction with xid2: " + e.getMessage()); + } + _logger.debug("receiving a message from topic test we expect it to be the second one"); + try + { + TextMessage message = (TextMessage) _consumer.receive(1000); + if (message == null) + { + fail("did not receive second message as expected "); + } + else + { + if (message.getLongProperty(_sequenceNumberPropertyName) != 2) + { + fail("receive wrong message its sequence number is: " + message + .getLongProperty(_sequenceNumberPropertyName)); + } + } + } + catch (JMSException e) + { + fail("Exception when receiving second message: " + e.getMessage()); + } + _logger.debug("end and one phase commit the first transaction"); + try + { + _xaResource.end(xid1, XAResource.TMSUCCESS); + _xaResource.commit(xid1, true); + } + catch (XAException e) + { + fail("Exception thrown when commiting transaction with xid1"); + } + _logger.debug("We should now be able to receive the first and second message"); + try + { + TextMessage message1 = (TextMessage) nonXAConsumer.receive(1000); + if (message1 == null) + { + fail("did not receive first message as expected "); + } + else + { + if (message1.getLongProperty(_sequenceNumberPropertyName) != 2) + { + fail("receive wrong message its sequence number is: " + message1 + .getLongProperty(_sequenceNumberPropertyName)); + } + } + message1 = (TextMessage) nonXAConsumer.receive(1000); + if (message1 == null) + { + fail("did not receive first message as expected "); + } + else + { + if (message1.getLongProperty(_sequenceNumberPropertyName) != 1) + { + fail("receive wrong message its sequence number is: " + message1 + .getLongProperty(_sequenceNumberPropertyName)); + } + } + _logger.debug("commit transacted session"); + nonXASession.commit(); + _logger.debug("Test that the topic is now empty"); + message1 = (TextMessage) nonXAConsumer.receive(1000); + if (message1 != null) + { + fail("receive an unexpected message "); + } + } + catch (JMSException e) + { + fail("Exception thrown when emptying the queue: " + e.getMessage()); + } + } + catch (JMSException e) + { + fail("cannot create standard consumer: " + e.getMessage()); + } + } + } + + + /** + * strategy: Produce a message within Tx1 and commit tx1. consume this message within tx2 and abort tx2. + * Consume the same message within tx3 and commit it. Check that no more message is available. + */ + public void testDurSub() + { + if (!isBroker08()) + { + Xid xid1 = getNewXid(); + Xid xid2 = getNewXid(); + Xid xid3 = getNewXid(); + Xid xid4 = getNewXid(); + String durSubName = "xaSubDurable"; + try + { + TopicSubscriber xaDurSub = _session.createDurableSubscriber(_topic, durSubName); + try + { + _topicConnection.start(); + _logger.debug("start xid1"); + _xaResource.start(xid1, XAResource.TMNOFLAGS); + // start the connection + _topicConnection.start(); + _logger.debug("produce a message with sequence number 1"); + _message.setLongProperty(_sequenceNumberPropertyName, 1); + _producer.send(_message); + _logger.debug("2 phases commit xid1"); + _xaResource.end(xid1, XAResource.TMSUCCESS); + if (_xaResource.prepare(xid1) != XAResource.XA_OK) + { + fail("Problem when preparing tx1 "); + } + _xaResource.commit(xid1, false); + } + catch (Exception e) + { + _logger.error("Exception when working with xid1", e); + fail("Exception when working with xid1: " + e.getMessage()); + } + try + { + _logger.debug("start xid2"); + _xaResource.start(xid2, XAResource.TMNOFLAGS); + _logger.debug("receive the previously produced message"); + TextMessage message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received "); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != 1) + { + fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); + } + _logger.debug("rollback xid2"); + boolean rollbackOnFailure = false; + try + { + _xaResource.end(xid2, XAResource.TMFAIL); + } + catch (XAException e) + { + if (e.errorCode != XAException.XA_RBROLLBACK) + { + fail("Exception when working with xid2: " + e.getMessage()); + } + rollbackOnFailure = true; + } + if (!rollbackOnFailure) + { + if (_xaResource.prepare(xid2) != XAResource.XA_OK) + { + fail("Problem when preparing tx2 "); + } + _xaResource.rollback(xid2); + } + } + catch (Exception e) + { + _logger.error("Exception when working with xid2", e); + fail("Exception when working with xid2: " + e.getMessage()); + } + try + { + _logger.debug("start xid3"); + _xaResource.start(xid3, XAResource.TMNOFLAGS); + _logger.debug(" receive the previously aborted consumed message"); + TextMessage message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received "); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != 1) + { + fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); + } + _logger.debug("commit xid3"); + _xaResource.end(xid3, XAResource.TMSUCCESS); + if (_xaResource.prepare(xid3) != XAResource.XA_OK) + { + fail("Problem when preparing tx3 "); + } + _xaResource.commit(xid3, false); + } + catch (Exception e) + { + _logger.error("Exception when working with xid3", e); + fail("Exception when working with xid3: " + e.getMessage()); + } + try + { + _logger.debug("start xid4"); + _xaResource.start(xid4, XAResource.TMNOFLAGS); + _logger.debug("check that topic is empty"); + TextMessage message = (TextMessage) xaDurSub.receive(1000); + if (message != null) + { + fail("An unexpected message was received "); + } + _logger.debug("commit xid4"); + _xaResource.end(xid4, XAResource.TMSUCCESS); + _xaResource.commit(xid4, true); + } + catch (Exception e) + { + _logger.error("Exception when working with xid4", e); + fail("Exception when working with xid4: " + e.getMessage()); + } + } + catch (Exception e) + { + _logger.error("problem when creating dur sub", e); + fail("problem when creating dur sub: " + e.getMessage()); + } + finally + { + try + { + _session.unsubscribe(durSubName); + } + catch (JMSException e) + { + _logger.error("problem when unsubscribing dur sub", e); + fail("problem when unsubscribing dur sub: " + e.getMessage()); + } + } + } + } + + /** + * strategy: create a XA durable subscriber dusSub, produce 7 messages with the standard session, + * consume 2 messages respectively with tx1, tx2 and tx3 + * abort tx2, we now expect to receive messages 3 and 4 first! Receive 3 messages within tx1 i.e. 34 and 7! + * commit tx3 + * abort tx1: we now expect that only messages 5 and 6 are definitly consumed! + * start tx4 and consume messages 1 - 4 and 7 + * commit tx4 + * Now the topic should be empty! + */ + public void testMultiMessagesDurSub() + { + if (!isBroker08()) + { + Xid xid1 = getNewXid(); + Xid xid2 = getNewXid(); + Xid xid3 = getNewXid(); + Xid xid4 = getNewXid(); + Xid xid6 = getNewXid(); + String durSubName = "xaSubDurable"; + TextMessage message; + try + { + TopicSubscriber xaDurSub = _session.createDurableSubscriber(_topic, durSubName); + try + { + Session txSession = _nonXASession; + MessageProducer txProducer = txSession.createProducer(_topic); + _logger.debug("produce 10 persistent messages"); + txProducer.setDeliveryMode(DeliveryMode.PERSISTENT); + _topicConnection.start(); + for (int i = 1; i <= 7; i++) + { + _message.setLongProperty(_sequenceNumberPropertyName, i); + txProducer.send(_message); + } + // commit txSession + txSession.commit(); + } + catch (JMSException e) + { + _logger.error("Exception thrown when producing messages", e); + fail("Exception thrown when producing messages: " + e.getMessage()); + } + + try + { + _logger.debug(" consume 2 messages respectively with tx1, tx2 and tx3"); + //----- start xid1 + _xaResource.start(xid1, XAResource.TMNOFLAGS); + // receive the 2 first messages + for (int i = 1; i <= 2; i++) + { + message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received! expected: " + i); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != i) + { + fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); + } + } + _xaResource.end(xid1, XAResource.TMSUSPEND); + //----- start xid2 + _xaResource.start(xid2, XAResource.TMNOFLAGS); + // receive the 2 first messages + for (int i = 3; i <= 4; i++) + { + message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received! expected: " + i); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != i) + { + fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); + } + } + _xaResource.end(xid2, XAResource.TMSUSPEND); + //----- start xid3 + _xaResource.start(xid3, XAResource.TMNOFLAGS); + // receive the 2 first messages + for (int i = 5; i <= 6; i++) + { + message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received! expected: " + i); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != i) + { + fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); + } + } + _xaResource.end(xid3, XAResource.TMSUCCESS); + } + catch (Exception e) + { + _logger.error("Exception thrown when consumming 6 first messages", e); + fail("Exception thrown when consumming 6 first messages: " + e.getMessage()); + } + try + { + _logger.debug("abort tx2, we now expect to receive messages 3, 4 and 7"); + _xaResource.start(xid2, XAResource.TMRESUME); + _xaResource.end(xid2, XAResource.TMSUCCESS); + _xaResource.prepare(xid2); + _xaResource.rollback(xid2); + // receive 3 message within tx1: 3, 4 and 7 + _xaResource.start(xid1, XAResource.TMRESUME); + _logger.debug(" 3, 4 and 7"); + for (int i = 1; i <= 3; i++) + { + message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received! expected: " + 3); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) <= 2 || 5 == message + .getLongProperty(_sequenceNumberPropertyName) || message + .getLongProperty(_sequenceNumberPropertyName) == 6) + { + fail("wrong sequence number: " + message + .getLongProperty(_sequenceNumberPropertyName)); + } + } + } + catch (Exception e) + { + _logger.error("Exception thrown when consumming message: 3, 4 and 7", e); + fail("Exception thrown when consumming message: 3, 4 and 7: " + e.getMessage()); + } + + try + { + _xaResource.end(xid1, XAResource.TMSUCCESS); + _logger.debug(" commit tx3"); + _xaResource.commit(xid3, true); + _logger.debug("abort tx1"); + _xaResource.prepare(xid1); + _xaResource.rollback(xid1); + } + catch (XAException e) + { + _logger.error("XAException thrown when committing tx3 or aborting tx1", e); + fail("XAException thrown when committing tx3 or aborting tx1: " + e.getMessage()); + } + + try + { + // consume messages 1 - 4 + 7 + //----- start xid1 + _xaResource.start(xid4, XAResource.TMNOFLAGS); + for (int i = 1; i <= 5; i++) + { + + message = (TextMessage) xaDurSub.receive(1000); + + if(message != null) + { + _logger.debug(" received message: " + message.getLongProperty(_sequenceNumberPropertyName)); + } + + if (message == null) + { + fail("no message received! expected: " + i); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) == 5 || message + .getLongProperty(_sequenceNumberPropertyName) == 6) + { + fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); + } + } + _xaResource.end(xid4, XAResource.TMSUCCESS); + _xaResource.prepare(xid4); + _xaResource.commit(xid4, false); + } + catch (Exception e) + { + _logger.error("Exception thrown in last phase", e); + fail("Exception thrown in last phase: " + e.getMessage()); + } + // now the topic should be empty!! + try + { + // start xid6 + _xaResource.start(xid6, XAResource.TMNOFLAGS); + // should now be empty + message = (TextMessage) xaDurSub.receive(1000); + if (message != null) + { + fail("An unexpected message was received " + message + .getLongProperty(_sequenceNumberPropertyName)); + } + // commit xid6 + _xaResource.end(xid6, XAResource.TMSUCCESS); + _xaResource.commit(xid6, true); + } + catch (Exception e) + { + _logger.error("Exception when working with xid6", e); + fail("Exception when working with xid6: " + e.getMessage()); + } + } + catch (Exception e) + { + _logger.error("problem when creating dur sub", e); + fail("problem when creating dur sub: " + e.getMessage()); + } + finally + { + try + { + _session.unsubscribe(durSubName); + } + catch (JMSException e) + { + _logger.error("problem when unsubscribing dur sub", e); + fail("problem when unsubscribing dur sub: " + e.getMessage()); + } + } + } + } + + /** + * strategy: create a XA durable subscriber dusSub, produce 10 messages with the standard session, + * consume 2 messages respectively with tx1, tx2 and tx3 + * prepare xid2 and xid3 + * crash the server + * Redo the job for xid1 that has been aborted by server crash + * abort tx2, we now expect to receive messages 3 and 4 first! Receive 3 messages within tx1 i.e. 34 and 7! + * commit tx3 + * abort tx1: we now expect that only messages 5 and 6 are definitly consumed! + * start tx4 and consume messages 1 - 4 + * start tx5 and consume messages 7 - 10 + * abort tx4 + * consume messages 1-4 with tx5 + * commit tx5 + * Now the topic should be empty! + */ + public void testMultiMessagesDurSubCrash() + { + if (!isBroker08()) + { + Xid xid1 = getNewXid(); + Xid xid2 = getNewXid(); + Xid xid3 = getNewXid(); + Xid xid4 = getNewXid(); + Xid xid5 = getNewXid(); + Xid xid6 = getNewXid(); + String durSubName = "xaSubDurable"; + TextMessage message; + try + { + TopicSubscriber xaDurSub = _session.createDurableSubscriber(_topic, durSubName); + try + { + Session txSession = _nonXASession; + MessageProducer txProducer = txSession.createProducer(_topic); + // produce 10 persistent messages + txProducer.setDeliveryMode(DeliveryMode.PERSISTENT); + _topicConnection.start(); + for (int i = 1; i <= 10; i++) + { + _message.setLongProperty(_sequenceNumberPropertyName, i); + txProducer.send(_message); + } + // commit txSession + txSession.commit(); + } + catch (JMSException e) + { + _logger.error("Exception thrown when producing messages", e); + fail("Exception thrown when producing messages: " + e.getMessage()); + } + try + { + // consume 2 messages respectively with tx1, tx2 and tx3 + //----- start xid1 + _xaResource.start(xid1, XAResource.TMNOFLAGS); + // receive the 2 first messages + for (int i = 1; i <= 2; i++) + { + message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received! expected: " + i); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != i) + { + fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); + } + } + _xaResource.end(xid1, XAResource.TMSUCCESS); + //----- start xid2 + _xaResource.start(xid2, XAResource.TMNOFLAGS); + // receive the 2 first messages + for (int i = 3; i <= 4; i++) + { + message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received! expected: " + i); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != i) + { + fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); + } + } + _xaResource.end(xid2, XAResource.TMSUCCESS); + //----- start xid3 + _xaResource.start(xid3, XAResource.TMNOFLAGS); + // receive the 2 first messages + for (int i = 5; i <= 6; i++) + { + message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received! expected: " + i); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != i) + { + fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); + } + } + _xaResource.end(xid3, XAResource.TMSUCCESS); + // prepare tx2 and tx3 + + _xaResource.prepare(xid2); + _xaResource.prepare(xid3); + } + catch (Exception e) + { + _logger.error("Exception thrown when consumming 6 first messages", e); + fail("Exception thrown when consumming 6 first messages: " + e.getMessage()); + } + /////// stop the broker now !! + try + { + restartBroker(); + init(); + } + catch (Exception e) + { + fail("Exception when stopping and restarting the server"); + } + // get the list of in doubt transactions + try + { + _topicConnection.start(); + // reconnect to dursub! + xaDurSub = _session.createDurableSubscriber(_topic, durSubName); + Xid[] inDoubt = _xaResource.recover(XAResource.TMSTARTRSCAN); + if (inDoubt == null) + { + fail("the array of in doubt transactions should not be null "); + } + // At that point we expect only two indoubt transactions: + if (inDoubt.length != 2) + { + fail("in doubt transaction size is diffenrent than 2, there are " + inDoubt.length + "in doubt transactions"); + } + } + catch (XAException e) + { + _logger.error("exception thrown when recovering transactions", e); + fail("exception thrown when recovering transactions " + e.getMessage()); + } + try + { + // xid1 has been aborted redo the job! + // consume 2 messages with tx1 + //----- start xid1 + _xaResource.start(xid1, XAResource.TMNOFLAGS); + // receive the 2 first messages + for (int i = 1; i <= 2; i++) + { + message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received! expected: " + i); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != i) + { + fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); + } + } + _xaResource.end(xid1, XAResource.TMSUSPEND); + // abort tx2, we now expect to receive messages 3 and 4 first! + _xaResource.rollback(xid2); + + // receive 3 message within tx1: 3, 4 and 7 + _xaResource.start(xid1, XAResource.TMRESUME); + // receive messages 3, 4 and 7 + Set expected = new HashSet(); + expected.add(3L); + expected.add(4L); + expected.add(7L); + message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received! expected one of: " + expected); + } + else if (!expected.remove(message.getLongProperty(_sequenceNumberPropertyName))) + { + fail("wrong sequence number: " + message + .getLongProperty(_sequenceNumberPropertyName) + " expected one from " + expected); + } + message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received! expected one of: " + expected); + } + else if (!expected.remove(message.getLongProperty(_sequenceNumberPropertyName))) + { + + fail("wrong sequence number: " + message + .getLongProperty(_sequenceNumberPropertyName) + " expected one from " + expected); + } + message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received! expected one of: " + expected); + } + else if (!expected.remove(message.getLongProperty(_sequenceNumberPropertyName))) + { + fail("wrong sequence number: " + message + .getLongProperty(_sequenceNumberPropertyName) + " expected one from " + expected); + } + } + catch (Exception e) + { + _logger.error("Exception thrown when consumming message: 3, 4 and 7", e); + fail("Exception thrown when consumming message: 3, 4 and 7: " + e.getMessage()); + } + + try + { + _xaResource.end(xid1, XAResource.TMSUSPEND); + // commit tx3 + _xaResource.commit(xid3, false); + // abort tx1 + _xaResource.prepare(xid1); + _xaResource.rollback(xid1); + } + catch (XAException e) + { + _logger.error("XAException thrown when committing tx3 or aborting tx1", e); + fail("XAException thrown when committing tx3 or aborting tx1: " + e.getMessage()); + } + + try + { + // consume messages: could be any from (1 - 4, 7-10) + //----- start xid4 + Set expected = new HashSet(); + Set xid4msgs = new HashSet(); + for(long l = 1; l <= 4l; l++) + { + expected.add(l); + } + for(long l = 7; l <= 10l; l++) + { + expected.add(l); + } + _xaResource.start(xid4, XAResource.TMNOFLAGS); + for (int i = 1; i <= 4; i++) + { + message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received! expected: " + i); + } + + long seqNo = message.getLongProperty(_sequenceNumberPropertyName); + xid4msgs.add(seqNo); + + if (!expected.remove(seqNo)) + { + fail("wrong sequence number: " + seqNo + + " expected one from " + expected); + } + } + _xaResource.end(xid4, XAResource.TMSUSPEND); + // consume messages 8 - 10 + _xaResource.start(xid5, XAResource.TMNOFLAGS); + for (int i = 7; i <= 10; i++) + { + message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received! expected: " + i); + } + else if (!expected.remove(message.getLongProperty(_sequenceNumberPropertyName))) + { + fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName) + + " expected one from " + expected); + } + } + _xaResource.end(xid5, XAResource.TMSUSPEND); + // abort tx4 + _xaResource.prepare(xid4); + _xaResource.rollback(xid4); + expected.addAll(xid4msgs); + // consume messages 1-4 with tx5 + _xaResource.start(xid5, XAResource.TMRESUME); + for (int i = 1; i <= 4; i++) + { + message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received! expected: " + i); + } + else if (!expected.remove(message.getLongProperty(_sequenceNumberPropertyName))) + { + fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName) + + " expected one from " + expected); + } + } + _xaResource.end(xid5, XAResource.TMSUSPEND); + // commit tx5 + + _xaResource.prepare(xid5); + _xaResource.commit(xid5, false); + } + catch (Exception e) + { + _logger.error("Exception thrown in last phase", e); + fail("Exception thrown in last phase: " + e.getMessage()); + } + // now the topic should be empty!! + try + { + // start xid6 + _xaResource.start(xid6, XAResource.TMNOFLAGS); + // should now be empty + message = (TextMessage) xaDurSub.receive(1000); + if (message != null) + { + fail("An unexpected message was received " + message + .getLongProperty(_sequenceNumberPropertyName)); + } + // commit xid6 + _xaResource.end(xid6, XAResource.TMSUSPEND); + _xaResource.commit(xid6, true); + } + catch (Exception e) + { + _logger.error("Exception when working with xid6", e); + fail("Exception when working with xid6: " + e.getMessage()); + } + } + catch (Exception e) + { + _logger.error("problem when creating dur sub", e); + fail("problem when creating dur sub: " + e.getMessage()); + } + finally + { + try + { + _session.unsubscribe(durSubName); + } + catch (JMSException e) + { + _logger.error("problem when unsubscribing dur sub", e); + fail("problem when unsubscribing dur sub: " + e.getMessage()); + } + } + } + } + + + /** + * strategy: Produce a message within Tx1 and commit tx1. a durable subscriber then receives that message within tx2 + * that is then prepared. + * Shutdown the server and get the list of in doubt transactions: + * we expect tx2, Tx2 is aborted and the message consumed within tx3 that is committed we then check that the topic is empty. + */ + public void testDurSubCrash() + { + if (!isBroker08()) + { + Xid xid1 = getNewXid(); + Xid xid2 = getNewXid(); + Xid xid3 = getNewXid(); + Xid xid4 = getNewXid(); + String durSubName = "xaSubDurable"; + try + { + TopicSubscriber xaDurSub = _session.createDurableSubscriber(_topic, durSubName); + try + { + _topicConnection.start(); + //----- start xid1 + _xaResource.start(xid1, XAResource.TMNOFLAGS); + // start the connection + _topicConnection.start(); + // produce a message with sequence number 1 + _message.setLongProperty(_sequenceNumberPropertyName, 1); + _producer.send(_message); + // commit + _xaResource.end(xid1, XAResource.TMSUCCESS); + if (_xaResource.prepare(xid1) != XAResource.XA_OK) + { + fail("Problem when preparing tx1 "); + } + _xaResource.commit(xid1, false); + } + catch (Exception e) + { + _logger.error("Exception when working with xid1", e); + fail("Exception when working with xid1: " + e.getMessage()); + } + try + { + // start xid2 + _xaResource.start(xid2, XAResource.TMNOFLAGS); + // receive the previously produced message + TextMessage message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received "); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != 1) + { + fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); + } + // prepare xid2 + _xaResource.end(xid2, XAResource.TMSUCCESS); + if (_xaResource.prepare(xid2) != XAResource.XA_OK) + { + fail("Problem when preparing tx2 "); + } + } + catch (Exception e) + { + _logger.error("Exception when working with xid2", e); + fail("Exception when working with xid2: " + e.getMessage()); + } + + /////// stop the server now !! + try + { + restartBroker(); + init(); + } + catch (Exception e) + { + fail("Exception when stopping and restarting the server"); + } + + // get the list of in doubt transactions + try + { + _topicConnection.start(); + // reconnect to dursub! + xaDurSub = _session.createDurableSubscriber(_topic, durSubName); + Xid[] inDoubt = _xaResource.recover(XAResource.TMSTARTRSCAN); + if (inDoubt == null) + { + fail("the array of in doubt transactions should not be null "); + } + // At that point we expect only two indoubt transactions: + if (inDoubt.length != 1) + { + fail("in doubt transaction size is diffenrent than 2, there are " + inDoubt.length + "in doubt transactions"); + } + + // commit them + for (Xid anInDoubt : inDoubt) + { + if (anInDoubt.equals(xid2)) + { + _logger.info("aborting xid2 "); + try + { + _xaResource.rollback(anInDoubt); + } + catch (Exception e) + { + _logger.error("exception when aborting xid2 ", e); + fail("exception when aborting xid2 "); + } + } + else + { + _logger.info("XID2 is not in doubt "); + } + } + } + catch (XAException e) + { + _logger.error("exception thrown when recovering transactions", e); + fail("exception thrown when recovering transactions " + e.getMessage()); + } + + try + { + // start xid3 + _xaResource.start(xid3, XAResource.TMNOFLAGS); + // receive the previously produced message and aborted + TextMessage message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received "); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != 1) + { + fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); + } + // commit xid3 + _xaResource.end(xid3, XAResource.TMSUCCESS); + if (_xaResource.prepare(xid3) != XAResource.XA_OK) + { + fail("Problem when preparing tx3 "); + } + _xaResource.commit(xid3, false); + } + catch (Exception e) + { + _logger.error("Exception when working with xid3", e); + fail("Exception when working with xid3: " + e.getMessage()); + } + try + { + // start xid4 + _xaResource.start(xid4, XAResource.TMNOFLAGS); + // should now be empty + TextMessage message = (TextMessage) xaDurSub.receive(1000); + if (message != null) + { + fail("An unexpected message was received " + message + .getLongProperty(_sequenceNumberPropertyName)); + } + // commit xid4 + _xaResource.end(xid4, XAResource.TMSUCCESS); + _xaResource.commit(xid4, true); + } + catch (Exception e) + { + _logger.error("Exception when working with xid4", e); + fail("Exception when working with xid4: " + e.getMessage()); + } + } + catch (Exception e) + { + _logger.error("problem when creating dur sub", e); + fail("problem when creating dur sub: " + e.getMessage()); + } + finally + { + try + { + _session.unsubscribe(durSubName); + } + catch (JMSException e) + { + _logger.error("problem when unsubscribing dur sub", e); + fail("problem when unsubscribing dur sub: " + e.getMessage()); + } + } + } + } + + /** + * strategy: Produce a message within Tx1 and prepare tx1. Shutdown the server and get the list of indoubt transactions: + * we expect tx1, Tx1 is committed so we expect the test topic not to be empty! + */ + public void testRecover() + { + if (!isBroker08()) + { + Xid xid1 = getNewXid(); + String durSubName = "test1"; + try + { + // create a dummy durable subscriber to be sure that messages are persisted! + _nonXASession.createDurableSubscriber(_topic, durSubName); + // start the xaResource for xid1 + try + { + _xaResource.start(xid1, XAResource.TMNOFLAGS); + } + catch (XAException e) + { + fail("cannot start the transaction with xid1: " + e.getMessage()); + } + try + { + // start the connection + _topicConnection.start(); + // produce a message with sequence number 1 + _message.setLongProperty(_sequenceNumberPropertyName, 1); + _producer.send(_message); + } + catch (JMSException e) + { + fail(" cannot send persistent message: " + e.getMessage()); + } + // suspend the transaction + try + { + _xaResource.end(xid1, XAResource.TMSUCCESS); + } + catch (XAException e) + { + fail("Cannot end the transaction with xid1: " + e.getMessage()); + } + // prepare the transaction with xid1 + try + { + _xaResource.prepare(xid1); + } + catch (XAException e) + { + fail("Exception when preparing xid1: " + e.getMessage()); + } + + /////// stop the server now !! + try + { + restartBroker(); + init(); + } + catch (Exception e) + { + fail("Exception when stopping and restarting the server"); + } + + try + { + MessageConsumer nonXAConsumer = _nonXASession.createDurableSubscriber(_topic, durSubName); + _topicConnection.start(); + // get the list of in doubt transactions + try + { + Xid[] inDoubt = _xaResource.recover(XAResource.TMSTARTRSCAN); + if (inDoubt == null) + { + fail("the array of in doubt transactions should not be null "); + } + // At that point we expect only two indoubt transactions: + if (inDoubt.length != 1) + { + fail("in doubt transaction size is diffenrent thatn 2, there are " + inDoubt.length + "in doubt transactions"); + } + // commit them + for (Xid anInDoubt : inDoubt) + { + if (anInDoubt.equals(xid1)) + { + _logger.debug("committing xid1 "); + try + { + _xaResource.commit(anInDoubt, false); + } + catch (Exception e) + { + _logger.error("PB when aborted xid1"); + fail("exception when committing xid1 "); + } + } + else + { + _logger.debug("XID1 is not in doubt "); + } + } + } + catch (XAException e) + { + _logger.error("exception thrown when recovering transactions ", e); + fail("exception thrown when recovering transactions " + e.getMessage()); + } + _logger.debug("the topic should not be empty"); + TextMessage message1 = (TextMessage) nonXAConsumer.receive(1000); + if (message1 == null) + { + fail("The topic is empty! "); + } + } + catch (Exception e) + { + _logger.error("Exception thrown when testin that queue test is empty", e); + fail("Exception thrown when testin that queue test is empty: " + e.getMessage()); + } + } + catch (JMSException e) + { + _logger.error("cannot create dummy durable subscriber", e); + fail("cannot create dummy durable subscriber: " + e.getMessage()); + } + finally + { + try + { + // unsubscribe the dummy durable subscriber + TopicSession nonXASession = _nonXASession; + nonXASession.unsubscribe(durSubName); + } + catch (JMSException e) + { + fail("cannot unsubscribe durable subscriber: " + e.getMessage()); + } + } + } + } + + /** + * strategy: + * create a standard durable subscriber + * produce 3 messages + * consume the first message with that durable subscriber + * close the standard session that deactivates the durable subscriber + * migrate the durable subscriber to an xa one + * consume the second message with that xa durable subscriber + * close the xa session that deactivates the durable subscriber + * reconnect to the durable subscriber with a standard session + * consume the two remaining messages and check that the topic is empty! + */ + public void testMigrateDurableSubscriber() + { + if (!isBroker08()) + { + Xid xid1 = getNewXid(); + Xid xid2 = getNewXid(); + String durSubName = "DurableSubscriberMigrate"; + try + { + Session stSession = _nonXASession; + MessageProducer producer = stSession.createProducer(_topic); + _logger.debug("Create a standard durable subscriber!"); + TopicSubscriber durSub = stSession.createDurableSubscriber(_topic, durSubName); + TopicSubscriber durSub1 = stSession.createDurableSubscriber(_topic, durSubName + "_second"); + TextMessage message; + producer.setDeliveryMode(DeliveryMode.PERSISTENT); + _topicConnection.start(); + _logger.debug("produce 3 messages"); + for (int i = 1; i <= 3; i++) + { + _message.setLongProperty(_sequenceNumberPropertyName, i); + //producer.send( _message ); + producer.send(_message, DeliveryMode.PERSISTENT, 9 - i, 0); + stSession.commit(); + } + _logger.debug("consume the first message with that durable subscriber"); + message = (TextMessage) durSub.receive(1000); + if (message == null) + { + fail("no message received "); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != 1) + { + fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); + } + // commit the standard session + stSession.commit(); + _logger.debug("first message consumed "); + // close the session that deactivates the durable subscriber + stSession.close(); + _logger.debug("migrate the durable subscriber to an xa one"); + _xaResource.start(xid1, XAResource.TMNOFLAGS); + durSub = _session.createDurableSubscriber(_topic, durSubName); + _logger.debug(" consume the second message with that xa durable subscriber and abort it"); + message = (TextMessage) durSub.receive(1000); + if (message == null) + { + fail("no message received "); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != 2) + { + _logger.info("wrong sequence number, 2 expected, received: " + message + .getLongProperty(_sequenceNumberPropertyName)); + } + _xaResource.end(xid1, XAResource.TMSUCCESS); + _xaResource.prepare(xid1); + _xaResource.rollback(xid1); + _logger.debug("close the session that deactivates the durable subscriber"); + _session.close(); + _logger.debug("create a new standard session"); + stSession = _topicConnection.createTopicSession(true, 1); + _logger.debug("reconnect to the durable subscriber"); + durSub = stSession.createDurableSubscriber(_topic, durSubName); + durSub1 = stSession.createDurableSubscriber(_topic, durSubName + "_second"); + _logger.debug("Reconnected to durablse subscribers"); + _logger.debug(" consume the 2 remaining messages"); + message = (TextMessage) durSub.receive(1000); + if (message == null) + { + fail("no message received "); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != 2) + { + _logger.info("wrong sequence number, 2 expected, received: " + message + .getLongProperty(_sequenceNumberPropertyName)); + } + // consume the third message with that xa durable subscriber + message = (TextMessage) durSub.receive(1000); + if (message == null) + { + fail("no message received "); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != 3) + { + _logger.info("wrong sequence number, 3 expected, received: " + message + .getLongProperty(_sequenceNumberPropertyName)); + } + stSession.commit(); + _logger.debug("the topic should be empty now"); + message = (TextMessage) durSub.receive(1000); + if (message != null) + { + fail("Received unexpected message "); + } + stSession.commit(); + _logger.debug(" use dursub1 to receive all the 3 messages"); + for (int i = 1; i <= 3; i++) + { + message = (TextMessage) durSub1.receive(1000); + if (message == null) + { + _logger.debug("no message received "); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != i) + { + fail("wrong sequence number, " + i + " expected, received: " + message + .getLongProperty(_sequenceNumberPropertyName)); + } + } + stSession.commit(); + // send a non persistent message to check that all persistent messages are deleted + producer = stSession.createProducer(_topic); + producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); + producer.send(_message); + stSession.commit(); + message = (TextMessage) durSub.receive(1000); + if (message == null) + { + fail("message not received "); + } + message = (TextMessage) durSub1.receive(1000); + if (message == null) + { + fail("message not received "); + } + stSession.commit(); + stSession.close(); + _logger.debug(" now create a standard non transacted session and reconnect to the durable xubscriber"); + TopicConnection stConnection = + _topicConnection; //_topicFactory.createTopicConnection("guest", "guest"); + TopicSession autoAclSession = stConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + TopicPublisher publisher = autoAclSession.createPublisher(_topic); + durSub = autoAclSession.createDurableSubscriber(_topic, durSubName); + stConnection.start(); + // produce 3 persistent messages + for (int i = 1; i <= 3; i++) + { + _message.setLongProperty(_sequenceNumberPropertyName, i); + //producer.send( _message ); + publisher.send(_message, DeliveryMode.PERSISTENT, 9 - i, 0); + } + _logger.debug(" use dursub to receive all the 3 messages"); + for (int i = 1; i <= 3; i++) + { + message = (TextMessage) durSub.receive(1000); + if (message == null) + { + _logger.info("no message received "); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != i) + { + _logger.info("wrong sequence number, " + i + " expected, received: " + message + .getLongProperty(_sequenceNumberPropertyName)); + } + } + + _logger.debug("now set a message listener"); + AtomicBoolean lock = new AtomicBoolean(true); + reset(); + stConnection.stop(); + durSub.setMessageListener(new TopicListener(1, 3, lock)); + _logger.debug(" produce 3 persistent messages"); + for (int i = 1; i <= 3; i++) + { + _message.setLongProperty(_sequenceNumberPropertyName, i); + //producer.send( _message ); + publisher.send(_message, DeliveryMode.PERSISTENT, 9 - i, 0); + } + // start the connection + stConnection.start(); + while (lock.get()) + { + synchronized (lock) + { + lock.wait(); + } + } + if (getFailureStatus()) + { + fail("problem with message listener"); + } + stConnection.stop(); + durSub.setMessageListener(null); + _logger.debug(" do the same with an xa session"); + // produce 3 persistent messages + for (int i = 1; i <= 3; i++) + { + _message.setLongProperty(_sequenceNumberPropertyName, i); + //producer.send( _message ); + publisher.send(_message, DeliveryMode.PERSISTENT, 9 - i, 0); + } + //stConnection.close(); + autoAclSession.close(); + _logger.debug(" migrate the durable subscriber to an xa one"); + _session = _topicConnection.createXATopicSession(); + _xaResource = _session.getXAResource(); + _xaResource.start(xid2, XAResource.TMNOFLAGS); + durSub = _session.createDurableSubscriber(_topic, durSubName); + lock = new AtomicBoolean(); + reset(); + _topicConnection.stop(); + durSub.setMessageListener(new TopicListener(1, 3, lock)); + // start the connection + _topicConnection.start(); + while (lock.get()) + { + synchronized (lock) + { + lock.wait(); + } + } + if (getFailureStatus()) + { + fail("problem with XA message listener"); + } + _xaResource.end(xid2, XAResource.TMSUCCESS); + _xaResource.commit(xid2, true); + _session.close(); + } + catch (Exception e) + { + _logger.error("Exception thrown", e); + fail("Exception thrown: " + e.getMessage()); + } + finally + { + try + { + _topicConnection.createXASession().unsubscribe(durSubName); + _topicConnection.createXASession().unsubscribe(durSubName + "_second"); + } + catch (JMSException e) + { + fail("Exception thrown when unsubscribing durable subscriber " + e.getMessage()); + } + } + } + } + + /** -------------------------------------------------------------------------------------- **/ + /** ----------------------------- Utility methods --------------------------------------- **/ + /** -------------------------------------------------------------------------------------- **/ + + /** + * get a new queue connection + * + * @return a new queue connection + * @throws javax.jms.JMSException If the JMS provider fails to create the queue connection + * due to some internal error or in case of authentication failure + */ + private XATopicConnection getNewTopicXAConnection() throws JMSException + { + return _topicFactory.createXATopicConnection("guest", "guest"); + } + + public static void failure() + { + _failure = true; + } + + public static void reset() + { + _failure = false; + } + + public static boolean getFailureStatus() + { + return _failure; + } + + private class TopicListener implements MessageListener + { + private long _counter; + private long _end; + private final AtomicBoolean _lock; + + public TopicListener(long init, long end, AtomicBoolean lock) + { + _counter = init; + _end = end; + _lock = lock; + } + + public void onMessage(Message message) + { + long seq = 0; + try + { + seq = message.getLongProperty(TopicTest._sequenceNumberPropertyName); + } + catch (JMSException e) + { + _logger.error("Error getting long property: " + TopicTest._sequenceNumberPropertyName , e); + TopicTest.failure(); + _lock.set(false); + synchronized (_lock) + { + _lock.notifyAll(); + } + } + if (seq != _counter) + { + _logger.info("received message " + seq + " expected " + _counter); + TopicTest.failure(); + _lock.set(false); + synchronized (_lock) + { + _lock.notifyAll(); + } + } + _counter++; + if (_counter > _end) + { + _lock.set(false); + synchronized (_lock) + { + _lock.notifyAll(); + } + } + } + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/utils/BrokerCommandHelperTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/utils/BrokerCommandHelperTest.java new file mode 100644 index 0000000000..83c2f1e58d --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/utils/BrokerCommandHelperTest.java @@ -0,0 +1,79 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.test.utils; + +import static org.mockito.Mockito.*; + +import java.io.File; + +public class BrokerCommandHelperTest extends QpidTestCase +{ + private static final String PATH_TO_QPID_EXECUTABLE = "/path / to (/qpid"; + private static final String ARGUMENT_WITH_SPACES = " blah / blah /blah"; + private static final String ARGUMENT_PORT = "-p"; + private static final String ARGUMENT_PORT_VALUE = "@PORT"; + private static final String ARGUMENT_STORE_PATH = "-sp"; + private static final String ARGUMENT_STORE_PATH_VALUE = "@STORE_PATH"; + private static final String ARGUMENT_STORE_TYPE = "-st"; + private static final String ARGUMENT_STORE_TYPE_VALUE = "@STORE_TYPE"; + private static final String ARGUMENT_LOG = "-l"; + private static final String ARGUMENT_LOG_VALUE = "@LOG_CONFIG_FILE"; + + private BrokerCommandHelper _brokerCommandHelper; + + private File _logConfigFile = mock(File.class); + + @Override + public void setUp() + { + when(_logConfigFile.getAbsolutePath()).thenReturn("log Config File"); + _brokerCommandHelper = new BrokerCommandHelper("\"" + PATH_TO_QPID_EXECUTABLE + "\" " + ARGUMENT_PORT + " " + + ARGUMENT_PORT_VALUE + " " + ARGUMENT_STORE_PATH + " " + ARGUMENT_STORE_PATH_VALUE + " " + ARGUMENT_STORE_TYPE + + " " + ARGUMENT_STORE_TYPE_VALUE + " " + ARGUMENT_LOG + " " + ARGUMENT_LOG_VALUE + " '" + ARGUMENT_WITH_SPACES + + "'"); + } + + public void testGetBrokerCommand() + { + String[] brokerCommand = _brokerCommandHelper.getBrokerCommand(1, "path to config file", "json", _logConfigFile); + + String[] expected = { PATH_TO_QPID_EXECUTABLE, ARGUMENT_PORT, "1", ARGUMENT_STORE_PATH, "path to config file", + ARGUMENT_STORE_TYPE, "json", ARGUMENT_LOG, "\"log Config File\"", ARGUMENT_WITH_SPACES }; + assertEquals("Unexpected broker command", expected.length, brokerCommand.length); + for (int i = 0; i < expected.length; i++) + { + assertEquals("Unexpected command part value at " + i,expected[i], brokerCommand[i] ); + } + } + + public void testRemoveBrokerCommandLog4JFile() + { + _brokerCommandHelper.removeBrokerCommandLog4JFile(); + String[] brokerCommand = _brokerCommandHelper.getBrokerCommand(1, "configFile", "json", _logConfigFile); + + String[] expected = { PATH_TO_QPID_EXECUTABLE, ARGUMENT_PORT, "1", ARGUMENT_STORE_PATH, "configFile", + ARGUMENT_STORE_TYPE, "json", ARGUMENT_WITH_SPACES }; + + assertEquals("Unexpected broker command", expected.length, brokerCommand.length); + for (int i = 0; i < expected.length; i++) + { + assertEquals("Unexpected command part value at " + i,expected[i], brokerCommand[i] ); + } + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/utils/ConversationFactory.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/utils/ConversationFactory.java new file mode 100644 index 0000000000..3a9354d822 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/utils/ConversationFactory.java @@ -0,0 +1,484 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.utils; + +import org.apache.log4j.Logger; + +import javax.jms.Connection; +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 java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +/** + * A conversation helper, uses a message correlation id pattern to match up sent and received messages as a conversation + * over JMS messaging. Incoming message traffic is divided up by correlation id. Each id has a queue (behaviour dependant + * on the queue implementation). Clients of this de-multiplexer can wait on messages, defined by message correlation ids. + * + *

One use of this is as a conversation synchronizer where multiple threads are carrying out conversations over a + * multiplexed messaging route. This can be usefull, as JMS sessions are not multi-threaded. Setting up the conversation + * with synchronous queues will allow these threads to be written in a synchronous style, but with their execution order + * governed by the asynchronous message flow. For example, something like the following code could run a multi-threaded + * conversation (the conversation methods can be called many times in parallel): + * + *

+ * class Initiator
+ * {
+ * ConversationHelper conversation = new ConversationHelper(connection, null,
+ *                                                          java.util.concurrent.LinkedBlockingQueue.class);
+ *
+ * initiateConversation()
+ * {
+ *  try {
+ *   // Exchange greetings.
+ *   conversation.send(sendDestination, conversation.getSession().createTextMessage("Hello."));
+ *   Message greeting = conversation.receive();
+ *
+ *   // Exchange goodbyes.
+ *   conversation.send(conversation.getSession().createTextMessage("Goodbye."));
+ *   Message goodbye = conversation.receive();
+ *  } finally {
+ *   conversation.end();
+ *  }
+ * }
+ * }
+ *
+ * class Responder
+ * {
+ * ConversationHelper conversation = new ConversationHelper(connection, receiveDestination,
+ *                                                          java.util.concurrent.LinkedBlockingQueue.class);
+ *
+ * respondToConversation()
+ * {
+ *   try {
+ *   // Exchange greetings.
+ *   Message greeting = conversation.receive();
+ *   conversation.send(conversation.getSession().createTextMessage("Hello."));
+ *
+ *   // Exchange goodbyes.
+ *   Message goodbye = conversation.receive();
+ *   conversation.send(conversation.getSession().createTextMessage("Goodbye."));
+ *  } finally {
+ *   conversation.end();
+ *  }
+ * }
+ * }
+ * 
+ * + *

Conversation correlation id's are generated on a per thread basis. + * + *

The same controlSession is shared amongst all conversations. Calls to send are therefore synchronized because JMS + * sessions are not multi-threaded. + * + *

+ *
CRC Card
Responsibilities Collaborations + *
Associate messages to an ongoing conversation using correlation ids. + *
Auto manage sessions for conversations. + *
Store messages not in a conversation in dead letter box. + *
+ */ +public class ConversationFactory +{ + /** Used for debugging. */ + private static final Logger log = Logger.getLogger(ConversationFactory.class); + + /** Holds a map from correlation id's to queues. */ + private Map> idsToQueues = new HashMap>(); + + /** Holds the connection over which the conversation is conducted. */ + private Connection connection; + + /** Holds the controlSession over which the conversation is conduxted. */ + private Session session; + + /** The message consumer for incoming messages. */ + private MessageConsumer consumer; + + /** The message producer for outgoing messages. */ + private MessageProducer producer; + + /** The well-known or temporary destination to receive replies on. */ + private Destination receiveDestination; + + /** Holds the queue implementation class for the reply queue. */ + private Class queueClass; + + /** Used to hold any replies that are received outside of the context of a conversation. */ + private BlockingQueue deadLetterBox = new LinkedBlockingQueue(); + + /* Used to hold conversation state on a per thread basis. */ + /* + ThreadLocal threadLocals = + new ThreadLocal() + { + protected Conversation initialValue() + { + Conversation settings = new Conversation(); + settings.conversationId = conversationIdGenerator.getAndIncrement(); + + return settings; + } + }; + */ + + /** Generates new coversation id's as needed. */ + private AtomicLong conversationIdGenerator = new AtomicLong(); + + /** + * Creates a conversation helper on the specified connection with the default sending destination, and listening + * to the specified receiving destination. + * + * @param connection The connection to build the conversation helper on. + * @param receiveDestination The destination to listen to for incoming messages. This may be null to use a temporary + * queue. + * @param queueClass The queue implementation class. + * + * @throws JMSException All underlying JMSExceptions are allowed to fall through. + */ + public ConversationFactory(Connection connection, Destination receiveDestination, + Class queueClass) throws JMSException + { + log.debug("public ConversationFactory(Connection connection, Destination receiveDestination = " + receiveDestination + + ", Class queueClass = " + queueClass + "): called"); + + this.connection = connection; + this.queueClass = queueClass; + + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // Check if a well-known receive destination has been provided, or use a temporary queue if not. + this.receiveDestination = (receiveDestination != null) ? receiveDestination : session.createTemporaryQueue(); + + consumer = session.createConsumer(receiveDestination); + producer = session.createProducer(null); + + consumer.setMessageListener(new Receiver()); + } + + /** + * Creates a new conversation context. + * + * @return A new conversation context. + */ + public Conversation startConversation() + { + log.debug("public Conversation startConversation(): called"); + + Conversation conversation = new Conversation(); + conversation.conversationId = conversationIdGenerator.getAndIncrement(); + + return conversation; + } + + /** + * Ensures that the reply queue for a conversation exists. + * + * @param conversationId The conversation correlation id. + */ + private void initQueueForId(long conversationId) + { + if (!idsToQueues.containsKey(conversationId)) + { + idsToQueues.put(conversationId, ReflectionUtils.newInstance(queueClass)); + } + } + + /** + * Clears the dead letter box, returning all messages that were in it. + * + * @return All messages in the dead letter box. + */ + public Collection emptyDeadLetterBox() + { + log.debug("public Collection emptyDeadLetterBox(): called"); + + Collection result = new ArrayList(); + deadLetterBox.drainTo(result); + + return result; + } + + /** + * Gets the controlSession over which the conversation is conducted. + * + * @return The controlSession over which the conversation is conducted. + */ + public Session getSession() + { + // Conversation settings = threadLocals.get(); + + return session; + } + + /** + * Used to hold a conversation context. This consists of a correlating id for the conversation, and a reply + * destination automatically updated to the last received reply-to destination. + */ + public class Conversation + { + /** Holds the correlation id for the context. */ + private long conversationId; + + /** + * Holds the send destination for the context. This will automatically be updated to the most recently received + * reply-to destination. + */ + private Destination sendDestination; + + /** + * Sends a message to the default sending location. The correlation id of the message will be assigned by this + * method, overriding any previously set value. + * + * @param sendDestination The destination to send to. This may be null to use the last received reply-to + * destination. + * @param message The message to send. + * + * @throws JMSException All undelying JMSExceptions are allowed to fall through. This will also be thrown if no + * send destination is specified and there is no most recent reply-to destination available + * to use. + */ + public void send(Destination sendDestination, Message message) throws JMSException + { + log.debug("public void send(Destination sendDestination = " + sendDestination + ", Message message = " + + message.getJMSMessageID() + "): called"); + + // Conversation settings = threadLocals.get(); + // long conversationId = conversationId; + message.setJMSCorrelationID(Long.toString(conversationId)); + message.setJMSReplyTo(receiveDestination); + + // Ensure that the reply queue for this conversation exists. + initQueueForId(conversationId); + + // Check if an overriding send to destination has been set or use the last reply-to if not. + Destination sendTo = null; + + if (sendDestination != null) + { + sendTo = sendDestination; + } + else + { + throw new JMSException("The send destination was specified, and no most recent reply-to available to use."); + } + + // Send the message. + synchronized (this) + { + producer.send(sendTo, message); + } + } + + /** + * Gets the next message in an ongoing conversation. This method may block until such a message is received. + * + * @return The next incoming message in the conversation. + * + * @throws JMSException All undelying JMSExceptions are allowed to fall through. Thrown if the received message + * did not have its reply-to destination set up. + */ + public Message receive() throws JMSException + { + log.debug("public Message receive(): called"); + + // Conversation settings = threadLocals.get(); + // long conversationId = settings.conversationId; + + // Ensure that the reply queue for this conversation exists. + initQueueForId(conversationId); + + BlockingQueue queue = idsToQueues.get(conversationId); + + try + { + Message result = queue.take(); + + // Keep the reply-to destination to send replies to. + sendDestination = result.getJMSReplyTo(); + + return result; + } + catch (InterruptedException e) + { + return null; + } + } + + /** + * Gets many messages in an ongoing conversation. If a limit is specified, then once that many messages are + * received they will be returned. If a timeout is specified, then all messages up to the limit, received within + * that timespan will be returned. At least one of the message count or timeout should be set to a value of + * 1 or greater. + * + * @param num The number of messages to receive, or all if this is less than 1. + * @param timeout The timeout in milliseconds to receive the messages in, or forever if this is less than 1. + * + * @return All messages received within the count limit and the timeout. + * + * @throws JMSException All undelying JMSExceptions are allowed to fall through. + */ + public Collection receiveAll(int num, long timeout) throws JMSException + { + log.debug("public Collection receiveAll(int num = " + num + ", long timeout = " + timeout + + "): called"); + + // Check that a timeout or message count was set. + if ((num < 1) && (timeout < 1)) + { + throw new IllegalArgumentException("At least one of message count (num) or timeout must be set."); + } + + // Ensure that the reply queue for this conversation exists. + initQueueForId(conversationId); + BlockingQueue queue = idsToQueues.get(conversationId); + + // Used to collect the received messages in. + Collection result = new ArrayList(); + + // Used to indicate when the timeout or message count has expired. + boolean receiveMore = true; + + int messageCount = 0; + + // Receive messages until the timeout or message count expires. + do + { + try + { + Message next = null; + + // Try to receive the message with a timeout if one has been set. + if (timeout > 0) + { + next = queue.poll(timeout, TimeUnit.MILLISECONDS); + + // Check if the timeout expired, and stop receiving if so. + if (next == null) + { + receiveMore = false; + } + } + // Receive the message without a timeout. + else + { + next = queue.take(); + } + + // Increment the message count if a message was received. + messageCount += (next != null) ? 1 : 0; + + // Check if all the requested messages were received, and stop receiving if so. + if ((num > 0) && (messageCount >= num)) + { + receiveMore = false; + } + + // Keep the reply-to destination to send replies to. + sendDestination = (next != null) ? next.getJMSReplyTo() : sendDestination; + + if (next != null) + { + result.add(next); + } + } + catch (InterruptedException e) + { + // Restore the threads interrupted status. + Thread.currentThread().interrupt(); + + // Stop receiving but return the messages received so far. + receiveMore = false; + } + } + while (receiveMore); + + return result; + } + + /** + * Completes the conversation. Any correlation id's pertaining to the conversation are no longer valid, and any + * incoming messages using them will go to the dead letter box. + */ + public void end() + { + log.debug("public void end(): called"); + + // Ensure that the thread local for the current thread is cleaned up. + // Conversation settings = threadLocals.get(); + // long conversationId = settings.conversationId; + // threadLocals.remove(); + + // Ensure that its queue is removed from the queue map. + BlockingQueue queue = idsToQueues.remove(conversationId); + + // Move any outstanding messages on the threads conversation id into the dead letter box. + queue.drainTo(deadLetterBox); + } + } + + /** + * Implements the message listener for this conversation handler. + */ + protected class Receiver implements MessageListener + { + /** + * Handles all incoming messages in the ongoing conversations. These messages are split up by correaltion id + * and placed into queues. + * + * @param message The incoming message. + */ + public void onMessage(Message message) + { + log.debug("public void onMessage(Message message = " + message + "): called"); + + try + { + Long conversationId = Long.parseLong(message.getJMSCorrelationID()); + + // Find the converstaion queue to place the message on. If there is no conversation for the message id, + // the the dead letter box queue is used. + BlockingQueue queue = idsToQueues.get(conversationId); + queue = (queue == null) ? deadLetterBox : queue; + + queue.put(message); + } + catch (JMSException e) + { + throw new RuntimeException(e); + } + catch (InterruptedException e) + { + throw new RuntimeException(e); + } + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/utils/FailoverBaseCase.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/utils/FailoverBaseCase.java new file mode 100644 index 0000000000..f6c481431a --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/utils/FailoverBaseCase.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.test.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.client.AMQConnectionFactory; +import org.apache.qpid.util.FileUtils; + +import javax.naming.NamingException; + +public class FailoverBaseCase extends QpidBrokerTestCase +{ + protected static final Logger _logger = LoggerFactory.getLogger(FailoverBaseCase.class); + + public static final long DEFAULT_FAILOVER_TIME = 10000L; + + protected void setUp() throws java.lang.Exception + { + super.setUp(); + startBroker(getFailingPort()); + } + + /** + * We are using failover factories + * + * @return a connection + * @throws Exception + */ + @Override + public AMQConnectionFactory getConnectionFactory() throws NamingException + { + _logger.info("get ConnectionFactory"); + if (_connectionFactory == null) + { + if (Boolean.getBoolean("profile.use_ssl")) + { + _connectionFactory = getConnectionFactory("failover.ssl"); + } + else + { + _connectionFactory = getConnectionFactory("failover"); + } + } + return _connectionFactory; + } + + public void tearDown() throws Exception + { + try + { + super.tearDown(); + } + finally + { + // Ensure we shutdown any secondary brokers, even if we are unable + // to cleanly tearDown the QTC. + stopBroker(getFailingPort()); + FileUtils.deleteDirectory(System.getProperty("QPID_WORK") + "/" + getFailingPort()); + } + } + + public void failBroker(int port) + { + try + { + //TODO: use killBroker instead + stopBroker(port); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/test/utils/QpidClientConnection.java b/qpid/java/systests/src/test/java/org/apache/qpid/test/utils/QpidClientConnection.java new file mode 100644 index 0000000000..0e0032da64 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/test/utils/QpidClientConnection.java @@ -0,0 +1,288 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.test.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.JMSAMQException; + +import javax.jms.Connection; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +public class QpidClientConnection extends QpidBrokerTestCase implements ExceptionListener +{ + private static final Logger _logger = LoggerFactory.getLogger(QpidClientConnection.class); + + private boolean transacted = true; + private int ackMode = Session.CLIENT_ACKNOWLEDGE; + private Connection connection; + + private String virtualHost; + private String brokerlist; + private int prefetch; + protected Session session; + protected boolean connected; + + public QpidClientConnection(String broker) + { + super(); + setVirtualHost("/test"); + setBrokerList(broker); + setPrefetch(5000); + } + + + public Connection getConnection() + { + return connection; + } + + public void connect() throws JMSException + { + if (!connected) + { + /* + * amqp://[user:pass@][clientid]/virtualhost? + * brokerlist='[transport://]host[:port][?option='value'[&option='value']];' + * [&failover='method[?option='value'[&option='value']]'] + * [&option='value']" + */ + String brokerUrl = "amqp://guest:guest@" + virtualHost + "?brokerlist='" + brokerlist + "'"; + try + { + _logger.info("connecting to Qpid :" + brokerUrl); + connection = getConnection("guest", "guest") ; + // register exception listener + connection.setExceptionListener(this); + + session = ((AMQConnection) connection).createSession(transacted, ackMode, prefetch); + + _logger.info("starting connection"); + connection.start(); + + connected = true; + } + catch (Exception e) + { + throw new JMSAMQException("URL syntax error in [" + brokerUrl + "]: " + e.getMessage(), e); + } + } + } + + public void disconnect() throws Exception + { + if (connected) + { + session.commit(); + session.close(); + connection.close(); + connected = false; + _logger.info("disconnected"); + } + } + + public void disconnectWithoutCommit() throws JMSException + { + if (connected) + { + session.close(); + connection.close(); + connected = false; + _logger.info("disconnected without commit"); + } + } + + public String getBrokerList() + { + return brokerlist; + } + + public void setBrokerList(String brokerlist) + { + this.brokerlist = brokerlist; + } + + public String getVirtualHost() + { + return virtualHost; + } + + public void setVirtualHost(String virtualHost) + { + this.virtualHost = virtualHost; + } + + public void setPrefetch(int prefetch) + { + this.prefetch = prefetch; + } + + /** override as necessary */ + public void onException(JMSException exception) + { + _logger.info("ExceptionListener event: error " + exception.getErrorCode() + ", message: " + exception.getMessage()); + } + + public boolean isConnected() + { + return connected; + } + + public Session getSession() + { + return session; + } + + /** + * Put a String as a text messages, repeat n times. A null payload will result in a null message. + * + * @param queueName The queue name to put to + * @param payload the content of the payload + * @param copies the number of messages to put + * + * @throws javax.jms.JMSException any exception that occurs + */ + public void put(String queueName, String payload, int copies) throws JMSException + { + if (!connected) + { + connect(); + } + + _logger.info("putting to queue " + queueName); + Queue queue = session.createQueue(queueName); + + final MessageProducer sender = session.createProducer(queue); + + for (int i = 0; i < copies; i++) + { + Message m = session.createTextMessage(payload + i); + m.setIntProperty("index", i + 1); + sender.send(m); + } + + session.commit(); + sender.close(); + _logger.info("put " + copies + " copies"); + } + + /** + * GET the top message on a queue. Consumes the message. Accepts timeout value. + * + * @param queueName The quename to get from + * @param readTimeout The timeout to use + * + * @return the content of the text message if any + * + * @throws javax.jms.JMSException any exception that occured + */ + public Message getNextMessage(String queueName, long readTimeout) throws JMSException + { + if (!connected) + { + connect(); + } + + Queue queue = session.createQueue(queueName); + + final MessageConsumer consumer = session.createConsumer(queue); + + Message message = consumer.receive(readTimeout); + session.commit(); + consumer.close(); + + Message result; + + // all messages we consume should be TextMessages + if (message instanceof TextMessage) + { + result = ((TextMessage) message); + } + else if (null == message) + { + result = null; + } + else + { + _logger.info("warning: received non-text message"); + result = message; + } + + return result; + } + + /** + * GET the top message on a queue. Consumes the message. + * + * @param queueName The Queuename to get from + * + * @return The string content of the text message, if any received + * + * @throws javax.jms.JMSException any exception that occurs + */ + public Message getNextMessage(String queueName) throws JMSException + { + return getNextMessage(queueName, 0); + } + + /** + * Completely clears a queue. For readTimeout behaviour see Javadocs for javax.jms.MessageConsumer. + * + * @param queueName The Queue name to consume from + * @param readTimeout The timeout for each consume + * + * @throws javax.jms.JMSException Any exception that occurs during the consume + * @throws InterruptedException If the consume thread was interrupted during a consume. + */ + public void consume(String queueName, int readTimeout) throws JMSException, InterruptedException + { + if (!connected) + { + connect(); + } + + _logger.info("consuming queue " + queueName); + Queue queue = session.createQueue(queueName); + + final MessageConsumer consumer = session.createConsumer(queue); + int messagesReceived = 0; + + _logger.info("consuming..."); + while ((consumer.receive(readTimeout)) != null) + { + messagesReceived++; + } + + session.commit(); + consumer.close(); + _logger.info("consumed: " + messagesReceived); + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/transport/MaxFrameSizeTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/transport/MaxFrameSizeTest.java new file mode 100644 index 0000000000..322b971487 --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/transport/MaxFrameSizeTest.java @@ -0,0 +1,349 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.transport; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.naming.NamingException; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; + +import org.apache.qpid.codec.MarkableDataInput; +import org.apache.qpid.framing.AMQBody; +import org.apache.qpid.framing.AMQDataBlockDecoder; +import org.apache.qpid.framing.AMQFrame; +import org.apache.qpid.framing.AMQFrameDecodingException; +import org.apache.qpid.framing.AMQProtocolVersionException; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.framing.BodyFactory; +import org.apache.qpid.framing.ByteArrayDataInput; +import org.apache.qpid.framing.ConnectionCloseBody; +import org.apache.qpid.framing.ConnectionStartOkBody; +import org.apache.qpid.framing.ConnectionTuneOkBody; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.framing.amqp_0_91.ConnectionStartOkBodyImpl; +import org.apache.qpid.framing.amqp_0_91.ConnectionTuneOkBodyImpl; +import org.apache.qpid.framing.amqp_0_91.MethodRegistry_0_91; +import org.apache.qpid.jms.BrokerDetails; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.protocol.v0_8.ProtocolEngineCreator_0_8; +import org.apache.qpid.server.protocol.v0_8.ProtocolEngineCreator_0_9; +import org.apache.qpid.server.protocol.v0_8.ProtocolEngineCreator_0_9_1; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.test.utils.TestBrokerConfiguration; + +public class MaxFrameSizeTest extends QpidBrokerTestCase +{ + + @Override + public void setUp() throws Exception + { + // don't call super.setup() as we want a change to set stuff up before the broker starts + // super.setUp(); + } + + public void testTooSmallFrameSize() throws Exception + { + + getBrokerConfiguration().setObjectAttribute(AuthenticationProvider.class, + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, + "secureOnlyMechanisms", + "[]"); + super.setUp(); + + if(isBroker010()) + { + Connection conn = new Connection(); + final ConnectionSettings settings = new ConnectionSettings(); + BrokerDetails brokerDetails = getConnectionFactory().getConnectionURL().getAllBrokerDetails().get(0); + settings.setHost(brokerDetails.getHost()); + settings.setPort(brokerDetails.getPort()); + settings.setUsername(GUEST_USERNAME); + settings.setPassword(GUEST_PASSWORD); + final ConnectionDelegate clientDelegate = new TestClientDelegate(settings, 1024); + conn.setConnectionDelegate(clientDelegate); + try + { + conn.connect(settings); + fail("Connection should not be possible with a frame size < " + Constant.MIN_MAX_FRAME_SIZE); + } + catch(ConnectionException e) + { + // pass + } + + } + else + { + doAMQP08test(1024, new ResultEvaluator() + { + + @Override + public void evaluate(final Socket socket, final List frames) + { + if(!socket.isClosed()) + { + AMQFrame lastFrame = frames.get(frames.size() - 1); + assertTrue("Connection should not be possible with a frame size < " + Constant.MIN_MAX_FRAME_SIZE, lastFrame.getBodyFrame() instanceof ConnectionCloseBody); + } + } + }); + } + } + + + public void testTooLargeFrameSize() throws Exception + { + getBrokerConfiguration().setObjectAttribute(AuthenticationProvider.class, + TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER, + "secureOnlyMechanisms", + "[]"); + setTestSystemProperty(Broker.BROKER_FRAME_SIZE, "8192"); + super.setUp(); + if(isBroker010()) + { + Connection conn = new Connection(); + final ConnectionSettings settings = new ConnectionSettings(); + BrokerDetails brokerDetails = getConnectionFactory().getConnectionURL().getAllBrokerDetails().get(0); + settings.setHost(brokerDetails.getHost()); + settings.setPort(brokerDetails.getPort()); + settings.setUsername(GUEST_USERNAME); + settings.setPassword(GUEST_PASSWORD); + final ConnectionDelegate clientDelegate = new TestClientDelegate(settings, 0xffff); + conn.setConnectionDelegate(clientDelegate); + try + { + conn.connect(settings); + fail("Connection should not be possible with a frame size larger than the broker requested"); + } + catch(ConnectionException e) + { + // pass + } + + } + else + { + doAMQP08test(10000, new ResultEvaluator() + { + + @Override + public void evaluate(final Socket socket, final List frames) + { + if(!socket.isClosed()) + { + AMQFrame lastFrame = frames.get(frames.size() - 1); + assertTrue("Connection should not be possible with a frame size larger than the broker requested", lastFrame.getBodyFrame() instanceof ConnectionCloseBody); + } + } + }); + } + } + + private static interface ResultEvaluator + { + void evaluate(Socket socket, List frames); + } + + private void doAMQP08test(int frameSize, ResultEvaluator evaluator) + throws NamingException, IOException, AMQFrameDecodingException, AMQProtocolVersionException + { + BrokerDetails brokerDetails = getConnectionFactory().getConnectionURL().getAllBrokerDetails().get(0); + + Socket socket = new Socket(brokerDetails.getHost(), brokerDetails.getPort()); + socket.setTcpNoDelay(true); + OutputStream os = socket.getOutputStream(); + + byte[] protocolHeader; + Protocol protocol = getBrokerProtocol(); + switch(protocol) + { + case AMQP_0_8: + protocolHeader = (ProtocolEngineCreator_0_8.getInstance().getHeaderIdentifier()); + break; + case AMQP_0_9: + protocolHeader = (ProtocolEngineCreator_0_9.getInstance().getHeaderIdentifier()); + break; + case AMQP_0_9_1: + protocolHeader = (ProtocolEngineCreator_0_9_1.getInstance().getHeaderIdentifier()); + break; + default: + throw new RuntimeException("Unexpected Protocol Version: " + protocol); + } + os.write(protocolHeader); + InputStream is = socket.getInputStream(); + + final byte[] response = new byte[2+GUEST_USERNAME.length()+GUEST_PASSWORD.length()]; + int i = 1; + for(byte b : GUEST_USERNAME.getBytes(StandardCharsets.US_ASCII)) + { + response[i++] = b; + } + i++; + for(byte b : GUEST_PASSWORD.getBytes(StandardCharsets.US_ASCII)) + { + response[i++] = b; + } + + ConnectionStartOkBody startOK = new ConnectionStartOkBodyImpl(new FieldTable(), AMQShortString.valueOf("PLAIN"), response, AMQShortString.valueOf("en_US")); + + DataOutputStream dos = new DataOutputStream(os); + new AMQFrame(0, startOK).writePayload(dos); + dos.flush(); + ConnectionTuneOkBody tuneOk = new ConnectionTuneOkBodyImpl(256, frameSize, 0); + new AMQFrame(0, tuneOk).writePayload(dos); + dos.flush(); + socket.setSoTimeout(5000); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int size; + while((size = is.read(buffer)) > 0) + { + baos.write(buffer,0,size); + } + + byte[] serverData = baos.toByteArray(); + ByteArrayDataInput badi = new ByteArrayDataInput(serverData); + AMQDataBlockDecoder datablockDecoder = new AMQDataBlockDecoder(); + final MethodRegistry_0_91 methodRegistry_0_91 = new MethodRegistry_0_91(); + BodyFactory methodBodyFactory = new BodyFactory() + { + @Override + public AMQBody createBody(final MarkableDataInput in, final long bodySize) + throws AMQFrameDecodingException, IOException + { + return methodRegistry_0_91.convertToBody(in, bodySize); + } + }; + + List frames = new ArrayList<>(); + while (datablockDecoder.decodable(badi)) + { + frames.add(datablockDecoder.createAndPopulateFrame(methodBodyFactory, badi)); + } + + evaluator.evaluate(socket, frames); + } + + private static class TestClientDelegate extends ClientDelegate + { + + private final int _maxFrameSize; + + public TestClientDelegate(final ConnectionSettings settings, final int maxFrameSize) + { + super(settings); + _maxFrameSize = maxFrameSize; + } + + @Override + protected SaslClient createSaslClient(final List brokerMechs) throws ConnectionException, SaslException + { + final CallbackHandler handler = new CallbackHandler() + { + @Override + public void handle(final Callback[] callbacks) throws IOException, UnsupportedCallbackException + { + for (int i = 0; i < callbacks.length; i++) + { + Callback cb = callbacks[i]; + if (cb instanceof NameCallback) + { + ((NameCallback)cb).setName(GUEST_USERNAME); + } + else if (cb instanceof PasswordCallback) + { + ((PasswordCallback)cb).setPassword(GUEST_PASSWORD.toCharArray()); + } + else + { + throw new UnsupportedCallbackException(cb); + } + } + + } + }; + String[] selectedMechs = {}; + for(String mech : new String[] { "ANONYMOUS", "PLAIN", "CRAM-MD5", "SCRAM-SHA-1", "SCRAM-SHA-256"}) + { + if(brokerMechs.contains(mech)) + { + selectedMechs = new String[] {mech}; + break; + } + } + + + return Sasl.createSaslClient(selectedMechs, + null, + getConnectionSettings().getSaslProtocol(), + getConnectionSettings().getSaslServerName(), + Collections.emptyMap(), + handler); + + } + + @Override + public void connectionTune(Connection conn, ConnectionTune tune) + { + int heartbeatInterval = getConnectionSettings().getHeartbeatInterval010(); + float heartbeatTimeoutFactor = getConnectionSettings().getHeartbeatTimeoutFactor(); + int actualHeartbeatInterval = calculateHeartbeatInterval(heartbeatInterval, + tune.getHeartbeatMin(), + tune.getHeartbeatMax()); + + conn.connectionTuneOk(tune.getChannelMax(), + _maxFrameSize, + actualHeartbeatInterval); + + int idleTimeout = (int)(actualHeartbeatInterval * 1000 * heartbeatTimeoutFactor); + conn.getNetworkConnection().setMaxReadIdle((int)(actualHeartbeatInterval*heartbeatTimeoutFactor)); + conn.getNetworkConnection().setMaxWriteIdle(actualHeartbeatInterval); + conn.setMaxFrameSize(_maxFrameSize); + + + conn.setIdleTimeout(idleTimeout); + + int channelMax = tune.getChannelMax(); + conn.setChannelMax(channelMax == 0 ? Connection.MAX_CHANNEL_MAX : channelMax); + + conn.connectionOpen(getConnectionSettings().getVhost(), null, Option.INSIST); + } + + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/util/ClasspathScanner.java b/qpid/java/systests/src/test/java/org/apache/qpid/util/ClasspathScanner.java new file mode 100644 index 0000000000..151d1473ac --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/util/ClasspathScanner.java @@ -0,0 +1,239 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.util; + +import org.apache.log4j.Logger; + +import java.io.File; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * An ClasspathScanner scans the classpath for classes that implement an interface or extend a base class and have names + * that match a regular expression. + * + *

In order to test whether a class implements an interface or extends a class, the class must be loaded (unless + * the class files were to be scanned directly). Using this collector can cause problems when it scans the classpath, + * because loading classes will initialize their statics, which in turn may cause undesired side effects. For this + * reason, the collector should always be used with a regular expression, through which the class file names are + * filtered, and only those that pass this filter will be tested. For example, if you define tests in classes that + * end with the keyword "Test" then use the regular expression "Test$" to match this. + * + *

+ *
CRC Card
Responsibilities Collaborations + *
Find all classes matching type and name pattern on the classpath. + *
+ * + * @todo Add logic to scan jars as well as directories. + */ +public class ClasspathScanner +{ + private static final Logger log = Logger.getLogger(ClasspathScanner.class); + + /** + * Scans the classpath and returns all classes that extend a specified class and match a specified name. + * There is an flag that can be used to indicate that only Java Beans will be matched (that is, only those classes + * that have a default constructor). + * + * @param matchingClass The class or interface to match. + * @param matchingRegexp The regular expression to match against the class name. + * @param beanOnly Flag to indicate that onyl classes with default constructors should be matched. + * + * @return All the classes that match this collector. + */ + public static Collection> getMatches(Class matchingClass, String matchingRegexp, + boolean beanOnly) + { + log.debug("public static Collection> getMatches(Class matchingClass = " + matchingClass + + ", String matchingRegexp = " + matchingRegexp + ", boolean beanOnly = " + beanOnly + "): called"); + + // Build a compiled regular expression from the pattern to match. + Pattern matchPattern = Pattern.compile(matchingRegexp); + + String classPath = System.getProperty("java.class.path"); + Map> result = new HashMap>(); + + log.debug("classPath = " + classPath); + + // Find matching classes starting from all roots in the classpath. + for (String path : splitClassPath(classPath)) + { + gatherFiles(new File(path), "", result, matchPattern, matchingClass); + } + + return result.values(); + } + + /** + * Finds all matching classes rooted at a given location in the file system. If location is a directory it + * is recursively examined. + * + * @param classRoot The root of the current point in the file system being examined. + * @param classFileName The name of the current file or directory to examine. + * @param result The accumulated mapping from class names to classes that match the scan. + * + * @todo Recursion ok as file system depth is not likely to exhaust the stack. Might be better to replace with + * iteration. + */ + private static void gatherFiles(File classRoot, String classFileName, Map> result, + Pattern matchPattern, Class matchClass) + { + log.debug("private static void gatherFiles(File classRoot = " + classRoot + ", String classFileName = " + + classFileName + ", Map> result, Pattern matchPattern = " + matchPattern + + ", Class matchClass = " + matchClass + "): called"); + + File thisRoot = new File(classRoot, classFileName); + + // If the current location is a file, check if it is a matching class. + if (thisRoot.isFile()) + { + // Check that the file has a matching name. + if (matchesName(thisRoot.getName(), matchPattern)) + { + String className = classNameFromFile(thisRoot.getName()); + + // Check that the class has matching type. + try + { + Class candidateClass = Class.forName(className); + + Class matchedClass = matchesClass(candidateClass, matchClass); + + if (matchedClass != null) + { + result.put(className, matchedClass); + } + } + catch (ClassNotFoundException e) + { + // Ignore this. The matching class could not be loaded. + log.debug("Got ClassNotFoundException, ignoring.", e); + } + } + + return; + } + // Otherwise the current location is a directory, so examine all of its contents. + else + { + String[] contents = thisRoot.list(); + + if (contents != null) + { + for (String content : contents) + { + gatherFiles(classRoot, classFileName + File.separatorChar + content, result, matchPattern, matchClass); + } + } + } + } + + /** + * Checks if the specified class file name corresponds to a class with name matching the specified regular expression. + * + * @param classFileName The class file name. + * @param matchPattern The regular expression pattern to match. + * + * @return true if the class name matches, false otherwise. + */ + private static boolean matchesName(String classFileName, Pattern matchPattern) + { + String className = classNameFromFile(classFileName); + Matcher matcher = matchPattern.matcher(className); + + return matcher.matches(); + } + + /** + * Checks if the specified class to compare extends the base class being scanned for. + * + * @param matchingClass The base class to match against. + * @param toMatch The class to match against the base class. + * + * @return The class to check, cast as an instance of the class to match if the class extends the base class, or + * null otherwise. + */ + private static Class matchesClass(Class matchingClass, Class toMatch) + { + try + { + return matchingClass.asSubclass(toMatch); + } + catch (ClassCastException e) + { + return null; + } + } + + /** + * Takes a classpath (which is a series of paths) and splits it into its component paths. + * + * @param classPath The classpath to split. + * + * @return A list of the component paths that make up the class path. + */ + private static List splitClassPath(String classPath) + { + List result = new LinkedList(); + String separator = System.getProperty("path.separator"); + StringTokenizer tokenizer = new StringTokenizer(classPath, separator); + + while (tokenizer.hasMoreTokens()) + { + result.add(tokenizer.nextToken()); + } + + return result; + } + + /** + * Translates from the filename of a class to its fully qualified classname. Files are named using forward slash + * seperators and end in ".class", whereas fully qualified class names use "." sperators and no ".class" ending. + * + * @param classFileName The filename of the class to translate to a class name. + * + * @return The fully qualified class name. + */ + private static String classNameFromFile(String classFileName) + { + log.debug("private static String classNameFromFile(String classFileName = " + classFileName + "): called"); + + // Remove the .class ending. + String s = classFileName.substring(0, classFileName.length() - ".class".length()); + + // Turn / seperators in . seperators. + String s2 = s.replace(File.separatorChar, '.'); + + // Knock off any leading . caused by a leading /. + if (s2.startsWith(".")) + { + return s2.substring(1); + } + + return s2; + } +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/util/LogMonitor.java b/qpid/java/systests/src/test/java/org/apache/qpid/util/LogMonitor.java new file mode 100644 index 0000000000..d77731d09f --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/util/LogMonitor.java @@ -0,0 +1,336 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.util; + +import org.apache.log4j.FileAppender; +import org.apache.log4j.Logger; +import org.apache.log4j.SimpleLayout; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.LineNumberReader; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * Utility to simplify the monitoring of Log4j file output + * + * Monitoring of a given log file can be done alternatively the Monitor will + * add a new log4j FileAppender to the root Logger to gather all the available + * logging for monitoring + */ +public class LogMonitor +{ + private static final Logger _logger = Logger.getLogger(LogMonitor.class); + + // The file that the log statements will be written to. + private final File _logfile; + + // The appender we added to the get messages + private final FileAppender _appender; + + private int _linesToSkip = 0; + + /** + * Create a new LogMonitor that creates a new Log4j Appender and monitors + * all log4j output via the current configuration. + * + * @throws IOException if there is a problem creating the temporary file. + */ + public LogMonitor() throws IOException + { + this(null); + } + + /** + * Create a new LogMonitor on the specified file if the file does not exist + * or the value is null then a new Log4j appender will be added and + * monitoring set up on that appender. + * + * NOTE: for the appender to receive any value the RootLogger will need to + * have the level correctly configured.ng + * + * @param file the file to monitor + * + * @throws IOException if there is a problem creating a temporary file + */ + public LogMonitor(File file) throws IOException + { + if (file != null && file.exists()) + { + _logfile = file; + _appender = null; + } + else + { + // This is mostly for running the test outside of the ant setup + _logfile = File.createTempFile("LogMonitor", ".log"); + _appender = new FileAppender(new SimpleLayout(), + _logfile.getAbsolutePath()); + _appender.setFile(_logfile.getAbsolutePath()); + _appender.setImmediateFlush(true); + Logger.getRootLogger().addAppender(_appender); + } + + _logger.info("Created LogMonitor. Monitoring file: " + _logfile.getAbsolutePath()); + } + + /** + * Checks the log file for a given message to appear and returns all + * instances of that appearance. + * + * @param message the message to wait for in the log + * @param wait the time in ms to wait for the message to occur + * @return true if the message was found + * + * @throws java.io.FileNotFoundException if the Log file can no longer be found + * @throws IOException thrown when reading the log file + */ + public List waitAndFindMatches(String message, long wait) + throws FileNotFoundException, IOException + { + if (waitForMessage(message, wait)) + { + return findMatches(message); + } + else + { + return new LinkedList(); + } + } + + /** + * Checks the log for instances of the search string. If the caller + * has previously called {@link #markDiscardPoint()}, lines up until the discard + * point are not considered. + * + * The pattern parameter can take any valid argument used in String.contains() + * + * {@see String.contains(CharSequences)} + * + * @param pattern the search string + * + * @return a list of matching lines from the log + * + * @throws IOException if there is a problem with the file + */ + public List findMatches(String pattern) throws IOException + { + + List results = new LinkedList(); + + LineNumberReader reader = new LineNumberReader(new FileReader(_logfile)); + try + { + while (reader.ready()) + { + String line = reader.readLine(); + if (reader.getLineNumber() > _linesToSkip && line.contains(pattern)) + { + results.add(line); + } + } + } + finally + { + reader.close(); + } + + return results; + } + + public Map> findMatches(String... pattern) throws IOException + { + + Map> results= new HashMap>(); + for (String p : pattern) + { + results.put(p, new LinkedList()); + } + LineNumberReader reader = new LineNumberReader(new FileReader(_logfile)); + try + { + while (reader.ready()) + { + String line = reader.readLine(); + if (reader.getLineNumber() > _linesToSkip) + { + for (String p : pattern) + { + if (line.contains(p)) + { + results.get(p).add(line); + } + } + } + } + } + finally + { + reader.close(); + } + + return results; + } + /** + * Checks the log file for a given message to appear. If the caller + * has previously called {@link #markDiscardPoint()}, lines up until the discard + * point are not considered. + * + * @param message the message to wait for in the log + * @param wait the time in ms to wait for the message to occur + * @return true if the message was found + * + * @throws java.io.FileNotFoundException if the Log file can no longer be found + * @throws IOException thrown when reading the log file + */ + public boolean waitForMessage(String message, long wait) + throws FileNotFoundException, IOException + { + // Loop through alerts until we're done or wait ms seconds have passed, + // just in case the logfile takes a while to flush. + LineNumberReader reader = null; + try + { + reader = new LineNumberReader(new FileReader(_logfile)); + + boolean found = false; + long endtime = System.currentTimeMillis() + wait; + while (!found && System.currentTimeMillis() < endtime) + { + boolean ready = true; + while (ready = reader.ready()) + { + String line = reader.readLine(); + + if (reader.getLineNumber() > _linesToSkip) + { + if (line.contains(message)) + { + found = true; + break; + } + } + } + if (!ready) + { + try + { + Thread.sleep(50); + } + catch (InterruptedException ie) + { + Thread.currentThread().interrupt(); + } + } + } + return found; + + } + finally + { + if (reader != null) + { + reader.close(); + } + } + } + + /** + * Read the log file in to memory as a String + * + * @return the current contents of the log file + * + * @throws java.io.FileNotFoundException if the Log file can no longer be found + * @throws IOException thrown when reading the log file + */ + public String readFile() throws FileNotFoundException, IOException + { + return FileUtils.readFileAsString(_logfile); + } + + /** + * Return a File reference to the monitored file + * + * @return the file being monitored + */ + public File getMonitoredFile() + { + return _logfile; + } + + /** + * Marks the discard point in the log file. + * + * @throws java.io.FileNotFoundException if the Log file can no longer be found + * @throws IOException thrown if there is a problem with the log file + */ + public void markDiscardPoint() throws FileNotFoundException, IOException + { + _linesToSkip = countLinesInFile(); + } + + private int countLinesInFile() throws IOException + { + int lineCount = 0; + BufferedReader br = null; + try + { + br = new BufferedReader(new FileReader(_logfile)); + while(br.readLine() != null) + { + lineCount++; + } + + return lineCount; + } + finally + { + if (br != null) + { + br.close(); + } + } + } + + /** + * Stop monitoring this file. + * + * This is required to be called incase we added a new logger. + * + * If we don't call close then the new logger will continue to get log entries + * after our desired test has finished. + */ + public void close() + { + //Remove the custom appender we added for this logger + if (_appender != null) + { + Logger.getRootLogger().removeAppender(_appender); + } + } + +} diff --git a/qpid/java/systests/src/test/java/org/apache/qpid/util/LogMonitorTest.java b/qpid/java/systests/src/test/java/org/apache/qpid/util/LogMonitorTest.java new file mode 100644 index 0000000000..89f707fbef --- /dev/null +++ b/qpid/java/systests/src/test/java/org/apache/qpid/util/LogMonitorTest.java @@ -0,0 +1,274 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.util; + +import junit.framework.TestCase; +import org.apache.log4j.Logger; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +public class LogMonitorTest extends TestCase +{ + + private LogMonitor _monitor; + + @Override + public void setUp() throws Exception + { + _monitor = new LogMonitor(); + _monitor.getMonitoredFile().deleteOnExit(); // Make sure we clean up + } + + /** + * Test that a new file is created when attempting to set up a monitor with + * the default constructor. + */ + public void testMonitor() + { + //Validate that the monitor is now running on a new file + assertTrue("New file does not have correct name:" + _monitor. + getMonitoredFile().getName(), + _monitor.getMonitoredFile().getName().contains("LogMonitor")); + } + + /** + * Test that creation of a monitor on an existing file is possible + * + * This also tests taht getMonitoredFile works + * + * @throws IOException if there is a problem creating the temporary file + */ + public void testMonitorNormalFile() throws IOException + { + File testFile = File.createTempFile("testMonitorFile", ".log"); + testFile.deleteOnExit(); + + //Ensure that we can create a monitor on a file + try + { + _monitor = new LogMonitor(testFile); + assertEquals(testFile, _monitor.getMonitoredFile()); + } + catch (IOException ioe) + { + fail("IOE thrown:" + ioe); + } + + } + + /** + * Test that a new file is created when attempting to set up a monitor on + * a null input value. + */ + public void testMonitorNullFile() + { + // Validate that a NPE is thrown with null input + try + { + LogMonitor montior = new LogMonitor(null); + //Validte that the monitor is now running on a new file + assertTrue("New file does not have correct name:" + montior. + getMonitoredFile().getName(), + montior.getMonitoredFile().getName().contains("LogMonitor")); + } + catch (IOException ioe) + { + fail("IOE thrown:" + ioe); + } + } + + /** + * Test that a new file is created when attempting to set up a monitor on + * a non existing file. + * + * @throws IOException if there is a problem setting up the nonexistent file + */ + public void testMonitorNonExistentFile() throws IOException + { + //Validate that we get a FileNotFound if the file does not exist + + File nonexist = File.createTempFile("nonexist", ".out"); + + assertTrue("Unable to delete file for our test", nonexist.delete()); + + assertFalse("Unable to test as our test file exists.", nonexist.exists()); + + try + { + LogMonitor montior = new LogMonitor(nonexist); + //Validte that the monitor is now running on a new file + assertTrue("New file does not have correct name:" + montior. + getMonitoredFile().getName(), + montior.getMonitoredFile().getName().contains("LogMonitor")); + } + catch (IOException ioe) + { + fail("IOE thrown:" + ioe); + } + } + + /** + * Test that Log file matches logged messages. + * + * @throws java.io.IOException if there is a problem creating LogMontior + */ + public void testFindMatches_Match() throws IOException + { + + String message = getName() + ": Test Message"; + + Logger.getRootLogger().warn(message); + + validateLogContainsMessage(_monitor, message); + } + + /** + * Test that Log file does not match a message not logged. + * + * @throws java.io.IOException if there is a problem creating LogMontior + */ + public void testFindMatches_NoMatch() throws IOException + { + String message = getName() + ": Test Message"; + + Logger.getRootLogger().warn(message); + + String notLogged = "This text was not logged"; + + validateLogDoesNotContainMessage(_monitor, notLogged); + } + + public void testWaitForMessage_Timeout() throws IOException + { + String message = getName() + ": Test Message"; + + long TIME_OUT = 2000; + + logMessageWithDelay(message, TIME_OUT); + + // Verify that we can time out waiting for a message + assertFalse("Message was logged ", + _monitor.waitForMessage(message, TIME_OUT / 2)); + + // Verify that the message did eventually get logged. + assertTrue("Message was never logged.", + _monitor.waitForMessage(message, TIME_OUT)); + } + + public void testDiscardPoint() throws IOException + { + String firstMessage = getName() + ": Test Message1"; + Logger.getRootLogger().warn(firstMessage); + + validateLogContainsMessage(_monitor, firstMessage); + + _monitor.markDiscardPoint(); + + validateLogDoesNotContainMessage(_monitor, firstMessage); + + String secondMessage = getName() + ": Test Message2"; + Logger.getRootLogger().warn(secondMessage); + validateLogContainsMessage(_monitor, secondMessage); + } + + public void testRead() throws IOException + { + String message = getName() + ": Test Message"; + + Logger.getRootLogger().warn(message); + + String fileContents = _monitor.readFile(); + + assertTrue("Logged message not found when reading file.", + fileContents.contains(message)); + } + + /****************** Helpers ******************/ + + /** + * Validate that the LogMonitor does not match the given string in the log + * + * @param log The LogMonitor to check + * @param message The message to check for + * + * @throws IOException if a problems occurs + */ + protected void validateLogDoesNotContainMessage(LogMonitor log, String message) + throws IOException + { + List results = log.findMatches(message); + + assertNotNull("Null results returned.", results); + + assertEquals("Incorrect result set size", 0, results.size()); + } + + /** + * Validate that the LogMonitor can match the given string in the log + * + * @param log The LogMonitor to check + * @param message The message to check for + * + * @throws IOException if a problems occurs + */ + protected void validateLogContainsMessage(LogMonitor log, String message) + throws IOException + { + List results = log.findMatches(message); + + assertNotNull("Null results returned.", results); + + assertEquals("Incorrect result set size", 1, results.size()); + + assertTrue("Logged Message'" + message + "' not present in results:" + + results.get(0), results.get(0).contains(message)); + } + + /** + * Create a new thread to log the given message after the set delay + * + * @param message the messasge to log + * @param delay the delay (ms) to wait before logging + */ + private void logMessageWithDelay(final String message, final long delay) + { + new Thread(new Runnable() + { + + public void run() + { + try + { + Thread.sleep(delay); + } + catch (InterruptedException e) + { + //ignore + } + + Logger.getRootLogger().warn(message); + } + }).start(); + } + +} diff --git a/qpid/java/systests/src/test/resources/org/apache/qpid/test/unit/message/UTF8En b/qpid/java/systests/src/test/resources/org/apache/qpid/test/unit/message/UTF8En new file mode 100644 index 0000000000..c9734b1988 --- /dev/null +++ b/qpid/java/systests/src/test/resources/org/apache/qpid/test/unit/message/UTF8En @@ -0,0 +1,4 @@ +exhangeName +queueName +routingkey +data \ No newline at end of file diff --git a/qpid/java/systests/src/test/resources/org/apache/qpid/test/unit/message/UTF8Jp b/qpid/java/systests/src/test/resources/org/apache/qpid/test/unit/message/UTF8Jp new file mode 100644 index 0000000000..ae10752dab --- /dev/null +++ b/qpid/java/systests/src/test/resources/org/apache/qpid/test/unit/message/UTF8Jp @@ -0,0 +1,4 @@ +設定がそのように構成されていなければな +的某些更新没有出现在这个 README 中。你可以访问下面的 +的发行版本包括多张光盘,其中包括安装光盘和源码光盘 +目のインストール CD は、ほとんどの最近のシス \ No newline at end of file diff --git a/qpid/java/systests/src/test/resources/systests.log4j b/qpid/java/systests/src/test/resources/systests.log4j new file mode 100644 index 0000000000..6d596d1d19 --- /dev/null +++ b/qpid/java/systests/src/test/resources/systests.log4j @@ -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. +# +log4j.rootLogger=${root.logging.level} + + +log4j.logger.org.apache.qpid=${amqj.logging.level}, console +log4j.additivity.org.apache.qpid=false + +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.Threshold=all +log4j.appender.console.layout=org.apache.log4j.PatternLayout +log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n diff --git a/qpid/java/test-profiles/CPPExcludes b/qpid/java/test-profiles/CPPExcludes index 3d87da11c8..44014c9ec0 100755 --- a/qpid/java/test-profiles/CPPExcludes +++ b/qpid/java/test-profiles/CPPExcludes @@ -197,3 +197,5 @@ org.apache.qpid.server.queue.QueueBindTest#testQueueCanBeReboundOnTopicExchange // Tests queue message durability settings which are a Java Broker specific feature org.apache.qpid.server.queue.QueueMessageDurabilityTest#* +// QPID-4429 : C++ Broker does not enforce max frame size negotiation rules as per the spec +org.apache.qpid.transport.MaxFrameSizeTest#* diff --git a/qpid/java/test-profiles/JavaJsonExcludes b/qpid/java/test-profiles/JavaJsonExcludes index 1c4524987b..77b4e3d704 100644 --- a/qpid/java/test-profiles/JavaJsonExcludes +++ b/qpid/java/test-profiles/JavaJsonExcludes @@ -22,5 +22,5 @@ org.apache.qpid.server.store.berkeleydb.replication.* org.apache.qpid.server.store.SplitStoreTest#* org.apache.qpid.systest.rest.acl.VirtualHostACLTest#* org.apache.qpid.systest.rest.VirtualHostNodeRestTest#testCreateAndDeleteVirtualHostNode -org.apache.qpid.systest.rest.VirtualHostRestTest#testPutCreateVirtualHostUsingProfileNodeType +org.apache.qpid.systest.rest.VirtualHostRestTest#testPutCreateProvidedVirtualHost org.apache.qpid.server.BrokerStartupTest#testStartupWithNoConfig diff --git a/qpid/java/test-profiles/JavaTransientExcludes b/qpid/java/test-profiles/JavaTransientExcludes index 3bfeba92b3..70056d6968 100644 --- a/qpid/java/test-profiles/JavaTransientExcludes +++ b/qpid/java/test-profiles/JavaTransientExcludes @@ -55,7 +55,6 @@ org.apache.qpid.systest.management.jmx.QueueManagementTest#testCopyMessageBetwee org.apache.qpid.test.unit.client.MaxDeliveryCountTest#testWhenBrokerIsRestartedAfterEnqeuingMessages -org.apache.qpid.systest.rest.VirtualHostRestTest#testPutCreateVirtualHostUsingProfileNodeType org.apache.qpid.systest.rest.VirtualHostRestTest#testRecoverVirtualHostInDesiredStateStoppedWithDescription org.apache.qpid.systest.rest.VirtualHostRestTest#testMutateStateOfVirtualHostWithQueuesAndMessages diff --git a/qpid/java/tools/src/main/java/org/apache/qpid/tools/JNDICheck.java b/qpid/java/tools/src/main/java/org/apache/qpid/tools/JNDICheck.java index c604b24408..bd6cfd4363 100644 --- a/qpid/java/tools/src/main/java/org/apache/qpid/tools/JNDICheck.java +++ b/qpid/java/tools/src/main/java/org/apache/qpid/tools/JNDICheck.java @@ -21,21 +21,22 @@ package org.apache.qpid.tools; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQConnectionFactory; -import org.apache.qpid.jms.FailoverPolicy; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; -import java.util.Properties; -import java.util.Hashtable; -import java.util.Enumeration; -import java.util.List; -import java.util.LinkedList; -import java.io.IOException; -import java.io.File; -import java.io.FileInputStream; + +import org.apache.qpid.client.AMQConnectionFactory; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.jms.FailoverPolicy; public class JNDICheck { @@ -79,9 +80,9 @@ public class JNDICheck // Load JNDI properties Properties properties = new Properties(); - try + try(FileInputStream propertiesStream = new FileInputStream(new File(propertyFile))) { - properties.load(new FileInputStream(new File(propertyFile))); + properties.load(propertiesStream); } catch (IOException e) { -- cgit v1.2.1