diff options
| author | Martin Ritchie <ritchiem@apache.org> | 2008-07-15 16:58:26 +0000 |
|---|---|---|
| committer | Martin Ritchie <ritchiem@apache.org> | 2008-07-15 16:58:26 +0000 |
| commit | a2c070796499496abf08d61539de1d567963a156 (patch) | |
| tree | c728baf14d99a02dd025cf2f31dbad9a407c4035 /java | |
| parent | 8d5835a2e574d884d78e8fcb5ec4003c75185ee6 (diff) | |
| download | qpid-python-a2c070796499496abf08d61539de1d567963a156.tar.gz | |
QPID-1079 : Based on Code Review : Remvoed AutoCreateVMBroker code from QpidTestCase. Removed VMTestCase and all references to it, it was only used in JUnit4 testSuite wrappers. Rather than move QpidTestCase to a new module all client tests have that require this class have been moved to systests.
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@676969 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java')
115 files changed, 15287 insertions, 429 deletions
diff --git a/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java b/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java index 85ee78bd17..b438304892 100644 --- a/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java +++ b/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java @@ -20,17 +20,12 @@ */ package org.apache.qpid.client; -import junit.framework.TestCase; - -import org.apache.qpid.client.transport.TransportConnection; -import org.apache.qpid.jndi.PropertiesFileInitialContextFactory; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.jms.Connection; -import javax.jms.ConnectionFactory; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageListener; @@ -38,9 +33,7 @@ import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.Session; import javax.naming.Context; -import javax.naming.spi.InitialContextFactory; -import java.util.Hashtable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; diff --git a/java/client/src/test/java/org/apache/qpid/client/MessageListenerTest.java b/java/client/src/test/java/org/apache/qpid/client/MessageListenerTest.java index 3b7302df62..e1c0f0ccef 100644 --- a/java/client/src/test/java/org/apache/qpid/client/MessageListenerTest.java +++ b/java/client/src/test/java/org/apache/qpid/client/MessageListenerTest.java @@ -20,17 +20,12 @@ */ package org.apache.qpid.client; -import junit.framework.TestCase; - -import org.apache.qpid.client.transport.TransportConnection; -import org.apache.qpid.jndi.PropertiesFileInitialContextFactory; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.jms.Connection; -import javax.jms.ConnectionFactory; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageListener; @@ -38,9 +33,7 @@ import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.Session; import javax.naming.Context; -import javax.naming.spi.InitialContextFactory; -import java.util.Hashtable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; diff --git a/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java b/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java index c920499a07..a0bb31192f 100644 --- a/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java +++ b/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java @@ -20,17 +20,12 @@ */ package org.apache.qpid.client; -import junit.framework.TestCase; - -import org.apache.qpid.client.transport.TransportConnection; -import org.apache.qpid.jndi.PropertiesFileInitialContextFactory; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.jms.Connection; -import javax.jms.ConnectionFactory; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; @@ -40,9 +35,7 @@ import javax.jms.Queue; import javax.jms.Session; import javax.jms.TextMessage; import javax.naming.Context; -import javax.naming.spi.InitialContextFactory; -import java.util.Hashtable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/ack/RecoverTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/ack/RecoverTest.java index 216bbedef3..7434fcbb30 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/ack/RecoverTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/ack/RecoverTest.java @@ -23,7 +23,7 @@ import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.jms.Session; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java index cf09566f30..747b081f8c 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java @@ -29,7 +29,7 @@ import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.message.JMSBytesMessage; import org.apache.qpid.testutil.VMBrokerSetup; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTableMessageTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTableMessageTest.java index e8d3497bdb..1738997f6f 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTableMessageTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/basic/FieldTableMessageTest.java @@ -31,7 +31,7 @@ import org.apache.qpid.framing.AMQFrameDecodingException; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.FieldTableFactory; import org.apache.qpid.testutil.VMBrokerSetup; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java index 1738db7239..06f4a6464f 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java @@ -23,7 +23,7 @@ package org.apache.qpid.test.unit.basic; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import javax.jms.Session; import javax.jms.QueueSession; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java index 81171fa330..24fef48028 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java @@ -24,7 +24,7 @@ package org.apache.qpid.test.unit.basic; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQSession; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/basic/MapMessageTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/basic/MapMessageTest.java index 2c4df682f6..390850185c 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/basic/MapMessageTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/basic/MapMessageTest.java @@ -26,7 +26,7 @@ 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.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java index 4f3fc5501d..658cf26135 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java @@ -25,7 +25,7 @@ import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.AMQTopic; import org.apache.qpid.client.transport.TransportConnection; import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/basic/ObjectMessageTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/basic/ObjectMessageTest.java index a385c196b2..10705119e7 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/basic/ObjectMessageTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/basic/ObjectMessageTest.java @@ -20,15 +20,13 @@ package org.apache.qpid.test.unit.basic; import junit.framework.Assert; -import junit.framework.TestCase; 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.client.transport.TransportConnection; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/basic/PropertyValueTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/basic/PropertyValueTest.java index 0e7bb2208b..ca896b08bb 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/basic/PropertyValueTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/basic/PropertyValueTest.java @@ -21,16 +21,14 @@ package org.apache.qpid.test.unit.basic; import junit.framework.Assert; -import junit.framework.TestCase; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.message.AMQMessage; import org.apache.qpid.client.message.JMSTextMessage; -import org.apache.qpid.client.transport.TransportConnection; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/basic/PubSubTwoConnectionTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/basic/PubSubTwoConnectionTest.java index 60c84f451d..66c5a5b07e 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/basic/PubSubTwoConnectionTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/basic/PubSubTwoConnectionTest.java @@ -27,13 +27,10 @@ import javax.jms.Session; import javax.jms.TextMessage; import javax.jms.Topic; -import junit.framework.TestCase; - import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.client.transport.TransportConnection; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; /** * @author Apache Software Foundation diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/basic/ReceiveTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/basic/ReceiveTest.java index 5711d12b9e..eec3db8c5f 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/basic/ReceiveTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/basic/ReceiveTest.java @@ -23,15 +23,11 @@ package org.apache.qpid.test.unit.basic; import javax.jms.MessageConsumer; import javax.jms.Message; -import junit.framework.TestCase; - 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.transport.TransportConnection; -import org.apache.qpid.client.vmbroker.AMQVMBrokerCreationException; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; public class ReceiveTest extends QpidTestCase { diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/basic/SelectorTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/basic/SelectorTest.java index 987b30ce28..cc9afeffa2 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/basic/SelectorTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/basic/SelectorTest.java @@ -20,15 +20,13 @@ */ package org.apache.qpid.test.unit.basic; -import junit.framework.TestCase; import org.apache.qpid.AMQException; +import org.apache.qpid.test.utils.QpidTestCase; 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.client.transport.TransportConnection; -import org.apache.qpid.testutil.QpidTestCase; import org.apache.qpid.url.URLSyntaxException; import org.slf4j.Logger; @@ -41,7 +39,7 @@ import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageListener; -public class SelectorTest extends QpidTestCase implements MessageListener +public class SelectorTest extends QpidTestCase implements MessageListener { private static final Logger _logger = LoggerFactory.getLogger(SelectorTest.class); diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/basic/SessionStartTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/basic/SessionStartTest.java index 7864feb069..1dd6916d04 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/basic/SessionStartTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/basic/SessionStartTest.java @@ -20,15 +20,13 @@ */ package org.apache.qpid.test.unit.basic; -import junit.framework.TestCase; - 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.testutil.VMBrokerSetup; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/basic/TextMessageTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/basic/TextMessageTest.java index 1453e1b014..29943161d4 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/basic/TextMessageTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/basic/TextMessageTest.java @@ -27,7 +27,7 @@ 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.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/basic/close/CloseTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/basic/close/CloseTest.java index 6f1ddebb0c..21eaad6d5b 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/basic/close/CloseTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/basic/close/CloseTest.java @@ -19,18 +19,14 @@ * */ package org.apache.qpid.test.unit.basic.close; -import org.apache.qpid.AMQException; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.transport.TransportConnection; import org.apache.qpid.url.AMQBindingURL; -import org.apache.qpid.url.URLSyntaxException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.jms.JMSException; import javax.jms.MessageConsumer; import javax.jms.MessageProducer; import javax.jms.Session; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java index 28782229a1..c91c27e894 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java @@ -29,7 +29,7 @@ import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.AMQTopic; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; public class AMQConnectionTest extends QpidTestCase { diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/AMQSessionTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/AMQSessionTest.java index 965c22af4a..19d56dc4f7 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/client/AMQSessionTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/AMQSessionTest.java @@ -29,7 +29,7 @@ import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.AMQTopic; import org.apache.qpid.testutil.VMBrokerSetup; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; /** * Tests for QueueReceiver and TopicSubscriber creation methods on AMQSession diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseOkTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseOkTest.java index 74c0098d72..b843f7c9c0 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseOkTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseOkTest.java @@ -25,7 +25,7 @@ import junit.textui.TestRunner; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.transport.TransportConnection; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java index 45a9ca1dd6..d210f5e1a1 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java @@ -20,17 +20,11 @@ */ package org.apache.qpid.test.unit.client.channelclose; -import junit.framework.TestCase; - import org.apache.qpid.AMQException; -import org.apache.qpid.AMQTimeoutException; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.handler.ClientMethodDispatcherImpl; import org.apache.qpid.client.failover.FailoverException; import org.apache.qpid.client.protocol.AMQProtocolHandler; -import org.apache.qpid.client.protocol.AMQProtocolSession; -import org.apache.qpid.client.state.AMQStateManager; import org.apache.qpid.client.transport.TransportConnection; import org.apache.qpid.framing.*; import org.apache.qpid.jms.ConnectionListener; @@ -49,9 +43,6 @@ import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.Session; import javax.jms.TextMessage; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; public class ChannelCloseTest extends QpidTestCase implements ExceptionListener, ConnectionListener { @@ -424,27 +415,4 @@ public class ChannelCloseTest extends QpidTestCase implements ExceptionListener, public void failoverComplete() { } - private static final class MethodDispatcherProxyHandler implements InvocationHandler - { - private final ClientMethodDispatcherImpl _underlyingDispatcher; - private final ChannelCloseMethodHandlerNoCloseOk _handler = ChannelCloseMethodHandlerNoCloseOk.getInstance(); - - - public MethodDispatcherProxyHandler(ClientMethodDispatcherImpl dispatcher) - { - _underlyingDispatcher = dispatcher; - } - - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable - { - if(method.getName().equals("dispatchChannelClose")) - { - _handler.methodReceived(_underlyingDispatcher.getStateManager(), - (ChannelCloseBody) args[0], (Integer)args[1]); - } - Method dispatcherMethod = _underlyingDispatcher.getClass().getMethod(method.getName(), method.getParameterTypes()); - return dispatcherMethod.invoke(_underlyingDispatcher, args); - - } - } } diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/CloseWithBlockingReceiveTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/CloseWithBlockingReceiveTest.java index c3be691f2d..d4d19a34ea 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/CloseWithBlockingReceiveTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/channelclose/CloseWithBlockingReceiveTest.java @@ -20,16 +20,12 @@ */ package org.apache.qpid.test.unit.client.channelclose; -import javax.jms.Connection; import javax.jms.MessageConsumer; import javax.jms.Session; -import junit.framework.TestCase; - import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.client.transport.TransportConnection; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; /** * @author Apache Software Foundation diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java index 3ab3b0410e..410939f583 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java @@ -20,7 +20,7 @@ */ package org.apache.qpid.test.unit.client.connection; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.apache.qpidity.transport.util.Logger; import java.util.HashMap; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.java index 3cef57f90d..72691f3543 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.java @@ -34,7 +34,7 @@ import javax.jms.TextMessage; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQSession; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; public class ConnectionStartTest extends QpidTestCase { diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java index 30b7ccc550..ed7a0f18b6 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java @@ -23,18 +23,14 @@ package org.apache.qpid.test.unit.client.connection; import org.apache.qpid.AMQConnectionFailureException; import org.apache.qpid.AMQException; import org.apache.qpid.AMQUnresolvedAddressException; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.apache.qpid.client.AMQAuthenticationException; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.client.transport.TransportConnection; import org.apache.qpid.jms.Session; -import junit.framework.TestCase; - import javax.jms.Connection; -import javax.jms.JMSException; import javax.jms.QueueSession; import javax.jms.TopicSession; import javax.naming.NamingException; @@ -131,7 +127,6 @@ public class ConnectionTest extends QpidTestCase } } - //See QPID-771 public void testPasswordFailureConnection() throws Exception { AMQConnection conn = null; @@ -140,18 +135,10 @@ public class ConnectionTest extends QpidTestCase conn = new AMQConnection("amqp://guest:rubbishpassword@clientid/test?brokerlist='" + getBroker() + "?retries='1''"); fail("Connection should not be established password is wrong."); } - catch (AMQException amqe) + catch (AMQConnectionFailureException amqe) { assertNotNull("No cause set", amqe.getCause()); - if (amqe.getCause().getClass() == Exception.class) - { - System.err.println("QPID-594 : WARNING RACE CONDITION. Unable to determine cause of Connection Failure."); - return; - } - - assertEquals("Exception was wrong type", JMSException.class, amqe.getCause().getClass()); - Exception linked = ((JMSException) amqe.getCause()).getLinkedException(); - assertEquals("Exception was wrong type", AMQAuthenticationException.class, linked.getClass()); + assertEquals("Exception was wrong type", AMQAuthenticationException.class, amqe.getCause().getClass()); } finally { diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ExceptionListenerTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ExceptionListenerTest.java index ccf16a0b6e..6f31f7bc65 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ExceptionListenerTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/connection/ExceptionListenerTest.java @@ -20,7 +20,7 @@ */ package org.apache.qpid.test.unit.client.connection; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.apache.qpid.util.concurrent.Condition; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/Client.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/Client.java index f43ccaf0ff..0be11011b4 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/Client.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/Client.java @@ -24,7 +24,7 @@ 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.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/CombinedTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/CombinedTest.java index 29d9e5de2c..a1001a6f5d 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/CombinedTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/CombinedTest.java @@ -20,8 +20,7 @@ */ package org.apache.qpid.test.unit.client.forwardall; -import org.apache.qpid.testutil.VMBrokerSetup; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/Service.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/Service.java index 3dc9a3ccfb..9cd8b183af 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/Service.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/forwardall/Service.java @@ -28,7 +28,7 @@ import javax.jms.MessageListener; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQSession; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; /** * Declare a queue and bind it to amq.direct with a 'well known' routing key, diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/message/ObjectMessageTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/message/ObjectMessageTest.java index 7b3077a1c1..2c1a7facec 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/client/message/ObjectMessageTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/message/ObjectMessageTest.java @@ -25,7 +25,7 @@ import org.apache.qpid.client.AMQDestination; import org.apache.qpid.client.AMQQueue; import org.apache.qpid.client.AMQSession; import org.apache.qpid.testutil.VMBrokerSetup; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.java index 4cdd7dd7e8..cf6b968aed 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.java @@ -20,14 +20,13 @@ */ package org.apache.qpid.test.unit.client.protocol; -import junit.framework.TestCase; - import org.apache.mina.common.IoSession; import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.state.AMQStateManager; import org.apache.qpid.client.protocol.AMQProtocolHandler; import org.apache.qpid.client.protocol.AMQProtocolSession; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; public class AMQProtocolSessionTest extends QpidTestCase { diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java index 46b99fac8d..7a65b06dd4 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java @@ -30,9 +30,8 @@ import javax.jms.TemporaryQueue; import javax.jms.TextMessage; import junit.framework.Assert; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.transport.TransportConnection; import java.util.List; import java.util.LinkedList; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/close/CloseBeforeAckTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/close/CloseBeforeAckTest.java index 54b2ee95f4..a61bcca049 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/close/CloseBeforeAckTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/close/CloseBeforeAckTest.java @@ -22,9 +22,7 @@ package org.apache.qpid.test.unit.close; import junit.framework.Assert; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.transport.TransportConnection; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java index 5ebde71d6c..579e3350ff 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java @@ -21,11 +21,9 @@ package org.apache.qpid.test.unit.close; import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.test.utils.QpidTestCase; import org.apache.qpid.client.message.AbstractJMSMessage; -import org.apache.qpid.client.transport.TransportConnection; import org.apache.qpid.testutil.QpidClientConnection; -import org.apache.qpid.testutil.QpidTestCase; import org.apache.qpid.url.URLSyntaxException; import org.slf4j.Logger; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/close/TopicPublisherCloseTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/close/TopicPublisherCloseTest.java index 4957d700e6..da7642fb3c 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/close/TopicPublisherCloseTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/close/TopicPublisherCloseTest.java @@ -24,12 +24,9 @@ import javax.jms.Topic; import javax.jms.TopicPublisher; import javax.jms.TopicSession; -import junit.framework.TestCase; - import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.client.transport.TransportConnection; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; /** * @author Apache Software Foundation diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/ct/DurableSubscriberTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/ct/DurableSubscriberTest.java index 9caba63fe4..34fbd9532f 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/ct/DurableSubscriberTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/ct/DurableSubscriberTest.java @@ -19,7 +19,7 @@ package org.apache.qpid.test.unit.ct; import javax.jms.*; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; /** * Crash Recovery tests for durable subscription diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSDestinationTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSDestinationTest.java index 131cbd5f68..b30e3c1c1c 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSDestinationTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSDestinationTest.java @@ -25,7 +25,7 @@ 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.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java index 6883a09f1b..5bf99e719e 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java @@ -20,15 +20,12 @@ */ package org.apache.qpid.test.unit.message; -import junit.framework.TestCase; - 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.transport.TransportConnection; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/message/StreamMessageTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/message/StreamMessageTest.java index d9d078a01d..3027da00c7 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/message/StreamMessageTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/message/StreamMessageTest.java @@ -29,7 +29,7 @@ import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.url.AMQBindingURL; import org.apache.qpid.url.BindingURL; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java index 6856ad34fb..4897f5fa15 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java @@ -20,15 +20,10 @@ */ package org.apache.qpid.test.unit.topic; -import junit.framework.TestCase; - -import org.apache.qpid.AMQException; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.client.transport.TransportConnection; -import org.apache.qpid.url.URLSyntaxException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,7 +31,6 @@ import org.slf4j.LoggerFactory; import javax.jms.Connection; import javax.jms.InvalidDestinationException; import javax.jms.InvalidSelectorException; -import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageProducer; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/topic/TopicPublisherTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/topic/TopicPublisherTest.java index 4f0f0dbaa9..6d115d1a2b 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/topic/TopicPublisherTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/topic/TopicPublisherTest.java @@ -28,7 +28,7 @@ import javax.jms.TopicSession; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; /** * @author Apache Software Foundation diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java index 0ff3455624..ee970759ad 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java @@ -30,13 +30,10 @@ import javax.jms.TopicPublisher; import javax.jms.TopicSession; import javax.jms.TopicSubscriber; -import junit.framework.TestCase; - import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.client.transport.TransportConnection; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; /** @author Apache Software Foundation */ diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java index f2f35644c6..b2797e2535 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java @@ -20,7 +20,7 @@ */ package org.apache.qpid.test.unit.transacted; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.apache.qpid.client.AMQConnection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/transacted/TransactedTest.java b/java/client/src/test/java/org/apache/qpid/test/unit/transacted/TransactedTest.java index d96e8546e2..1eec6dd17c 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/transacted/TransactedTest.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/transacted/TransactedTest.java @@ -26,7 +26,7 @@ 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.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/client/src/test/java/org/apache/qpid/test/unit/xa/AbstractXATestCase.java b/java/client/src/test/java/org/apache/qpid/test/unit/xa/AbstractXATestCase.java index 18cdb645c6..42811ed390 100644 --- a/java/client/src/test/java/org/apache/qpid/test/unit/xa/AbstractXATestCase.java +++ b/java/client/src/test/java/org/apache/qpid/test/unit/xa/AbstractXATestCase.java @@ -18,7 +18,7 @@ package org.apache.qpid.test.unit.xa; import org.apache.qpidity.dtx.XidImpl; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import javax.transaction.xa.Xid; import javax.transaction.xa.XAResource; diff --git a/java/client/src/test/java/org/apache/qpid/testutil/Config.java b/java/client/src/test/java/org/apache/qpid/testutil/Config.java deleted file mode 100644 index b777cf93b6..0000000000 --- a/java/client/src/test/java/org/apache/qpid/testutil/Config.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.testutil; - -import javax.jms.Connection; -import javax.jms.Destination; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQHeadersExchange; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.exchange.ExchangeDefaults; - -public class Config -{ - public static final String QUEUE = "queue"; - public static final String TOPIC = "topic"; - public static final String HEADERS = "headers"; - - private String host = "localhost"; - private int port = 5672; - private String type; - private String name = "simple_test_queue"; - - public Config() - { - this("localhost", 5672, QUEUE, "simple_test_queue"); - } - - public Config(String host, int port, String type, String name) - { - setHost(host); - setPort(port); - setType(type); - setName(name); - } - - public String getHost() - { - return host; - } - - public void setHost(String host) - { - this.host = host; - } - - public int getPort() - { - return port; - } - - public void setPort(int port) - { - this.port = port; - } - - public String getType() - { - return type; - } - - public void setType(String type) - { - this.type = type; - } - - public boolean isQueue() - { - return QUEUE.equalsIgnoreCase(type); - } - - public boolean isTopic() - { - return TOPIC.equalsIgnoreCase(type); - } - - private boolean isHeaders() - { - return HEADERS.equalsIgnoreCase(type); - } - - public void setQueue(boolean queue) - { - type = queue ? QUEUE : TOPIC; - } - - public String getName() - { - return name; - } - - public void setName(String name) - { - this.name = name; - } - - public Destination getDestination() - { - if(isQueue()) - { - System.out.println("Using queue named " + name); - return new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME,name); - } - else if(isTopic()) - { - System.out.println("Using topic named " + name); - return new AMQTopic(ExchangeDefaults.TOPIC_EXCHANGE_NAME,name); - } - else if(isHeaders()) - { - System.out.println("Using headers exhange named " + name); - return new AMQHeadersExchange(name); - } - return null; - } - - public Connection getConnection() throws Exception - { - System.out.println("Connecting to " + host + " on " + port + "..."); - return new AMQConnection(host, port, "guest", "guest", "Client" + System.currentTimeMillis(), "/test"); - } - - public boolean setOptions(String[] argv) - { - try - { - for(int i = 0; i < argv.length - 1; i += 2) - { - String key = argv[i]; - String value = argv[i+1]; - setOption(key, value); - } - return true; - } - catch(Exception e) - { - System.out.println(e.getMessage()); - } - return false; - } - - private void setOption(String key, String value) - { - if("-host".equalsIgnoreCase(key)) - { - setHost(value); - } - else if("-port".equalsIgnoreCase(key)) - { - try - { - setPort(Integer.parseInt(value)); - } - catch(NumberFormatException e) - { - throw new RuntimeException("Bad port number: " + value, e); - } - } - else if("-name".equalsIgnoreCase(key)) - { - setName(value); - } - else if("-type".equalsIgnoreCase(key)) - { - if(QUEUE.equalsIgnoreCase(value) - || TOPIC.equalsIgnoreCase(value) - || HEADERS.equalsIgnoreCase(value)) - { - type = value; - } - else{ - throw new RuntimeException("Bad destination type: " + value); - } - } - else - { - System.out.println("Ignoring unrecognised option: " + key); - } - } -} diff --git a/java/client/src/test/java/org/apache/qpid/testutil/QpidClientConnection.java b/java/client/src/test/java/org/apache/qpid/testutil/QpidClientConnection.java index e99a51e1c7..ad2d34d41b 100644 --- a/java/client/src/test/java/org/apache/qpid/testutil/QpidClientConnection.java +++ b/java/client/src/test/java/org/apache/qpid/testutil/QpidClientConnection.java @@ -22,10 +22,8 @@ package org.apache.qpid.testutil; import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQConnectionFactory; -import org.apache.qpid.client.AMQConnectionURL; import org.apache.qpid.client.JMSAMQException; -import org.apache.qpid.url.URLSyntaxException; +import org.apache.qpid.test.utils.QpidTestCase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/java/systests/src/main/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.java b/java/systests/src/main/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.java new file mode 100644 index 0000000000..fe418535d6 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/client/AMQQueueDeferredOrderingTest.java @@ -0,0 +1,152 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.client; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.TextMessage; + +import junit.framework.TestCase; + +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.jms.Session; +import org.apache.qpid.client.transport.TransportConnection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class tests all the alerts an AMQQueue can throw based on threshold + * values of different parameters + */ +public class AMQQueueDeferredOrderingTest extends TestCase +{ + + private static final int NUM_MESSAGES = 1000; + + private AMQConnection con; + private Session session; + private AMQQueue queue; + private MessageConsumer consumer; + + private static final Logger _logger = LoggerFactory.getLogger(AMQQueueDeferredOrderingTest.class); + + private ASyncProducer producerThread; + private static final String BROKER = "vm://:1"; + + 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))); + } + this._logger.info("Sent " + (end - start) + " messages"); + } + catch (JMSException e) + { + throw new RuntimeException(e); + } + } + } + + protected void setUp() throws Exception + { + super.setUp(); + TransportConnection.createVMBroker(1); + + _logger.info("Create Connection"); + con = new AMQConnection(BROKER, "guest", "guest", "OrderingTest", "test"); + _logger.info("Create Session"); + session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + _logger.info("Create Q"); + queue = new AMQQueue(session.getDefaultQueueExchangeName(), 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 testPausedOrder() throws Exception + { + + // Setup initial messages + _logger.info("Creating first producer thread"); + producerThread = new ASyncProducer(queue, 0, NUM_MESSAGES / 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, NUM_MESSAGES / 2, NUM_MESSAGES); + producerThread.start(); + + // Start consuming and checking they're in order + _logger.info("Consuming messages"); + for (int i = 0; i < NUM_MESSAGES; i++) + { + Message msg = consumer.receive(3000); + assertNotNull("Message should not be null", msg); + assertTrue("Message should be a text message", msg instanceof TextMessage); + assertEquals("Message content 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(); + + TransportConnection.killAllVMBrokers(); + super.tearDown(); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(AMQQueueDeferredOrderingTest.class); + } + +} diff --git a/java/systests/src/main/java/org/apache/qpid/client/DispatcherTest.java b/java/systests/src/main/java/org/apache/qpid/client/DispatcherTest.java new file mode 100644 index 0000000000..7cca22de6c --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/client/DispatcherTest.java @@ -0,0 +1,252 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.client; + +import junit.framework.TestCase; + +import org.apache.qpid.client.transport.TransportConnection; +import org.apache.qpid.jndi.PropertiesFileInitialContextFactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +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.Context; +import javax.naming.spi.InitialContextFactory; + +import java.util.Hashtable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * QPID-293 Setting MessageListener after connection has started can cause messages to be "lost" on a internal delivery queue + * <p/> + * The message delivery process: + * Mina puts a message on _queue in AMQSession and the dispatcher thread take()s + * from here and dispatches to the _consumers. If the _consumer doesn't have a message listener set at connection start + * then messages are stored on _synchronousQueue (which needs to be > 1 to pass JMS TCK as multiple consumers on a + * session can run in any order and a synchronous put/poll will block the dispatcher). + * <p/> + * When setting the message listener later the _synchronousQueue is just poll()'ed and the first message delivered + * the remaining messages will be left on the queue and lost, subsequent messages on the session will arrive first. + */ +public class DispatcherTest extends TestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(DispatcherTest.class); + + Context _context; + + private static final int MSG_COUNT = 6; + private int _receivedCount = 0; + private int _receivedCountWhileStopped = 0; + private Connection _clientConnection, _producerConnection; + private MessageConsumer _consumer; + MessageProducer _producer; + Session _clientSession, _producerSession; + + private final CountDownLatch _allFirstMessagesSent = new CountDownLatch(1); // all messages Sent Lock + private final CountDownLatch _allSecondMessagesSent = new CountDownLatch(1); // all messages Sent Lock + + private volatile boolean _connectionStopped = false; + + protected void setUp() throws Exception + { + super.setUp(); + TransportConnection.createVMBroker(1); + + InitialContextFactory factory = new PropertiesFileInitialContextFactory(); + + Hashtable<String, String> env = new Hashtable<String, String>(); + + env.put("connectionfactory.connection", "amqp://guest:guest@MLT_ID/test?brokerlist='vm://:1'"); + env.put("queue.queue", "MessageListenerTest"); + + _context = factory.getInitialContext(env); + + Queue queue = (Queue) _context.lookup("queue"); + + // Create Client 1 + _clientConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection(); + + _clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + _consumer = _clientSession.createConsumer(queue); + + // Create Producer + _producerConnection = ((ConnectionFactory) _context.lookup("connection")).createConnection(); + + _producerConnection.start(); + + _producerSession = _producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + _producer = _producerSession.createProducer(queue); + + for (int msg = 0; msg < MSG_COUNT; msg++) + { + _producer.send(_producerSession.createTextMessage("Message " + msg)); + } + } + + protected void tearDown() throws Exception + { + + _clientConnection.close(); + + _producerConnection.close(); + super.tearDown(); + TransportConnection.killAllVMBrokers(); + } + + public void testAsynchronousRecieve() + { + _logger.info("Test Start"); + + assertTrue(!((AMQConnection) _clientConnection).started()); + + // Set default Message Listener + try + { + _consumer.setMessageListener(new MessageListener() + { + public void onMessage(Message message) + { + _logger.info("Client 1 ML 1 Received Message(" + _receivedCount + "):" + message); + + _receivedCount++; + + if (_receivedCount == MSG_COUNT) + { + _allFirstMessagesSent.countDown(); + } + + if (_connectionStopped) + { + _logger.info("Running with Message:" + _receivedCount); + } + + if (_connectionStopped && (_allFirstMessagesSent.getCount() == 0)) + { + _receivedCountWhileStopped++; + } + + if (_allFirstMessagesSent.getCount() == 0) + { + if (_receivedCount == (MSG_COUNT * 2)) + { + _allSecondMessagesSent.countDown(); + } + } + } + }); + + assertTrue("Connecion should not be started", !((AMQConnection) _clientConnection).started()); + _clientConnection.start(); + } + catch (JMSException e) + { + _logger.error("Error Setting Default ML on consumer1"); + } + + try + { + _allFirstMessagesSent.await(1000, TimeUnit.MILLISECONDS); + } + catch (InterruptedException e) + { + // do nothing + } + + try + { + assertTrue("Connecion should be started", ((AMQConnection) _clientConnection).started()); + _clientConnection.stop(); + _connectionStopped = true; + } + catch (JMSException e) + { + _logger.error("Error stopping connection"); + } + + try + { + _logger.error("Send additional messages"); + + for (int msg = 0; msg < MSG_COUNT; msg++) + { + _producer.send(_producerSession.createTextMessage("Message " + msg)); + } + } + catch (JMSException e) + { + _logger.error("Unable to send additional messages", e); + } + + try + { + Thread.sleep(1000); + } + catch (InterruptedException e) + { + // ignore + } + + try + { + _logger.info("Restarting connection"); + + _connectionStopped = false; + _clientConnection.start(); + } + catch (JMSException e) + { + _logger.error("Error Setting Better ML on consumer1", e); + } + + _logger.info("Waiting upto 2 seconds for messages"); + + try + { + _allSecondMessagesSent.await(1000, TimeUnit.MILLISECONDS); + } + catch (InterruptedException e) + { + // do nothing + } + + assertEquals("Messages not received correctly", 0, _allFirstMessagesSent.getCount()); + assertEquals("Messages not received correctly", 0, _allSecondMessagesSent.getCount()); + assertEquals("Client didn't get all messages", MSG_COUNT * 2, _receivedCount); + assertEquals("Messages received while stopped is not 0", 0, _receivedCountWhileStopped); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(DispatcherTest.class); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/client/MessageListenerMultiConsumerImmediatePrefetch.java b/java/systests/src/main/java/org/apache/qpid/client/MessageListenerMultiConsumerImmediatePrefetch.java new file mode 100644 index 0000000000..7461f6c200 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/client/MessageListenerMultiConsumerImmediatePrefetch.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.client; + +/** + * QPID-293 Setting MessageListener after connection has started can cause messages to be "lost" on a internal delivery + * queue <p/> The message delivery process: Mina puts a message on _queue in AMQSession and the dispatcher thread + * take()s from here and dispatches to the _consumers. If the _consumer1 doesn't have a message listener set at + * connection start then messages are stored on _synchronousQueue (which needs to be > 1 to pass JMS TCK as multiple + * consumers on a session can run in any order and a synchronous put/poll will block the dispatcher). <p/> When setting + * the message listener later the _synchronousQueue is just poll()'ed and the first message delivered the remaining + * messages will be left on the queue and lost, subsequent messages on the session will arrive first. + */ +public class MessageListenerMultiConsumerImmediatePrefetch extends MessageListenerMultiConsumerTest +{ + protected void setUp() throws Exception + { + System.setProperty(AMQSession.IMMEDIATE_PREFETCH, "true"); + super.setUp(); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(MessageListenerMultiConsumerImmediatePrefetch.class); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java b/java/systests/src/main/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java new file mode 100644 index 0000000000..b438304892 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java @@ -0,0 +1,245 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.test.utils.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +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.Context; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * QPID-293 Setting MessageListener after connection has started can cause messages to be "lost" on a internal delivery + * queue <p/> The message delivery process: Mina puts a message on _queue in AMQSession and the dispatcher thread + * take()s from here and dispatches to the _consumers. If the _consumer1 doesn't have a message listener set at + * connection start then messages are stored on _synchronousQueue (which needs to be > 1 to pass JMS TCK as multiple + * consumers on a session can run in any order and a synchronous put/poll will block the dispatcher). <p/> When setting + * the message listener later the _synchronousQueue is just poll()'ed and the first message delivered the remaining + * messages will be left on the queue and lost, subsequent messages on the session will arrive first. + */ +public class MessageListenerMultiConsumerTest extends QpidTestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(MessageListenerMultiConsumerTest.class); + + Context _context; + + private static final int MSG_COUNT = 6; + private int receivedCount1 = 0; + private int receivedCount2 = 0; + private Connection _clientConnection; + private MessageConsumer _consumer1; + private MessageConsumer _consumer2; + private Session _clientSession1; + private Queue _queue; + private final CountDownLatch _allMessagesSent = new CountDownLatch(2); // all messages Sent Lock + + protected void setUp() throws Exception + { + super.setUp(); + + // Create Client 1 + _clientConnection = getConnection("guest", "guest"); + + _clientConnection.start(); + + _clientSession1 = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + _queue =_clientSession1.createQueue("queue"); + + _consumer1 = _clientSession1.createConsumer(_queue); + + // Create Client 2 + Session clientSession2 = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + _consumer2 = clientSession2.createConsumer(_queue); + + // Create Producer + Connection producerConnection = getConnection("guest", "guest"); + + producerConnection.start(); + + Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer producer = producerSession.createProducer(_queue); + + for (int msg = 0; msg < MSG_COUNT; msg++) + { + producer.send(producerSession.createTextMessage("Message " + msg)); + } + + producerConnection.close(); + + } + + protected void tearDown() throws Exception + { + _clientConnection.close(); + super.tearDown(); + } + + public void testRecieveInterleaved() throws Exception + { + int msg = 0; + int MAX_LOOPS = MSG_COUNT * 2; + for (int loops = 0; (msg < MSG_COUNT) || (loops < MAX_LOOPS); loops++) + { + + if (_consumer1.receive(100) != null) + { + msg++; + } + + if (_consumer2.receive(100) != null) + { + msg++; + } + } + + assertEquals("Not all messages received.", MSG_COUNT, msg); + } + + public void testAsynchronousRecieve() throws Exception + { + _consumer1.setMessageListener(new MessageListener() + { + public void onMessage(Message message) + { + _logger.info("Client 1 Received Message(" + receivedCount1 + "):" + message); + + receivedCount1++; + + if (receivedCount1 == (MSG_COUNT / 2)) + { + _allMessagesSent.countDown(); + } + + } + }); + + _consumer2.setMessageListener(new MessageListener() + { + public void onMessage(Message message) + { + _logger.info("Client 2 Received Message(" + receivedCount2 + "):" + message); + + receivedCount2++; + if (receivedCount2 == (MSG_COUNT / 2)) + { + _allMessagesSent.countDown(); + } + } + }); + + _logger.info("Waiting upto 2 seconds for messages"); + + try + { + _allMessagesSent.await(4000, TimeUnit.MILLISECONDS); + } + catch (InterruptedException e) + { + // do nothing + } + + assertEquals(MSG_COUNT, receivedCount1 + receivedCount2); + } + + public void testRecieveC2Only() throws Exception + { + if ( + !Boolean.parseBoolean( + System.getProperties().getProperty(AMQSession.IMMEDIATE_PREFETCH, + AMQSession.IMMEDIATE_PREFETCH_DEFAULT))) + { + _logger.info("Performing Receive only on C2"); + for (int msg = 0; msg < MSG_COUNT; msg++) + { + assertTrue(MSG_COUNT + " msg should be received. Only received:" + msg, _consumer2.receive(1000) != null); + } + } + } + + public void testRecieveBoth() throws Exception + { + if ( + !Boolean.parseBoolean( + System.getProperties().getProperty(AMQSession.IMMEDIATE_PREFETCH, + AMQSession.IMMEDIATE_PREFETCH_DEFAULT))) + { + _logger.info("Performing Receive only with two consumers on one session "); + + MessageConsumer consumer2 = _clientSession1.createConsumer(_queue); + + int msg; + for (msg = 0; msg < (MSG_COUNT / 2); msg++) + { + + + final Message message = _consumer1.receive(1000); + if(message == null) + { + break; + } + + } + + _consumer1.close(); + _clientSession1.close(); + + for (; msg < MSG_COUNT ; msg++) + { + assertTrue("Failed at msg id" + msg, _consumer2.receive(1000) != null); + } + + } + else + { + _logger.info("Performing Receive only on both C1 and C2"); + + for (int msg = 0; msg < (MSG_COUNT / 2); msg++) + { + + assertTrue(_consumer1.receive(3000) != null); + } + + for (int msg = 0; msg < (MSG_COUNT / 2); msg++) + { + assertTrue(_consumer2.receive(3000) != null); + } + } + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(MessageListenerMultiConsumerTest.class); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/client/MessageListenerTest.java b/java/systests/src/main/java/org/apache/qpid/client/MessageListenerTest.java new file mode 100644 index 0000000000..e1c0f0ccef --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/client/MessageListenerTest.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.client; + +import org.apache.qpid.test.utils.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +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.Context; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * QPID-293 Setting MessageListener after connection has started can cause messages to be "lost" on a internal delivery + * queue <p/> The message delivery process: Mina puts a message on _queue in AMQSession and the dispatcher thread + * take()s from here and dispatches to the _consumers. If the _consumer doesn't have a message listener set at + * connection start then messages are stored on _synchronousQueue (which needs to be > 1 to pass JMS TCK as multiple + * consumers on a session can run in any order and a synchronous put/poll will block the dispatcher). <p/> When setting + * the message listener later the _synchronousQueue is just poll()'ed and the first message delivered the remaining + * messages will be left on the queue and lost, subsequent messages on the session will arrive first. + */ +public class MessageListenerTest extends QpidTestCase implements MessageListener +{ + private static final Logger _logger = LoggerFactory.getLogger(MessageListenerTest.class); + + Context _context; + + private static final int MSG_COUNT = 5; + private int receivedCount = 0; + private MessageConsumer _consumer; + private Connection _clientConnection; + private CountDownLatch _awaitMessages = new CountDownLatch(MSG_COUNT); + + protected void setUp() throws Exception + { + super.setUp(); + + // Create Client + _clientConnection = getConnection("guest", "guest"); + + _clientConnection.start(); + + Session clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Queue queue =clientSession.createQueue("message-listener-test-queue"); + + _consumer = clientSession.createConsumer(queue); + + // Create Producer + + Connection producerConnection = getConnection("guest", "guest"); + + producerConnection.start(); + + Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageProducer producer = producerSession.createProducer(queue); + + for (int msg = 0; msg < MSG_COUNT; msg++) + { + producer.send(producerSession.createTextMessage("Message " + msg)); + } + + producerConnection.close(); + + } + + protected void tearDown() throws Exception + { + _clientConnection.close(); + super.tearDown(); + } + + public void testSynchronousRecieve() throws Exception + { + for (int msg = 0; msg < MSG_COUNT; msg++) + { + assertTrue(_consumer.receive(2000) != null); + } + } + + public void testAsynchronousRecieve() throws Exception + { + _consumer.setMessageListener(this); + + _logger.info("Waiting 3 seconds for messages"); + + try + { + _awaitMessages.await(3000, TimeUnit.MILLISECONDS); + } + catch (InterruptedException e) + { + // do nothing + } + // Should have recieved all async messages + assertEquals(MSG_COUNT, receivedCount); + + } + + public void testRecieveThenUseMessageListener() throws Exception + { + + _logger.error("Test disabled as initial receive is not called first"); + // Perform initial receive to start connection + assertTrue(_consumer.receive(2000) != null); + receivedCount++; + + // Sleep to ensure remaining 4 msgs end up on _synchronousQueue + Thread.sleep(1000); + + // Set the message listener and wait for the messages to come in. + _consumer.setMessageListener(this); + + _logger.info("Waiting 3 seconds for messages"); + + try + { + _awaitMessages.await(3000, TimeUnit.MILLISECONDS); + } + catch (InterruptedException e) + { + // do nothing + } + // Should have recieved all async messages + assertEquals(MSG_COUNT, receivedCount); + + } + + public void onMessage(Message message) + { + _logger.info("Received Message(" + receivedCount + "):" + message); + + receivedCount++; + _awaitMessages.countDown(); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(MessageListenerTest.class); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/client/ResetMessageListenerTest.java b/java/systests/src/main/java/org/apache/qpid/client/ResetMessageListenerTest.java new file mode 100644 index 0000000000..a0bb31192f --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/client/ResetMessageListenerTest.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.client; + +import org.apache.qpid.test.utils.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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 javax.naming.Context; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * QPID-293 Setting MessageListener after connection has started can cause messages to be "lost" on a internal delivery + * queue <p/> The message delivery process: Mina puts a message on _queue in AMQSession and the dispatcher thread + * take()s from here and dispatches to the _consumers. If the _consumer1 doesn't have a message listener set at + * connection start then messages are stored on _synchronousQueue (which needs to be > 1 to pass JMS TCK as multiple + * consumers on a session can run in any order and a synchronous put/poll will block the dispatcher). <p/> When setting + * the message listener later the _synchronousQueue is just poll()'ed and the first message delivered the remaining + * messages will be left on the queue and lost, subsequent messages on the session will arrive first. + */ +public class ResetMessageListenerTest extends QpidTestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(ResetMessageListenerTest.class); + + Context _context; + + private static final int MSG_COUNT = 6; + private int receivedCount1ML1 = 0; + private int receivedCount1ML2 = 0; + private int receivedCount2 = 0; + private Connection _clientConnection, _producerConnection; + private MessageConsumer _consumer1; + private MessageConsumer _consumer2; + MessageProducer _producer; + Session _clientSession, _producerSession; + + private final CountDownLatch _allFirstMessagesSent = new CountDownLatch(2); // all messages Sent Lock + private final CountDownLatch _allSecondMessagesSent = new CountDownLatch(2); // all messages Sent Lock + private final CountDownLatch _allFirstMessagesSent010 = new CountDownLatch(MSG_COUNT); // all messages Sent Lock + private final CountDownLatch _allSecondMessagesSent010 = new CountDownLatch(MSG_COUNT); // all messages Sent Lock + + private String oldImmediatePrefetch; + + protected void setUp() throws Exception + { + super.setUp(); + + oldImmediatePrefetch = System.getProperty(AMQSession.IMMEDIATE_PREFETCH); + System.setProperty(AMQSession.IMMEDIATE_PREFETCH, "true"); + + _clientConnection = getConnection("guest", "guest"); + + // Create Client 1 + + _clientSession = _clientConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Queue queue = _clientSession.createQueue("reset-message-listener-test-queue"); + + _consumer1 = _clientSession.createConsumer(queue); + + // Create Client 2 on same session + _consumer2 = _clientSession.createConsumer(queue); + + // Create Producer + _producerConnection = getConnection("guest", "guest"); + + _producerConnection.start(); + + _producerSession = _producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + _producer = _producerSession.createProducer(queue); + + TextMessage m = _producerSession.createTextMessage(); + m.setStringProperty("rank", "first"); + for (int msg = 0; msg < MSG_COUNT; msg++) + { + m.setText("Message " + msg); + _producer.send(m); + } + + } + + protected void tearDown() throws Exception + { + _clientConnection.close(); + + super.tearDown(); + if (oldImmediatePrefetch == null) + { + oldImmediatePrefetch = AMQSession.IMMEDIATE_PREFETCH_DEFAULT; + } + System.setProperty(AMQSession.IMMEDIATE_PREFETCH, oldImmediatePrefetch); + } + + public void testAsynchronousRecieve() + { + + _logger.info("Test Start"); + if (isBroker08()) + { + // Set default Message Listener + try + { + _consumer1.setMessageListener(new MessageListener() + { + public void onMessage(Message message) + { + _logger.info("Client 1 ML 1 Received Message(" + receivedCount1ML1 + "):" + message); + + receivedCount1ML1++; + if (receivedCount1ML1 == (MSG_COUNT / 2)) + { + _allFirstMessagesSent.countDown(); + } + } + }); + } + catch (JMSException e) + { + _logger.error("Error Setting Default ML on consumer1"); + } + + try + { + _consumer2.setMessageListener(new MessageListener() + { + public void onMessage(Message message) + { + _logger.info("Client 2 Received Message(" + receivedCount2 + "):" + message); + + receivedCount2++; + if (receivedCount2 == (MSG_COUNT / 2)) + { + _logger.info("Client 2 received all its messages1"); + _allFirstMessagesSent.countDown(); + } + + if (receivedCount2 == MSG_COUNT) + { + _logger.info("Client 2 received all its messages2"); + _allSecondMessagesSent.countDown(); + } + } + }); + + _clientConnection.start(); + } + catch (JMSException e) + { + _logger.error("Error Setting Default ML on consumer2"); + + } + + try + { + _allFirstMessagesSent.await(1000, TimeUnit.MILLISECONDS); + _logger.info("Received first batch of messages"); + } + catch (InterruptedException e) + { + // do nothing + } + + try + { + _clientConnection.stop(); + } + catch (JMSException e) + { + _logger.error("Error stopping connection"); + } + + _logger.info("Reset Message Listener to better listener while connection stopped, will restart session"); + try + { + _consumer1.setMessageListener(new MessageListener() + { + public void onMessage(Message message) + { + _logger.info("Client 1 ML2 Received Message(" + receivedCount1ML1 + "):" + message); + + receivedCount1ML2++; + if (receivedCount1ML2 == (MSG_COUNT / 2)) + { + _allSecondMessagesSent.countDown(); + } + } + }); + + _clientConnection.start(); + } + catch (javax.jms.IllegalStateException e) + { + _logger.error("Connection not stopped while setting ML", e); + fail("Unable to change message listener:" + e.getCause()); + } + catch (JMSException e) + { + _logger.error("Error Setting Better ML on consumer1", e); + } + + try + { + _logger.info("Send additional messages"); + + for (int msg = 0; msg < MSG_COUNT; msg++) + { + _producer.send(_producerSession.createTextMessage("Message " + msg)); + } + } + catch (JMSException e) + { + _logger.error("Unable to send additional messages", e); + } + + _logger.info("Waiting upto 2 seconds for messages"); + + try + { + _allSecondMessagesSent.await(5000, TimeUnit.MILLISECONDS); + } + catch (InterruptedException e) + { + // do nothing + } + assertEquals("First batch of messages not received correctly", 0, _allFirstMessagesSent.getCount()); + assertEquals("Second batch of messages not received correctly", 0, _allSecondMessagesSent.getCount()); + assertEquals("Client 1 ML1 didn't get all messages", MSG_COUNT / 2, receivedCount1ML1); + assertEquals("Client 2 didn't get all messages", MSG_COUNT, receivedCount2); + assertEquals("Client 1 ML2 didn't get all messages", MSG_COUNT / 2, receivedCount1ML2); + } + else + { + try + { + _consumer2.close(); + _consumer1.setMessageListener(new MessageListener() + { + public void onMessage(Message message) + { + _logger.info("Received Message(" + receivedCount1ML1 + "):" + message); + + try + { + if (message.getStringProperty("rank").equals("first")) + { + _allFirstMessagesSent010.countDown(); + } + } + catch (JMSException e) + { + e.printStackTrace(); + fail("error receiving message"); + } + } + }); + } + catch (JMSException e) + { + _logger.error("Error Setting Default ML on consumer1"); + } + try + { + _allFirstMessagesSent.await(1000, TimeUnit.MILLISECONDS); + _logger.info("Received first batch of messages"); + } + catch (InterruptedException e) + { + // do nothing + } + + try + { + _clientConnection.stop(); + } + catch (JMSException e) + { + _logger.error("Error stopping connection"); + } + + _logger.info("Reset Message Listener "); + try + { + _consumer1.setMessageListener(new MessageListener() + { + public void onMessage(Message message) + { + _logger.info("Received Message(" + receivedCount1ML1 + "):" + message); + + try + { + if (message.getStringProperty("rank").equals("first")) + { + _allFirstMessagesSent010.countDown(); + } + else + { + _allSecondMessagesSent010.countDown(); + } + } + catch (JMSException e) + { + e.printStackTrace(); + fail("error receiving message"); + } + } + }); + + _clientConnection.start(); + } + catch (javax.jms.IllegalStateException e) + { + _logger.error("Connection not stopped while setting ML", e); + fail("Unable to change message listener:" + e.getCause()); + } + catch (JMSException e) + { + _logger.error("Error Setting Better ML on consumer1", e); + } + + try + { + _logger.info("Send additional messages"); + TextMessage m = _producerSession.createTextMessage(); + m.setStringProperty("rank", "second"); + for (int msg = 0; msg < MSG_COUNT; msg++) + { + m.setText("Message " + msg); + _producer.send(m); + } + } + catch (JMSException e) + { + _logger.error("Unable to send additional messages", e); + } + + _logger.info("Waiting upto 2 seconds for messages"); + + try + { + _allSecondMessagesSent.await(1000, TimeUnit.MILLISECONDS); + } + catch (InterruptedException e) + { + // do nothing + } + assertEquals("First batch of messages not received correctly", 0, _allFirstMessagesSent010.getCount()); + assertEquals("Second batch of messages not received correctly", 0, _allSecondMessagesSent010.getCount()); + } + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(ResetMessageListenerTest.class); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/client/message/NonQpidObjectMessage.java b/java/systests/src/main/java/org/apache/qpid/client/message/NonQpidObjectMessage.java new file mode 100644 index 0000000000..60a26c8e62 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/client/message/NonQpidObjectMessage.java @@ -0,0 +1,234 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 java.io.Serializable; +import java.util.Enumeration; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.ObjectMessage; + +public class NonQpidObjectMessage implements ObjectMessage { + + private JMSObjectMessage _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 + */ + public NonQpidObjectMessage() + { + _realMessage = new JMSObjectMessage(); + } + + 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/java/systests/src/main/java/org/apache/qpid/test/client/CancelTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/CancelTest.java index 7b6d6eadba..25b9b0ba14 100644 --- a/java/systests/src/main/java/org/apache/qpid/test/client/CancelTest.java +++ b/java/systests/src/main/java/org/apache/qpid/test/client/CancelTest.java @@ -22,7 +22,7 @@ package org.apache.qpid.test.client; import org.apache.log4j.Logger; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import javax.jms.Connection; import javax.jms.MessageConsumer; diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java index 5659f533a1..aa501cd9c6 100644 --- a/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java +++ b/java/systests/src/main/java/org/apache/qpid/test/client/DupsOkTest.java @@ -1,7 +1,6 @@ package org.apache.qpid.test.client; -import org.apache.qpid.AMQException; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.apache.qpid.client.AMQDestination; import org.apache.qpid.client.AMQSession; diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/FlowControlTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/FlowControlTest.java index b5a9bd2236..94096e412d 100644 --- a/java/systests/src/main/java/org/apache/qpid/test/client/FlowControlTest.java +++ b/java/systests/src/main/java/org/apache/qpid/test/client/FlowControlTest.java @@ -21,15 +21,12 @@ package org.apache.qpid.test.client; import org.apache.qpid.client.AMQSession_0_8; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.test.FailoverBaseCase; +import org.apache.qpid.test.utils.QpidTestCase; import org.apache.log4j.Logger; import javax.jms.*; - - -public class FlowControlTest extends FailoverBaseCase +public class FlowControlTest extends QpidTestCase { private static final Logger _logger = Logger.getLogger(FlowControlTest.class); @@ -37,20 +34,14 @@ public class FlowControlTest extends FailoverBaseCase private Session _clientSession; private Queue _queue; - public void setUp() throws Exception - { - - super.setUp(); - - - } - /** * Simply + * + * @throws Exception */ public void testBasicBytesFlowControl() throws Exception { - _queue = new AMQQueue("amq.direct","testqueue");//(Queue) _context.lookup("queue"); + _queue = (Queue) getInitialContext().lookup("queue"); //Create Client _clientConnection = getConnection(); @@ -71,25 +62,24 @@ public class FlowControlTest extends FailoverBaseCase BytesMessage m1 = producerSession.createBytesMessage(); m1.writeBytes(new byte[128]); - m1.setIntProperty("msg",1); + m1.setIntProperty("msg", 1); producer.send(m1); BytesMessage m2 = producerSession.createBytesMessage(); m2.writeBytes(new byte[128]); - m2.setIntProperty("msg",2); + m2.setIntProperty("msg", 2); producer.send(m2); BytesMessage m3 = producerSession.createBytesMessage(); m3.writeBytes(new byte[256]); - m3.setIntProperty("msg",3); + 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).setPrefecthLimits(0,256); + ((AMQSession_0_8) consumerSession).setPrefecthLimits(0, 256); MessageConsumer recv = consumerSession.createConsumer(_queue); consumerConnection.start(); @@ -111,7 +101,6 @@ public class FlowControlTest extends FailoverBaseCase r2.acknowledge(); - r3 = recv.receive(RECEIVE_TIMEOUT); assertNotNull("Third message not received", r3); assertEquals("Messages in wrong order", 3, r3.getIntProperty("msg")); @@ -125,7 +114,7 @@ public class FlowControlTest extends FailoverBaseCase public void testTwoConsumersBytesFlowControl() throws Exception { - _queue = new AMQQueue("amq.direct","testqueue1");//(Queue) _context.lookup("queue"); + _queue = (Queue) getInitialContext().lookup("queue"); //Create Client _clientConnection = getConnection(); @@ -146,25 +135,24 @@ public class FlowControlTest extends FailoverBaseCase BytesMessage m1 = producerSession.createBytesMessage(); m1.writeBytes(new byte[128]); - m1.setIntProperty("msg",1); + m1.setIntProperty("msg", 1); producer.send(m1); BytesMessage m2 = producerSession.createBytesMessage(); m2.writeBytes(new byte[256]); - m2.setIntProperty("msg",2); + m2.setIntProperty("msg", 2); producer.send(m2); BytesMessage m3 = producerSession.createBytesMessage(); m3.writeBytes(new byte[128]); - m3.setIntProperty("msg",3); + 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).setPrefecthLimits(0,256); + ((AMQSession_0_8) consumerSession1).setPrefecthLimits(0, 256); MessageConsumer recv1 = consumerSession1.createConsumer(_queue); consumerConnection.start(); @@ -173,15 +161,13 @@ public class FlowControlTest extends FailoverBaseCase assertNotNull("First message not received", r1); assertEquals("Messages in wrong order", 1, r1.getIntProperty("msg")); - Message r2 = recv1.receiveNoWait(); assertNull("Second message incorrectly delivered", r2); - + Session consumerSession2 = consumerConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE); - ((AMQSession_0_8)consumerSession2).setPrefecthLimits(0,256); + ((AMQSession_0_8) consumerSession2).setPrefecthLimits(0, 256); MessageConsumer recv2 = consumerSession2.createConsumer(_queue); - r2 = recv2.receive(100000L);//RECEIVE_TIMEOUT); assertNotNull("Second message not received", r2); assertEquals("Messages in wrong order", 2, r2.getIntProperty("msg")); @@ -193,10 +179,8 @@ public class FlowControlTest extends FailoverBaseCase assertNotNull("Third message not received", r3); assertEquals("Messages in wrong order", 3, r3.getIntProperty("msg")); - - r2.acknowledge(); - r3.acknowledge(); + r3.acknowledge(); recv1.close(); recv2.close(); consumerSession1.close(); @@ -205,4 +189,23 @@ public class FlowControlTest extends FailoverBaseCase } + 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); + + test.startBroker(); + test.testBasicBytesFlowControl(); + + Thread.sleep(1000); + + test.stopBroker(); + } + } } + diff --git a/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java b/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java index 2dbac84fc5..67ebc6fde0 100644 --- a/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java +++ b/java/systests/src/main/java/org/apache/qpid/test/client/QueueBrowserAutoAckTest.java @@ -24,10 +24,9 @@ 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.test.FailoverBaseCase; +import org.apache.qpid.test.utils.FailoverBaseCase; import javax.jms.Connection; -import javax.jms.ConnectionFactory; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkBaseCase.java b/java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkBaseCase.java index 082f3f29bd..eb51a32166 100644 --- a/java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkBaseCase.java +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkBaseCase.java @@ -25,12 +25,12 @@ import org.apache.log4j.NDC; import org.apache.qpid.test.framework.BrokerLifecycleAware; import org.apache.qpid.test.framework.sequencers.CircuitFactory; +import org.apache.qpid.test.utils.QpidTestCase; import org.apache.qpid.junit.extensions.SetupTaskAware; import org.apache.qpid.junit.extensions.SetupTaskHandler; import org.apache.qpid.junit.extensions.util.ParsedProperties; import org.apache.qpid.junit.extensions.util.TestContextProperties; -import org.apache.qpid.testutil.QpidTestCase; import java.util.ArrayList; import java.util.List; diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java index 4852cab3a6..d0814ca5fc 100644 --- a/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/AcknowledgeTest.java @@ -31,9 +31,7 @@ import javax.jms.Session; import org.apache.qpid.client.AMQDestination; import org.apache.qpid.client.AMQSession; -import org.apache.qpid.client.transport.TransportConnection; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.testutil.QpidTestCase; +import org.apache.qpid.test.utils.QpidTestCase; public class AcknowledgeTest extends QpidTestCase { @@ -63,21 +61,6 @@ public class AcknowledgeTest extends QpidTestCase _consumerA = _consumerSession.createConsumer(_queue); } - @Override - protected void tearDown() throws Exception - { - super.tearDown(); - try - { - TransportConnection.killAllVMBrokers(); - ApplicationRegistry.removeAll(); - } - catch (Exception e) - { - fail("Unable to clean up"); - } - - } private void sendMessages(int totalMessages) throws JMSException diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java new file mode 100644 index 0000000000..7434fcbb30 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/ack/RecoverTest.java @@ -0,0 +1,331 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.jms.Session; +import org.apache.qpid.test.utils.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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.AtomicInteger; + +public class RecoverTest extends QpidTestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(RecoverTest.class); + + private Exception _error; + private AtomicInteger count; + + protected void setUp() throws Exception + { + super.setUp(); + _error = null; + count = new AtomicInteger(); + } + + protected void tearDown() throws Exception + { + super.tearDown(); + count = null; + } + + public void testRecoverResendsMsgs() throws Exception + { + AMQConnection con = (AMQConnection) getConnection("guest", "guest"); + + Session consumerSession = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Queue queue = + new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("someQ"), + new AMQShortString("someQ"), false, true); + MessageConsumer consumer = consumerSession.createConsumer(queue); + // force synch to ensure the consumer has resulted in a bound queue + // ((AMQSession) consumerSession).declareExchangeSynch(ExchangeDefaults.DIRECT_EXCHANGE_NAME, ExchangeDefaults.DIRECT_EXCHANGE_CLASS); + // This is the default now + + AMQConnection con2 = (AMQConnection) getConnection("guest", "guest"); + Session producerSession = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageProducer producer = producerSession.createProducer(queue); + + _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")); + + con2.close(); + + _logger.info("Starting connection"); + con.start(); + TextMessage tm = (TextMessage) consumer.receive(); + tm.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(); + tm = (TextMessage) consumer.receive(3000); + assertEquals("msg2", tm.getText()); + + tm = (TextMessage) consumer.receive(3000); + assertEquals("msg3", tm.getText()); + + tm = (TextMessage) consumer.receive(3000); + assertEquals("msg4", tm.getText()); + + _logger.info("Received redelivery of three messages. Acknowledging last message"); + tm.acknowledge(); + + _logger.info("Calling acknowledge with no outstanding messages"); + // all acked so no messages to be delivered + consumerSession.recover(); + + tm = (TextMessage) consumer.receiveNoWait(); + assertNull(tm); + _logger.info("No messages redelivered as is expected"); + + con.close(); + } + + public void testRecoverResendsMsgsAckOnEarlier() throws Exception + { + AMQConnection con = (AMQConnection) getConnection("guest", "guest"); + + Session consumerSession = con.createSession(false, Session.CLIENT_ACKNOWLEDGE); + Queue queue = + new AMQQueue(consumerSession.getDefaultQueueExchangeName(), new AMQShortString("someQ"), + new AMQShortString("someQ"), false, true); + MessageConsumer consumer = consumerSession.createConsumer(queue); + // force synch to ensure the consumer has resulted in a bound queue + // ((AMQSession) consumerSession).declareExchangeSynch(ExchangeDefaults.DIRECT_EXCHANGE_NAME, ExchangeDefaults.DIRECT_EXCHANGE_CLASS); + // This is the default now + + AMQConnection con2 = (AMQConnection) getConnection("guest", "guest"); + Session producerSession = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageProducer producer = producerSession.createProducer(queue); + + _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")); + + con2.close(); + + _logger.info("Starting connection"); + con.start(); + TextMessage tm = (TextMessage) consumer.receive(); + consumer.receive(); + tm.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(); + TextMessage tm3 = (TextMessage) consumer.receive(3000); + assertEquals("msg3", tm3.getText()); + + TextMessage tm4 = (TextMessage) consumer.receive(3000); + assertEquals("msg4", tm4.getText()); + + _logger.info("Received redelivery of two messages. calling acknolwedgeThis() first of those message"); + ((org.apache.qpid.jms.Message) tm3).acknowledgeThis(); + + _logger.info("Calling recover"); + // all acked so no messages to be delivered + consumerSession.recover(); + + tm4 = (TextMessage) consumer.receive(3000); + assertEquals("msg4", tm4.getText()); + ((org.apache.qpid.jms.Message) tm4).acknowledgeThis(); + + _logger.info("Calling recover"); + // all acked so no messages to be delivered + consumerSession.recover(); + + tm = (TextMessage) consumer.receiveNoWait(); + assertNull(tm); + _logger.info("No messages redelivered as is expected"); + + con.close(); + } + + public void testAcknowledgePerConsumer() throws Exception + { + AMQConnection con = (AMQConnection) getConnection("guest", "guest"); + + 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("guest", "guest"); + 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("guest", "guest"); + + 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 redilvered on what should be first delivery attempt")); + } + + consumerSession.recover(); + } + else if (count.get() == 2) + { + if (!message.getJMSRedelivered()) + { + setError( + new Exception( + "Message not marked as redilvered on what should be second delivery attempt")); + } + } + else + { + System.err.println(message); + fail("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 (count.get() != 2) + { + System.err.println("Count != 2 : " + count); + } + + assertTrue(count.get() == 2); + + con.close(); + + if (_error != null) + { + throw _error; + } + } + + private void setError(Exception e) + { + _error = e; + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(RecoverTest.class); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java new file mode 100644 index 0000000000..9a7fe7c039 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/BytesMessageTest.java @@ -0,0 +1,282 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 junit.framework.Assert; + +import org.apache.mina.common.ByteBuffer; + +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.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageNotReadableException; +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 BytesMessageTest extends QpidTestCase implements MessageListener +{ + private static final Logger _logger = LoggerFactory.getLogger(BytesMessageTest.class); + + private Connection _connection; + private Destination _destination; + private Session _session; + private final List<JMSBytesMessage> received = new ArrayList<JMSBytesMessage>(); + private final List<byte[]> messages = new ArrayList<byte[]>(); + 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) + { + while (received.size() < count) + { + received.wait(); + } + } + } + + void check() throws JMSException + { + List<byte[]> actual = new ArrayList<byte[]>(); + 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<String> errors = new ArrayList<String>(); + 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]); + } + + System.out.println("connectionString = " + connectionString); + System.out.println("count = " + count); + + BytesMessageTest test = new BytesMessageTest(); + test._connectionString = connectionString; + test._count = count; + test.test(); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/basic/FieldTableMessageTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/FieldTableMessageTest.java new file mode 100644 index 0000000000..979023d4b6 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/FieldTableMessageTest.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.test.unit.basic; + +import org.apache.mina.common.ByteBuffer; + +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.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.BytesMessage; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class FieldTableMessageTest extends QpidTestCase implements MessageListener +{ + private static final Logger _logger = LoggerFactory.getLogger(FieldTableMessageTest.class); + + private AMQConnection _connection; + private AMQDestination _destination; + private AMQSession _session; + private final ArrayList<JMSBytesMessage> received = new ArrayList<JMSBytesMessage>(); + private FieldTable _expected; + private int _count = 10; + public 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 + { + for (Object m : received) + { + ByteBuffer buffer = ((JMSBytesMessage) m).getData(); + FieldTable actual = FieldTableFactory.newFieldTable(buffer, buffer.remaining()); + 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/java/systests/src/main/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java new file mode 100644 index 0000000000..06f4a6464f --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.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.basic; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.test.utils.QpidTestCase; + +import javax.jms.Session; +import javax.jms.QueueSession; +import javax.jms.Queue; +import javax.jms.QueueSender; +import javax.jms.TextMessage; +import javax.jms.InvalidDestinationException; + +public class InvalidDestinationTest extends QpidTestCase +{ + 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 + { + Queue invalidDestination = new AMQQueue("amq.direct","unknownQ"); + AMQQueue validDestination = new AMQQueue("amq.direct","knownQ"); + QueueSession queueSession = _connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + + // This is the only easy way to create and bind a queue from the API :-( + queueSession.createConsumer(validDestination); + + QueueSender sender = queueSession.createSender(invalidDestination); + TextMessage msg = queueSession.createTextMessage("Hello"); + try + { + sender.send(msg); + fail("Expected InvalidDestinationException"); + } + catch (InvalidDestinationException ex) + { + // pass + } + sender.close(); + + sender = queueSession.createSender(null); + invalidDestination = new AMQQueue("amq.direct","unknownQ"); + + try + { + sender.send(invalidDestination,msg); + fail("Expected InvalidDestinationException"); + } + catch (InvalidDestinationException ex) + { + // pass + } + sender.send(validDestination,msg); + sender.close(); + validDestination = new AMQQueue("amq.direct","knownQ"); + sender = queueSession.createSender(validDestination); + sender.send(msg); + + + + + } + + + public static junit.framework.Test suite() + { + + return new junit.framework.TestSuite(InvalidDestinationTest.class); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java new file mode 100644 index 0000000000..24fef48028 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/LargeMessageTest.java @@ -0,0 +1,184 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.test.utils.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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 QpidTestCase +{ + 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 test64kminus1() + { + checkLargeMessage((64 * 1024) - 1); + } + + public void test64k() + { + checkLargeMessage(64 * 1024); + } + + 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(1000); + + assertNotNull("Null message recevied", result); + assertEquals("Message Size", _messageText.length(), result.getText().length()); + assertEquals("Message content differes", _messageText, result.getText()); + } + catch (JMSException e) + { + e.printStackTrace(); + fail("Excpetion 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/java/systests/src/main/java/org/apache/qpid/test/unit/basic/MapMessageTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/MapMessageTest.java new file mode 100644 index 0000000000..390850185c --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/MapMessageTest.java @@ -0,0 +1,1271 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 junit.framework.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.JMSMapMessage; +import org.apache.qpid.test.utils.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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 QpidTestCase implements MessageListener +{ + private static final Logger _logger = LoggerFactory.getLogger(MapMessageTest.class); + + private AMQConnection _connection; + private Destination _destination; + private AMQSession _session; + private final List<JMSMapMessage> received = new ArrayList<JMSMapMessage>(); + + 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")); + + // 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")); + + Assert.assertEquals(_smallfloat, (float) m.getDouble("smallfloat")); + + // 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<Primiative> + + // 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<String> errors = new ArrayList<String>(); + 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/java/systests/src/main/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java new file mode 100644 index 0000000000..658cf26135 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/MultipleConnectionTest.java @@ -0,0 +1,230 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.AMQDestination; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.client.transport.TransportConnection; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.test.utils.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; + +public class MultipleConnectionTest extends QpidTestCase +{ + 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(); + } + } + + 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; + } + } + + protected void setUp() throws Exception + { + super.setUp(); + TransportConnection.createVMBroker(1); + } + + protected void tearDown() throws Exception + { + super.tearDown(); + TransportConnection.killAllVMBrokers(); + } + + 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]._counters); + } + } + + 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(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/java/systests/src/main/java/org/apache/qpid/test/unit/basic/ObjectMessageTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/ObjectMessageTest.java new file mode 100644 index 0000000000..10705119e7 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/ObjectMessageTest.java @@ -0,0 +1,273 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 junit.framework.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.message.JMSObjectMessage; +import org.apache.qpid.test.utils.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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 QpidTestCase implements MessageListener +{ + private static final Logger _logger = LoggerFactory.getLogger(ObjectMessageTest.class); + + private AMQConnection _connection; + private AMQDestination _destination; + private AMQSession _session; + private final List<JMSObjectMessage> received = new ArrayList<JMSObjectMessage>(); + private final List<Payload> messages = new ArrayList<Payload>(); + 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) + { + while (received.size() < count) + { + received.wait(); + } + } + } + + void check() throws JMSException + { + List<Object> actual = new ArrayList<Object>(); + 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<String> errors = new ArrayList<String>(); + 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/java/systests/src/main/java/org/apache/qpid/test/unit/basic/PropertyValueTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/PropertyValueTest.java new file mode 100644 index 0000000000..ca896b08bb --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/PropertyValueTest.java @@ -0,0 +1,375 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 junit.framework.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.AMQMessage; +import org.apache.qpid.client.message.JMSTextMessage; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class PropertyValueTest extends QpidTestCase implements MessageListener +{ + private static final Logger _logger = LoggerFactory.getLogger(PropertyValueTest.class); + + private int count = 0; + private AMQConnection _connection; + private Destination _destination; + private AMQSession _session; + private final List<JMSTextMessage> received = new ArrayList<JMSTextMessage>(); + private final List<String> messages = new ArrayList<String>(); + private int _count = 1; + public String _connectionString = "vm://:1"; + private static final String USERNAME = "guest"; + + protected void setUp() throws Exception + { + 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(); + } + + 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); + e.printStackTrace(); + } + } + + 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("TempQueue", q.toString()); + + _logger.debug("Message:" + m); + + Assert.assertEquals("Check temp queue has been set correctly", m.getJMSReplyTo().toString(), + m.getStringProperty("TempQueue")); + + 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"); + + // AMQP Specific values + + // Timestamp + long nano = System.nanoTime(); + m.setStringProperty("time-str", String.valueOf(nano)); + ((AMQMessage) m).setTimestampProperty(new AMQShortString("time"), nano); + + // Decimal + BigDecimal bd = new BigDecimal(Integer.MAX_VALUE); + ((AMQMessage) m).setDecimalProperty(new AMQShortString("decimal"), bd.setScale(Byte.MAX_VALUE)); + + bd = new BigDecimal((long) Integer.MAX_VALUE + 1L); + + try + { + ((AMQMessage) m).setDecimalProperty(new AMQShortString("decimal-bad-value"), bd.setScale(Byte.MAX_VALUE)); + fail("UnsupportedOperationException should be thrown as value can't be correctly transmitted"); + } + catch (UnsupportedOperationException uoe) + { + // normal path. + } + + try + { + ((AMQMessage) m).setDecimalProperty(new AMQShortString("decimal-bad-scale"), + bd.setScale(Byte.MAX_VALUE + 1)); + fail("UnsupportedOperationException should be thrown as scale can't be correctly transmitted"); + } + catch (UnsupportedOperationException uoe) + { + // normal path. + } + + // Void + ((AMQMessage) m).setVoidProperty(new AMQShortString("void")); + + _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 + { + List<String> actual = new ArrayList<String>(); + 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) Byte.MAX_VALUE, + m.getByteProperty("Byte")); + Assert.assertEquals("Check Double properties are correctly transported", (double) Double.MAX_VALUE, + m.getDoubleProperty("Double")); + Assert.assertEquals("Check Float properties are correctly transported", (float) Float.MAX_VALUE, + m.getFloatProperty("Float")); + Assert.assertEquals("Check Int properties are correctly transported", (int) 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 + Assert.assertEquals("Check ReplyTo properties are correctly transported", m.getStringProperty("TempQueue"), + m.getJMSReplyTo().toString()); + + 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")); + + // AMQP Tests Specific values + + Assert.assertEquals("Check Timestamp properties are correctly transported", m.getStringProperty("time-str"), + ((AMQMessage) m).getTimestampProperty(new AMQShortString("time")).toString()); + + // Decimal + BigDecimal bd = new BigDecimal(Integer.MAX_VALUE); + + Assert.assertEquals("Check decimal properties are correctly transported", bd.setScale(Byte.MAX_VALUE), + ((AMQMessage) m).getDecimalProperty(new AMQShortString("decimal"))); + + // Void + ((AMQMessage) m).setVoidProperty(new AMQShortString("void")); + + Assert.assertTrue("Check void properties are correctly transported", + ((AMQMessage) m).getPropertyHeaders().containsKey("void")); + + //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<String> errors = new ArrayList<String>(); + 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/java/systests/src/main/java/org/apache/qpid/test/unit/basic/PubSubTwoConnectionTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/PubSubTwoConnectionTest.java new file mode 100644 index 0000000000..66c5a5b07e --- /dev/null +++ b/java/systests/src/main/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 javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.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.QpidTestCase; + +/** + * @author Apache Software Foundation + */ +public class PubSubTwoConnectionTest extends QpidTestCase +{ + 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/java/systests/src/main/java/org/apache/qpid/test/unit/basic/ReceiveTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/ReceiveTest.java new file mode 100644 index 0000000000..eec3db8c5f --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/ReceiveTest.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.basic; + +import javax.jms.MessageConsumer; +import javax.jms.Message; + +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.QpidTestCase; + +public class ReceiveTest extends QpidTestCase +{ + private AMQConnection _connection; + private AMQDestination _destination; + private AMQSession _session; + private MessageConsumer _consumer; + + 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,"ReceiveTest", true)); + } + + private void init(AMQConnection connection, AMQDestination destination) throws Exception + { + _connection = connection; + _destination = destination; + _session = (AMQSession) connection.createSession(true, AMQSession.NO_ACKNOWLEDGE); + _consumer = _session.createConsumer(_destination); + _connection.start(); + } + + public void test() throws Exception + { + Message m = _consumer.receive(5000); + assertNull("should not have received a message", m); + _connection.close(); + } + + + public static junit.framework.Test suite() + { + // TODO: note that this test doesn't use the VMBrokerSetup + // test helper class to create and tear down its + // VMBroker. This is because the main() above seems to + // indicate that it's also used outside of the surefire test + // framework. If it isn't, then this test should also be + // changed to use VMBrokerSetup here. + return new junit.framework.TestSuite(ReceiveTest.class); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SelectorTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SelectorTest.java new file mode 100644 index 0000000000..cc9afeffa2 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SelectorTest.java @@ -0,0 +1,302 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.AMQException; +import org.apache.qpid.test.utils.QpidTestCase; +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.url.URLSyntaxException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +import javax.jms.DeliveryMode; +import javax.jms.InvalidSelectorException; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; + +public class SelectorTest extends QpidTestCase implements MessageListener +{ + private static final Logger _logger = LoggerFactory.getLogger(SelectorTest.class); + + private AMQConnection _connection; + private AMQDestination _destination; + private AMQSession _session; + private int count; + public String _connectionString = "vm://:1"; + private static final String INVALID_SELECTOR = "Cost LIKE 5"; + + 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 JMSException + { + init(connection, new AMQQueue(connection, randomize("SessionStartTest"), true)); + } + + private void init(AMQConnection connection, AMQDestination destination) throws JMSException + { + _connection = connection; + _destination = destination; + connection.start(); + + String selector = null; + selector = "Cost = 2 AND \"property-with-hyphen\" = 'wibble'"; + // selector = "JMSType = Special AND Cost = 2 AND AMQMessageID > 0 AND JMSDeliveryMode=" + DeliveryMode.NON_PERSISTENT; + + _session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); + // _session.createConsumer(destination).setMessageListener(this); + _session.createConsumer(destination, selector).setMessageListener(this); + } + + public synchronized void test() throws Exception + { + try + { + + init((AMQConnection) getConnection("guest", "guest", randomize("Client"))); + + 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..."); + wait(1000); + + 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 + { + System.out.println("SUCCESS!!"); + } + } + catch (InterruptedException e) + { + _logger.debug("IE :" + e.getClass().getSimpleName() + ":" + e.getMessage()); + } + catch (URLSyntaxException e) + { + _logger.debug("URL:" + e.getClass().getSimpleName() + ":" + e.getMessage()); + fail("Wrong exception"); + } + catch (AMQException e) + { + _logger.debug("AMQ:" + e.getClass().getSimpleName() + ":" + e.getMessage()); + fail("Wrong exception"); + } + + finally + { + if (_session != null) + { + _session.close(); + } + if (_connection != null) + { + _connection.close(); + } + } + } + + + public void testInvalidSelectors() throws Exception + { + Connection connection = null; + + try + { + connection = getConnection("guest", "guest", randomize("Client")); + _session = (AMQSession) connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); + } + catch (JMSException e) + { + fail(e.getMessage()); + } + catch (AMQException e) + { + fail(e.getMessage()); + } + catch (URLSyntaxException e) + { + fail("Error:" + e.getMessage()); + } + + //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()); + } + else + { + _logger.debug("SUCCESS!!"); + } + } + + //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()); + } + else + { + _logger.debug("SUCCESS!!"); + } + } + + //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()); + } + else + { + _logger.debug("SUCCESS!!"); + } + } + + finally + { + if (_session != null) + { + try + { + _session.close(); + } + catch (JMSException e) + { + fail("Error cleaning up:" + e.getMessage()); + } + } + if (_connection != null) + { + try + { + _connection.close(); + } + catch (JMSException e) + { + fail("Error cleaning up:" + e.getMessage()); + } + } + } + } + + public synchronized void onMessage(Message message) + { + count++; + _logger.info("Got Message:" + message); + notify(); + } + + private static String randomize(String in) + { + return in + System.currentTimeMillis(); + } + + public static void main(String[] argv) throws Exception + { + SelectorTest test = new SelectorTest(); + test._connectionString = (argv.length == 0) ? "localhost:3000" : argv[0]; + + try + { + while (true) + { + if (test._connectionString.contains("vm://:1")) + { + test.setUp(); + } + test.test(); + + if (test._connectionString.contains("vm://:1")) + { + test.tearDown(); + } + } + } + catch (Exception e) + { + System.err.println(e.getMessage()); + e.printStackTrace(); + } + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(SelectorTest.class); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SessionStartTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/SessionStartTest.java new file mode 100644 index 0000000000..10320914fe --- /dev/null +++ b/java/systests/src/main/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.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.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; + +public class SessionStartTest extends QpidTestCase 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/java/systests/src/main/java/org/apache/qpid/test/unit/basic/TextMessageTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/TextMessageTest.java new file mode 100644 index 0000000000..29943161d4 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/TextMessageTest.java @@ -0,0 +1,248 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 junit.framework.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.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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 QpidTestCase implements MessageListener +{ + private static final Logger _logger = LoggerFactory.getLogger(TextMessageTest.class); + + private AMQConnection _connection; + private Destination _destination; + private AMQSession _session; + private final List<JMSTextMessage> received = new ArrayList<JMSTextMessage>(); + private final List<String> messages = new ArrayList<String>(); + 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) + { + e.printStackTrace(); + } + 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<String> actual = new ArrayList<String>(); + 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<String> errors = new ArrayList<String>(); + 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/java/systests/src/main/java/org/apache/qpid/test/unit/basic/close/CloseTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/close/CloseTest.java new file mode 100644 index 0000000000..21eaad6d5b --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/basic/close/CloseTest.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.qpid.test.unit.basic.close; +import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.url.AMQBindingURL; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; + +public class CloseTest extends QpidTestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(CloseTest.class); + + private static final String BROKER = "vm://:1"; + + protected void setUp() throws Exception + { + super.setUp(); + } + + protected void tearDown() throws Exception + { + super.setUp(); + } + + public void testCloseQueueReceiver() throws Exception + { + AMQConnection connection = (AMQConnection) getConnection("guest", "guest"); + + Session session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); + + AMQQueue queue = new AMQQueue(new AMQBindingURL("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/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQConnectionTest.java new file mode 100644 index 0000000000..c91c27e894 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQConnectionTest.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.test.unit.client; + +import javax.jms.JMSException; +import javax.jms.QueueSession; +import javax.jms.TopicSession; + +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.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidTestCase; + +public class AMQConnectionTest extends QpidTestCase +{ + private static AMQConnection _connection; + private static AMQTopic _topic; + private static AMQQueue _queue; + private static QueueSession _queueSession; + private static TopicSession _topicSession; + + protected void setUp() throws Exception + { + super.setUp(); + _connection = (AMQConnection) getConnection("guest", "guest"); + _topic = new AMQTopic(_connection.getDefaultTopicExchangeName(), new AMQShortString("mytopic")); + _queue = new AMQQueue(_connection.getDefaultQueueExchangeName(), new AMQShortString("myqueue")); + } + + protected void tearDown() throws Exception + { + _connection.close(); + super.tearDown(); + } + + /** + * Simple tests to check we can create TopicSession and QueueSession ok + * And that they throw exceptions where appropriate as per JMS spec + */ + + public void testCreateQueueSession() throws JMSException + { + _queueSession = _connection.createQueueSession(false, AMQSession.NO_ACKNOWLEDGE); + } + + public void testCreateTopicSession() throws JMSException + { + _topicSession = _connection.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE); + } + + public void testTopicSessionCreateBrowser() throws JMSException + { + try + { + _topicSession.createBrowser(_queue); + fail("expected exception did not occur"); + } + catch (javax.jms.IllegalStateException s) + { + // ok + } + catch (Exception e) + { + fail("expected javax.jms.IllegalStateException, got " + e); + } + } + + public void testTopicSessionCreateQueue() throws JMSException + { + try + { + _topicSession.createQueue("abc"); + fail("expected exception did not occur"); + } + catch (javax.jms.IllegalStateException s) + { + // ok + } + catch (Exception e) + { + fail("expected javax.jms.IllegalStateException, got " + e); + } + } + + public void testTopicSessionCreateTemporaryQueue() throws JMSException + { + try + { + _topicSession.createTemporaryQueue(); + fail("expected exception did not occur"); + } + catch (javax.jms.IllegalStateException s) + { + // ok + } + catch (Exception e) + { + fail("expected javax.jms.IllegalStateException, got " + e); + } + } + + public void testQueueSessionCreateTemporaryTopic() throws JMSException + { + try + { + _queueSession.createTemporaryTopic(); + fail("expected exception did not occur"); + } + catch (javax.jms.IllegalStateException s) + { + // ok + } + catch (Exception e) + { + fail("expected javax.jms.IllegalStateException, got " + e); + } + } + + public void testQueueSessionCreateTopic() throws JMSException + { + try + { + _queueSession.createTopic("abc"); + fail("expected exception did not occur"); + } + catch (javax.jms.IllegalStateException s) + { + // ok + } + catch (Exception e) + { + fail("expected javax.jms.IllegalStateException, got " + e); + } + } + + public void testQueueSessionDurableSubscriber() throws JMSException + { + try + { + _queueSession.createDurableSubscriber(_topic, "abc"); + fail("expected exception did not occur"); + } + catch (javax.jms.IllegalStateException s) + { + // ok + } + catch (Exception e) + { + fail("expected javax.jms.IllegalStateException, got " + e); + } + } + + public void testQueueSessionUnsubscribe() throws JMSException + { + try + { + _queueSession.unsubscribe("abc"); + fail("expected exception did not occur"); + } + catch (javax.jms.IllegalStateException s) + { + // ok + } + catch (Exception e) + { + fail("expected javax.jms.IllegalStateException, got " + e); + } + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(AMQConnectionTest.class); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQSessionTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQSessionTest.java new file mode 100644 index 0000000000..417b9b75f0 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/AMQSessionTest.java @@ -0,0 +1,108 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.client; + +import javax.jms.JMSException; +import javax.jms.QueueReceiver; +import javax.jms.TopicSubscriber; + +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.QpidTestCase; + +/** + * Tests for QueueReceiver and TopicSubscriber creation methods on AMQSession + */ +public class AMQSessionTest extends QpidTestCase +{ + + 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()); + } + + 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()); + } + + public static void stopVmBrokers() + { + _queue = null; + _topic = null; + _session = null; + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseOkTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseOkTest.java new file mode 100644 index 0000000000..b843f7c9c0 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseOkTest.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.unit.client.channelclose; + +import junit.textui.TestRunner; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.transport.TransportConnection; +import org.apache.qpid.test.utils.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Destination; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + +import java.util.ArrayList; +import java.util.List; + +/** + * Due to bizarre exception handling all sessions are closed if you get + * a channel close request and no exception listener is registered. + * <p/> + * JIRA issue IBTBLZ-10. + * <p/> + * Simulate by: + * <p/> + * 0. Create two sessions with no exception listener. + * 1. Publish message to queue/topic that does not exist (wrong routing key). + * 2. This will cause a channel close. + * 3. Since client does not have an exception listener, currently all sessions are + * closed. + */ +public class ChannelCloseOkTest extends QpidTestCase +{ + private AMQConnection _connection; + private Destination _destination1; + private Destination _destination2; + private Session _session1; + private Session _session2; + private final List<Message> _received1 = new ArrayList<Message>(); + private final List<Message> _received2 = new ArrayList<Message>(); + + private static final Logger _log = LoggerFactory.getLogger(ChannelCloseOkTest.class); + public String _connectionString = "vm://:1"; + + protected void setUp() throws Exception + { + super.setUp(); + + TransportConnection.createVMBroker(1); + _connection = (AMQConnection) getConnection("guest", "guest"); + + _destination1 = new AMQQueue(_connection, "q1", true); + _destination2 = new AMQQueue(_connection, "q2", true); + _session1 = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _session1.createConsumer(_destination1).setMessageListener(new MessageListener() + { + public void onMessage(Message message) + { + _log.debug("consumer 1 got message [" + getTextMessage(message) + "]"); + synchronized (_received1) + { + _received1.add(message); + _received1.notify(); + } + } + }); + _session2 = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + _session2.createConsumer(_destination2).setMessageListener(new MessageListener() + { + public void onMessage(Message message) + { + _log.debug("consumer 2 got message [" + getTextMessage(message) + "]"); + synchronized (_received2) + { + _received2.add(message); + _received2.notify(); + } + } + }); + + _connection.start(); + } + + private String getTextMessage(Message message) + { + TextMessage tm = (TextMessage) message; + try + { + return tm.getText(); + } + catch (JMSException e) + { + return "oops " + e; + } + } + + protected void tearDown() throws Exception + { + closeConnection(); + super.tearDown(); + } + + public void closeConnection() throws JMSException + { + if (_connection != null) + { + _log.info(">>>>>>>>>>>>>>.. closing"); + _connection.close(); + } + } + + public void testWithoutExceptionListener() throws Exception + { + doTest(); + } + + public void testWithExceptionListener() throws Exception + { + _connection.setExceptionListener(new ExceptionListener() + { + public void onException(JMSException jmsException) + { + _log.warn("onException - " + jmsException.getMessage()); + } + }); + + doTest(); + } + + public void doTest() throws Exception + { + // Check both sessions are ok. + sendAndWait(_session1, _destination1, "first", _received1, 1); + sendAndWait(_session2, _destination2, "second", _received2, 1); + assertEquals(1, _received1.size()); + assertEquals(1, _received2.size()); + + // Now send message to incorrect destination on session 1. + Destination destination = new AMQQueue(_connection, "incorrect"); + send(_session1, destination, "third"); // no point waiting as message will never be received. + + // Ensure both sessions are still ok. + // Send a bunch of messages as this give time for the sessions to be erroneously closed. + final int num = 300; + for (int i = 0; i < num; ++i) + { + send(_session1, _destination1, "" + i); + send(_session2, _destination2, "" + i); + } + + waitFor(_received1, num + 1); + waitFor(_received2, num + 1); + + // Note that the third message is never received as it is sent to an incorrect destination. + assertEquals(num + 1, _received1.size()); + assertEquals(num + 1, _received2.size()); + } + + private void sendAndWait(Session session, Destination destination, String message, List<Message> received, int count) + throws JMSException, InterruptedException + { + send(session, destination, message); + waitFor(received, count); + } + + private void send(Session session, Destination destination, String message) throws JMSException + { + _log.debug("sending message " + message); + MessageProducer producer1 = session.createProducer(destination); + producer1.send(session.createTextMessage(message)); + } + + private void waitFor(List<Message> received, int count) throws InterruptedException + { + long timeout = 20000; + + synchronized (received) + { + long start = System.currentTimeMillis(); + while (received.size() < count) + { + if (System.currentTimeMillis() - start > timeout) + { + fail("timeout expired waiting for messages"); + } + try + { + received.wait(timeout); + } + catch (InterruptedException e) + { + _log.info("Interrupted: " + e); + throw e; + } + + } + } + } + + private static String randomize(String in) + { + return in + System.currentTimeMillis(); + } + + public static void main(String[] args) + { + TestRunner.run(ChannelCloseOkTest.class); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(ChannelCloseOkTest.class); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java new file mode 100644 index 0000000000..d210f5e1a1 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/ChannelCloseTest.java @@ -0,0 +1,418 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.AMQException; +import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.failover.FailoverException; +import org.apache.qpid.client.protocol.AMQProtocolHandler; +import org.apache.qpid.client.transport.TransportConnection; +import org.apache.qpid.framing.*; +import org.apache.qpid.jms.ConnectionListener; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.url.URLSyntaxException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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 ChannelCloseTest extends QpidTestCase implements ExceptionListener, ConnectionListener +{ + private static final Logger _logger = LoggerFactory.getLogger(ChannelCloseTest.class); + + Connection _connection; + private String _brokerlist = "vm://:1"; + private Session _session; + private static final long SYNC_TIMEOUT = 500; + private int TEST = 0; + + protected void setUp() throws Exception + { + super.setUp(); + TransportConnection.createVMBroker(1); + } + + protected void tearDown() throws Exception + { + super.tearDown(); + TransportConnection.killAllVMBrokers(); + } + + /* + close channel, use chanel with same id ensure error. + */ + public void testReusingChannelAfterFullClosure() throws Exception + { + // this is testing an 0.8 conneciton + if(isBroker08()) + { + _connection=newConnection(); + + // Create Producer + try + { + _connection.start(); + + createChannelAndTest(1); + + // Cause it to close + try + { + _logger.info("Testing invalid exchange"); + declareExchange(1, "", "name_that_will_lookup_to_null", false); + fail("Exchange name is empty so this should fail "); + } + catch (AMQException e) + { + assertEquals("Exchange should not be found", AMQConstant.NOT_FOUND, e.getErrorCode()); + } + + // Check that + try + { + _logger.info("Testing valid exchange should fail"); + declareExchange(1, "topic", "amq.topic", false); + fail("This should not succeed as the channel should be closed "); + } + catch (AMQException e) + { + if (_logger.isInfoEnabled()) + { + _logger.info("Exception occured was:" + e.getErrorCode()); + } + + assertEquals("Connection should be closed", AMQConstant.CHANNEL_ERROR, e.getErrorCode()); + + _connection=newConnection(); + } + + checkSendingMessage(); + + _session.close(); + _connection.close(); + + } + catch (JMSException e) + { + e.printStackTrace(); + fail(e.getMessage()); + } + } + } + + /* + close channel and send guff then send ok no errors + REMOVE TEST - The behaviour after server has sent close is undefined. + the server should be free to fail as it may wish to reclaim its resources + immediately after close. + */ + /*public void testSendingMethodsAfterClose() throws Exception + { + // this is testing an 0.8 connection + if(isBroker08()) + { + try + { + _connection=new AMQConnection("amqp://guest:guest@CCTTest/test?brokerlist='" + _brokerlist + "'"); + + ((AMQConnection) _connection).setConnectionListener(this); + + _connection.setExceptionListener(this); + + // Change the StateManager for one that doesn't respond with Close-OKs + AMQStateManager oldStateManager=((AMQConnection) _connection).getProtocolHandler().getStateManager(); + + _session=_connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + _connection.start(); + + // Test connection + checkSendingMessage(); + + // Set StateManager to manager that ignores Close-oks + AMQProtocolSession protocolSession= + ((AMQConnection) _connection).getProtocolHandler().getProtocolSession(); + + MethodDispatcher d = protocolSession.getMethodDispatcher(); + + MethodDispatcher wrappedDispatcher = (MethodDispatcher) + Proxy.newProxyInstance(d.getClass().getClassLoader(), + d.getClass().getInterfaces(), + new MethodDispatcherProxyHandler( + (ClientMethodDispatcherImpl) d)); + + protocolSession.setMethodDispatcher(wrappedDispatcher); + + + AMQStateManager newStateManager=new NoCloseOKStateManager(protocolSession); + newStateManager.changeState(oldStateManager.getCurrentState()); + + ((AMQConnection) _connection).getProtocolHandler().setStateManager(newStateManager); + + final int TEST_CHANNEL=1; + _logger.info("Testing Channel(" + TEST_CHANNEL + ") Creation"); + + createChannelAndTest(TEST_CHANNEL); + + // Cause it to close + try + { + _logger.info("Closing Channel - invalid exchange"); + declareExchange(TEST_CHANNEL, "", "name_that_will_lookup_to_null", false); + fail("Exchange name is empty so this should fail "); + } + catch (AMQException e) + { + assertEquals("Exchange should not be found", AMQConstant.NOT_FOUND, e.getErrorCode()); + } + + try + { + // Send other methods that should be ignored + // send them no wait as server will ignore them + _logger.info("Tested known exchange - should ignore"); + declareExchange(TEST_CHANNEL, "topic", "amq.topic", true); + + _logger.info("Tested known invalid exchange - should ignore"); + declareExchange(TEST_CHANNEL, "", "name_that_will_lookup_to_null", true); + + _logger.info("Tested known invalid exchange - should ignore"); + declareExchange(TEST_CHANNEL, "", "name_that_will_lookup_to_null", true); + + // Send sync .. server will igore and timy oue + _logger.info("Tested known invalid exchange - should ignore"); + declareExchange(TEST_CHANNEL, "", "name_that_will_lookup_to_null", false); + } + catch (AMQTimeoutException te) + { + assertEquals("Request should timeout", AMQConstant.REQUEST_TIMEOUT, te.getErrorCode()); + } + catch (AMQException e) + { + fail("This should not fail as all requests should be ignored"); + } + + _logger.info("Sending Close"); + // Send Close-ok + sendClose(TEST_CHANNEL); + + _logger.info("Re-opening channel"); + + createChannelAndTest(TEST_CHANNEL); + + // Test connection is still ok + + checkSendingMessage(); + + } + catch (JMSException e) + { + e.printStackTrace(); + fail(e.getMessage()); + } + catch (AMQException e) + { + fail(e.getMessage()); + + } + catch (URLSyntaxException e) + { + fail(e.getMessage()); + } + finally + { + try + { + _session.close(); + _connection.close(); + } + catch (JMSException e) + { + e.printStackTrace(); + fail(e.getMessage()); + } + } + } + } +*/ + private void createChannelAndTest(int channel) throws FailoverException + { + // Create A channel + try + { + createChannel(channel); + } + catch (AMQException e) + { + fail(e.getMessage()); + } + + // Test it is ok + try + { + declareExchange(channel, "topic", "amq.topic", false); + _logger.info("Tested known exchange"); + } + catch (AMQException e) + { + fail("This should not fail as this is the default exchange details"); + } + } + + private void sendClose(int channel) + { + ChannelCloseOkBody body = + ((AMQConnection) _connection).getProtocolHandler().getMethodRegistry().createChannelCloseOkBody(); + AMQFrame frame = body.generateFrame(channel); + + ((AMQConnection) _connection).getProtocolHandler().writeFrame(frame); + } + + private void checkSendingMessage() throws JMSException + { + TEST++; + _logger.info("Test creating producer which will use channel id 1"); + + Queue queue = _session.createQueue("CCT_test_validation_queue" + TEST); + + MessageConsumer consumer = _session.createConsumer(queue); + + MessageProducer producer = _session.createProducer(queue); + + final String MESSAGE = "CCT_Test_Message"; + producer.send(_session.createTextMessage(MESSAGE)); + + Message msg = consumer.receive(2000); + + assertNotNull("Received messages should not be null.", msg); + assertEquals("Message received not what we sent", MESSAGE, ((TextMessage) msg).getText()); + } + + private Connection newConnection() + { + AMQConnection connection = null; + try + { + connection = new AMQConnection("amqp://guest:guest@CCTTest/test?brokerlist='" + _brokerlist + "'"); + + connection.setConnectionListener(this); + + _session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + connection.start(); + + } + catch (JMSException e) + { + fail("Creating new connection when:" + e.getMessage()); + } + catch (AMQException e) + { + fail("Creating new connection when:" + e.getMessage()); + } + catch (URLSyntaxException e) + { + fail("Creating new connection when:" + e.getMessage()); + } + + return connection; + } + + private void declareExchange(int channelId, String _type, String _name, boolean nowait) + throws AMQException, FailoverException + { + ExchangeDeclareBody body = + ((AMQConnection) _connection).getProtocolHandler() + .getMethodRegistry() + .createExchangeDeclareBody(0, + new AMQShortString(_name), + new AMQShortString(_type), + true, + false, + false, + false, + nowait, + null); + AMQFrame exchangeDeclare = body.generateFrame(channelId); + AMQProtocolHandler protocolHandler = ((AMQConnection) _connection).getProtocolHandler(); + + + if (nowait) + { + protocolHandler.writeFrame(exchangeDeclare); + } + else + { + protocolHandler.syncWrite(exchangeDeclare, ExchangeDeclareOkBody.class, SYNC_TIMEOUT); + } + +// return null; +// } +// }, (AMQConnection)_connection).execute(); + + } + + private void createChannel(int channelId) throws AMQException, FailoverException + { + ChannelOpenBody body = + ((AMQConnection) _connection).getProtocolHandler().getMethodRegistry().createChannelOpenBody(null); + + ((AMQConnection) _connection).getProtocolHandler().syncWrite(body.generateFrame(channelId), // outOfBand + ChannelOpenOkBody.class); + + } + + public void onException(JMSException jmsException) + { + // _logger.info("CCT" + jmsException); + fail(jmsException.getMessage()); + } + + public void bytesSent(long count) + { } + + public void bytesReceived(long count) + { } + + public boolean preFailover(boolean redirect) + { + return false; + } + + public boolean preResubscribe() + { + return false; + } + + public void failoverComplete() + { } + +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/CloseWithBlockingReceiveTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/CloseWithBlockingReceiveTest.java new file mode 100644 index 0000000000..d4d19a34ea --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/channelclose/CloseWithBlockingReceiveTest.java @@ -0,0 +1,81 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.client.channelclose; + +import javax.jms.MessageConsumer; +import javax.jms.Session; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.test.utils.QpidTestCase; + +/** + * @author Apache Software Foundation + */ +public class CloseWithBlockingReceiveTest extends QpidTestCase +{ + + + protected void setUp() throws Exception + { + super.setUp(); + } + + protected void tearDown() throws Exception + { + super.tearDown(); + } + + + public void testReceiveReturnsNull() throws Exception + { + final AMQConnection connection = (AMQConnection) getConnection("guest", "guest"); + Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageConsumer consumer = session.createConsumer(new AMQTopic(connection, "banana")); + connection.start(); + + Runnable r = new Runnable() + { + + public void run() + { + try + { + Thread.sleep(1000); + connection.close(); + } + catch (Exception e) + { + } + } + }; + long startTime = System.currentTimeMillis(); + new Thread(r).start(); + consumer.receive(10000); + assertTrue(System.currentTimeMillis() - startTime < 10000); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(CloseWithBlockingReceiveTest.class); + } + +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java new file mode 100644 index 0000000000..410939f583 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java @@ -0,0 +1,108 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.client.connection; + +import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpidity.transport.util.Logger; + +import java.util.HashMap; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +/** + * ConnectionCloseTest + * + */ + +public class ConnectionCloseTest extends QpidTestCase +{ + + private static final Logger log = Logger.get(ConnectionCloseTest.class); + + public void testSendReceiveClose() throws Exception + { + Map<Thread,StackTraceElement[]> before = Thread.getAllStackTraces(); + + for (int i = 0; i < 500; i++) + { + if ((i % 10) == 0) + { + log.warn("%d messages sent and received", i); + } + + Connection receiver = getConnection(); + receiver.start(); + Session rssn = receiver.createSession(false, Session.AUTO_ACKNOWLEDGE); + Queue queue = rssn.createQueue("connection-close-test-queue"); + MessageConsumer cons = rssn.createConsumer(queue); + + Connection sender = getConnection(); + sender.start(); + Session sssn = sender.createSession(false, Session.AUTO_ACKNOWLEDGE); + MessageProducer prod = sssn.createProducer(queue); + prod.send(sssn.createTextMessage("test")); + sender.close(); + + TextMessage m = (TextMessage) cons.receive(2000); + assertNotNull("message was lost", m); + assertEquals(m.getText(), "test"); + receiver.close(); + } + + // The finalizer is notifying connector thread waiting on a selector key. + // This should leave the finalizer enough time to notify those threads + synchronized (this) + { + this.wait(1000); + } + + Map<Thread,StackTraceElement[]> after = Thread.getAllStackTraces(); + + Map<Thread,StackTraceElement[]> delta = new HashMap<Thread,StackTraceElement[]>(after); + for (Thread t : before.keySet()) + { + delta.remove(t); + } + + dumpStacks(delta); + + assertTrue("Spurious thread creation exceeded threshold, " + + delta.size() + " threads created.", + delta.size() < 10); + } + + private void dumpStacks(Map<Thread,StackTraceElement[]> map) + { + for (Map.Entry<Thread,StackTraceElement[]> entry : map.entrySet()) + { + Throwable t = new Throwable(); + t.setStackTrace(entry.getValue()); + log.warn(t, entry.getKey().toString()); + } + } + +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.java new file mode 100644 index 0000000000..72691f3543 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionStartTest.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.test.unit.client.connection; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +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 org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.test.utils.QpidTestCase; + +public class ConnectionStartTest extends QpidTestCase +{ + + String _broker = "vm://:1"; + + 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) + { + e.printStackTrace(); + 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/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java new file mode 100644 index 0000000000..ed7a0f18b6 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionTest.java @@ -0,0 +1,267 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.AMQConnectionFailureException; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQUnresolvedAddressException; +import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpid.client.AMQAuthenticationException; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.jms.Session; + +import javax.jms.Connection; +import javax.jms.QueueSession; +import javax.jms.TopicSession; +import javax.naming.NamingException; + +public class ConnectionTest extends QpidTestCase +{ + + String _broker_NotRunning = "vm://:2"; + String _broker_BadDNS = "tcp://hg3sgaaw4lgihjs"; + + public String getBroker() + { + try + { + if (getConnectionFactory().getConnectionURL().getBrokerCount() > 0) + { + return getConnectionFactory().getConnectionURL().getBrokerDetails(0).toString(); + } + else + { + fail("No broker details are available."); + } + } + catch (NamingException e) + { + fail(e.getMessage()); + } + + //keep compiler happy + return null; + } + + public void testSimpleConnection() throws Exception + { + AMQConnection conn = null; + try + { + conn = new AMQConnection(getBroker(), "guest", "guest", "fred", "test"); + } + catch (Exception e) + { + fail("Connection to " + getBroker() + " should succeed. Reason: " + e); + } + finally + { + conn.close(); + } + } + + public void testDefaultExchanges() throws Exception + { + AMQConnection conn = null; + try + { + conn = new AMQConnection("amqp://guest:guest@clientid/test?brokerlist='" + + getBroker() + + "?retries='1''&defaultQueueExchange='test.direct'" + + "&defaultTopicExchange='test.topic'" + + "&temporaryQueueExchange='tmp.direct'" + + "&temporaryTopicExchange='tmp.topic'"); + + 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 + { + conn = new AMQConnection("amqp://guest:rubbishpassword@clientid/test?brokerlist='" + getBroker() + "?retries='1''"); + fail("Connection should not be established password is wrong."); + } + catch (AMQConnectionFailureException amqe) + { + assertNotNull("No cause set", amqe.getCause()); + assertEquals("Exception was wrong type", AMQAuthenticationException.class, amqe.getCause().getClass()); + } + 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 + { + conn = new AMQConnection("amqp://guest:guest@clientid/rubbishhost?brokerlist='" + getBroker() + "?retries='0''"); + 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(), "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(), "guest", "guest", + null, "test"); + try + { + assertNotNull(connection.getClientID()); + } + finally + { + connection.close(); + } + connection.close(); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(ConnectionTest.class); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ExceptionListenerTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ExceptionListenerTest.java new file mode 100644 index 0000000000..6f31f7bc65 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ExceptionListenerTest.java @@ -0,0 +1,62 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.client.connection; + +import org.apache.qpid.test.utils.QpidTestCase; + +import org.apache.qpid.util.concurrent.Condition; + +import javax.jms.Connection; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; + +/** + * ExceptionListenerTest + * + */ + +public class ExceptionListenerTest extends QpidTestCase +{ + + public void testBrokerDeath() throws Exception + { + Connection conn = getConnection("guest", "guest"); + + conn.start(); + + final Condition fired = new Condition(); + conn.setExceptionListener(new ExceptionListener() + { + public void onException(JMSException e) + { + fired.set(); + } + }); + + stopBroker(); + + if (!fired.get(3000)) + { + fail("exception listener was not fired"); + } + } + +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/Client.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/Client.java new file mode 100644 index 0000000000..0be11011b4 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/Client.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.test.unit.client.forwardall; + +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.test.utils.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; + +/** + * Declare a private temporary response queue, + * send a message to amq.direct with a well known routing key with the + * private response queue as the reply-to destination + * consume responses. + */ +public class Client implements MessageListener +{ + private static final Logger _logger = LoggerFactory.getLogger(Client.class); + + private final AMQConnection _connection; + private final AMQSession _session; + private final int _expected; + private int _count; + private static QpidTestCase _qct; + + Client(String broker, int expected) throws Exception + { + this(connect(broker), expected); + } + + public static void setQTC(QpidTestCase qtc) + { + _qct = qtc; + } + Client(AMQConnection connection, int expected) throws Exception + { + _connection = connection; + _expected = expected; + _session = (AMQSession) _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); + AMQQueue response = + new AMQQueue(_connection.getDefaultQueueExchangeName(), new AMQShortString("ResponseQueue"), true); + _session.createConsumer(response).setMessageListener(this); + _connection.start(); + // AMQQueue service = new SpecialQueue(_connection, "ServiceQueue"); + AMQQueue service = (AMQQueue) _session.createQueue("ServiceQueue") ; + Message request = _session.createTextMessage("Request!"); + request.setJMSReplyTo(response); + MessageProducer prod = _session.createProducer(service); + prod.send(request); + } + + void shutdownWhenComplete() throws Exception + { + waitUntilComplete(); + _connection.close(); + } + + public synchronized void onMessage(Message response) + { + + _logger.info("Received " + (++_count) + " of " + _expected + " responses."); + if (_count == _expected) + { + + notifyAll(); + } + + } + + synchronized void waitUntilComplete() throws Exception + { + + if (_count < _expected) + { + wait(60000); + } + + if (_count < _expected) + { + throw new Exception("Didn't receive all messages... got " + _count + " expected " + _expected); + } + } + + static AMQConnection connect(String broker) throws Exception + { + //return new AMQConnection(broker, "guest", "guest", "Client" + System.currentTimeMillis(), "test"); + return (AMQConnection) _qct.getConnection("guest", "guest") ; + } + + public static void main(String[] argv) throws Exception + { + final String connectionString; + final int expected; + if (argv.length == 0) + { + connectionString = "localhost:5672"; + expected = 100; + } + else + { + connectionString = argv[0]; + expected = Integer.parseInt(argv[1]); + } + + new Client(connect(connectionString), expected).shutdownWhenComplete(); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/CombinedTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/CombinedTest.java new file mode 100644 index 0000000000..a1001a6f5d --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/CombinedTest.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.client.forwardall; + +import org.apache.qpid.test.utils.QpidTestCase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Runs the Service's and Client parts of the test in the same process + * as the broker + */ +public class CombinedTest extends QpidTestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(CombinedTest.class); + private int run = 0; + + protected void setUp() throws Exception + { + super.setUp(); + Service.setQTC(this); + Client.setQTC(this); + } + + protected void tearDown() throws Exception + { + ServiceCreator.closeAll(); + super.tearDown(); + } + + public void testForwardAll() throws Exception + { + while (run < 10) + { + int services =1; + ServiceCreator.start("vm://:1", services); + + _logger.info("Starting " + ++run + " client..."); + + new Client("vm://:1", services).shutdownWhenComplete(); + + + _logger.info("Completed " + run + " successfully!"); + } + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(CombinedTest.class); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/Service.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/Service.java new file mode 100644 index 0000000000..9cd8b183af --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/Service.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.unit.client.forwardall; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.test.utils.QpidTestCase; + +/** + * Declare a queue and bind it to amq.direct with a 'well known' routing key, + * register a consumer for this queue and send a response to every message received. + */ +public class Service implements MessageListener +{ + private final AMQConnection _connection; + private final AMQSession _session; + + private static QpidTestCase _qct; + + + public static void setQTC(QpidTestCase qtc) + { + _qct = qtc; + } + Service(String broker) throws Exception + { + this(connect(broker)); + } + + Service(AMQConnection connection) throws Exception + { + _connection = connection; + //AMQQueue queue = new SpecialQueue(connection, "ServiceQueue"); + _session = (AMQSession) _connection.createSession(false, AMQSession.NO_ACKNOWLEDGE); + AMQQueue queue = (AMQQueue) _session.createQueue("ServiceQueue") ; + _session.createConsumer(queue).setMessageListener(this); + _connection.start(); + } + + public void onMessage(Message request) + { + try + { + Message response = _session.createTextMessage("Response!"); + Destination replyTo = request.getJMSReplyTo(); + _session.createProducer(replyTo).send(response); + } + catch (Exception e) + { + e.printStackTrace(System.out); + } + } + + public void close() throws JMSException + { + _connection.close(); + } + + static AMQConnection connect(String broker) throws Exception + { + //return new AMQConnection(broker, "guest", "guest", "Client" + System.currentTimeMillis(), "test"); + return (AMQConnection) _qct.getConnection("guest", "guest") ; + } + +// public static void main(String[] argv) throws Exception +// { +// String broker = argv.length == 0? "localhost:5672" : argv[0]; +// new Service(broker); +// } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/ServiceCreator.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/ServiceCreator.java new file mode 100644 index 0000000000..be16f6b7ae --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/ServiceCreator.java @@ -0,0 +1,112 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.forwardall; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.JMSException; + +public class ServiceCreator implements Runnable +{ + private static final Logger _logger = LoggerFactory.getLogger(ServiceCreator.class); + + private static Thread[] threads; + private static ServiceCreator[] _services; + + private final String broker; + private Service service; + + ServiceCreator(String broker) + { + this.broker = broker; + } + + public void run() + { + try + { + service = new Service(broker); + } + catch (Exception e) + { + e.printStackTrace(System.out); + } + } + + public void closeSC() throws JMSException + { + service.close(); + } + + static void closeAll() + { + for (int i = 0; i < _services.length; i++) + { + try + { + _services[i].closeSC(); + } + catch (JMSException e) + { + // ignore + } + } + } + + static void start(String broker, int services) throws InterruptedException + { + threads = new Thread[services]; + _services = new ServiceCreator[services]; + ServiceCreator runner = new ServiceCreator(broker); + // start services + _logger.info("Starting " + services + " services..."); + for (int i = 0; i < services; i++) + { + threads[i] = new Thread(runner); + _services[i] = runner; + threads[i].start(); + } + + for (int i = 0; i < threads.length; i++) + { + threads[i].join(); + } + } + + public static void main(String[] argv) throws Exception + { + final String connectionString; + final int services; + if (argv.length == 0) + { + connectionString = "localhost:5672"; + services = 100; + } + else + { + connectionString = argv[0]; + services = Integer.parseInt(argv[1]); + } + + start(connectionString, services); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/SpecialQueue.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/SpecialQueue.java new file mode 100644 index 0000000000..27371b0397 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/forwardall/SpecialQueue.java @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.unit.client.forwardall; + +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.framing.AMQShortString; + +/** + * Queue that allows several private queues to be registered and bound + * to an exchange with the same routing key. + * + */ +class SpecialQueue extends AMQQueue +{ + private final AMQShortString name; + + SpecialQueue(AMQConnection con, String name) + { + super(con, name, true); + this.name = new AMQShortString(name); + } + + public AMQShortString getRoutingKey() + { + return name; + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/message/ObjectMessageTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/message/ObjectMessageTest.java new file mode 100644 index 0000000000..e67760a6c3 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/message/ObjectMessageTest.java @@ -0,0 +1,335 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.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.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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 QpidTestCase 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, true); + 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) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + 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: <broker>"); + } + + 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/java/systests/src/main/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.java new file mode 100644 index 0000000000..91cb37e455 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/protocol/AMQProtocolSessionTest.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.unit.client.protocol; + +import org.apache.mina.common.IoSession; +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.QpidTestCase; +import org.apache.qpid.test.utils.protocol.TestIoSession; + +public class AMQProtocolSessionTest extends QpidTestCase +{ + private static class AMQProtSession extends AMQProtocolSession + { + + public AMQProtSession(AMQProtocolHandler protocolHandler, IoSession protocolSession, AMQConnection connection) + { + super(protocolHandler,protocolSession,connection); + } + + public TestIoSession getMinaProtocolSession() + { + return (TestIoSession) _minaProtocolSession; + } + + public AMQShortString genQueueName() + { + return generateQueueName(); + } + } + + //private Strings for test values and expected results + private String _brokenAddress = "tcp://myAddress;:";; + private String _generatedAddress; + private String _emptyAddress; + private String _generatedAddress_2; + private String _validAddress; + private String _generatedAddress_3; + private int _port; + private AMQProtSession _testSession; + + protected void setUp() throws Exception + { + super.setUp(); + + //don't care about the values set here apart from the dummy IoSession + _testSession = new AMQProtSession(null,new TestIoSession(), (AMQConnection) getConnection("guest", "guest")); + + //initialise addresses for test and expected results + _port = 123; + _brokenAddress = "tcp://myAddress;:"; + _generatedAddress = "tmp_tcpmyAddress123_1"; + _emptyAddress = ""; + _generatedAddress_2 = "tmp_localhost127.0.0.1123_2"; + _validAddress = "abc"; + _generatedAddress_3 = "tmp_abc123_3"; + } + + public void testGenerateQueueName() + { + AMQShortString testAddress; + + //test address with / and ; chars which generateQueueName should removeKey + _testSession.getMinaProtocolSession().setStringLocalAddress(_brokenAddress); + _testSession.getMinaProtocolSession().setLocalPort(_port); + + testAddress = _testSession.genQueueName(); + assertEquals("Failure when generating a queue exchange from an address with special chars",_generatedAddress,testAddress.toString()); + + //test empty address + _testSession.getMinaProtocolSession().setStringLocalAddress(_emptyAddress); + + testAddress = _testSession.genQueueName(); + assertEquals("Failure when generating a queue exchange from an empty address",_generatedAddress_2,testAddress.toString()); + + //test address with no special chars + _testSession.getMinaProtocolSession().setStringLocalAddress(_validAddress); + + testAddress = _testSession.genQueueName(); + assertEquals("Failure when generating a queue exchange from an address with no special chars",_generatedAddress_3,testAddress.toString()); + + } + + protected void tearDown() throws Exception + { + _testSession = null; + _brokenAddress = null; + _generatedAddress = null; + _emptyAddress = null; + _generatedAddress_2 = null; + _validAddress = null; + _generatedAddress_3 = null; + super.tearDown(); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(AMQProtocolSessionTest.class); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.java new file mode 100644 index 0000000000..7a65b06dd4 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/client/temporaryqueue/TemporaryQueueTest.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.unit.client.temporaryqueue; + +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; +import junit.framework.Assert; + +import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpid.client.AMQQueue; + +import java.util.List; +import java.util.LinkedList; + +public class TemporaryQueueTest extends QpidTestCase +{ + protected void setUp() throws Exception + { + super.setUp(); + } + + protected void tearDown() throws Exception + { + super.tearDown(); + } + + protected Connection createConnection() throws Exception + { + return getConnection("guest", "guest"); + } + + public void testTempoaryQueue() throws Exception + { + Connection conn = createConnection(); + Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); + TemporaryQueue queue = session.createTemporaryQueue(); + assertNotNull(queue); + MessageProducer producer = session.createProducer(queue); + MessageConsumer consumer = session.createConsumer(queue); + conn.start(); + producer.send(session.createTextMessage("hello")); + TextMessage tm = (TextMessage) consumer.receive(2000); + assertNotNull(tm); + assertEquals("hello", tm.getText()); + + try + { + queue.delete(); + fail("Expected JMSException : should not be able to delete while there are active consumers"); + } + catch (JMSException je) + { + ; //pass + } + + consumer.close(); + + try + { + queue.delete(); + } + catch (JMSException je) + { + fail("Unexpected Exception: " + je.getMessage()); + } + + conn.close(); + } + + public void tUniqueness() throws Exception + { + int numProcs = Runtime.getRuntime().availableProcessors(); + final int threadsProc = 5; + + runUniqueness(1, 10); + runUniqueness(numProcs * threadsProc, 10); + runUniqueness(numProcs * threadsProc, 100); + runUniqueness(numProcs * threadsProc, 500); + } + + void runUniqueness(int makers, int queues) throws Exception + { + Connection connection = createConnection(); + + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + List<TempQueueMaker> tqList = new LinkedList<TempQueueMaker>(); + + //Create Makers + for (int m = 0; m < makers; m++) + { + tqList.add(new TempQueueMaker(session, queues)); + } + + + List<Thread> threadList = new LinkedList<Thread>(); + + //Create Makers + for (TempQueueMaker maker : tqList) + { + threadList.add(new Thread(maker)); + } + + //Start threads + for (Thread thread : threadList) + { + thread.start(); + } + + // Join Threads + for (Thread thread : threadList) + { + try + { + thread.join(); + } + catch (InterruptedException e) + { + fail("Couldn't correctly join threads"); + } + } + + + List<AMQQueue> list = new LinkedList<AMQQueue>(); + + // Test values + for (TempQueueMaker maker : tqList) + { + check(maker, list); + } + + Assert.assertEquals("Not enough queues made.", makers * queues, list.size()); + + connection.close(); + } + + private void check(TempQueueMaker tq, List<AMQQueue> list) + { + for (AMQQueue q : tq.getList()) + { + if (list.contains(q)) + { + fail(q + " already exists."); + } + else + { + list.add(q); + } + } + } + + + class TempQueueMaker implements Runnable + { + List<AMQQueue> _queues; + Session _session; + private int _count; + + + TempQueueMaker(Session session, int queues) throws JMSException + { + _queues = new LinkedList<AMQQueue>(); + + _count = queues; + + _session = session; + } + + public void run() + { + int i = 0; + try + { + for (; i < _count; i++) + { + _queues.add((AMQQueue) _session.createTemporaryQueue()); + } + } + catch (JMSException jmse) + { + //stop + } + } + + List<AMQQueue> getList() + { + return _queues; + } + } + + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(TemporaryQueueTest.class); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/close/CloseBeforeAckTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/close/CloseBeforeAckTest.java new file mode 100644 index 0000000000..a61bcca049 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/close/CloseBeforeAckTest.java @@ -0,0 +1,142 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 junit.framework.Assert; + +import org.apache.qpid.test.utils.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.qpid.junit.concurrency.TestRunnable; +import org.apache.qpid.junit.concurrency.ThreadTestCoordinator; + +import javax.jms.Connection; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.Session; + +/** + * This test forces the situation where a session is closed whilst a message consumer is still in its onMessage method. + * Running in AUTO_ACK mode, the close call ought to wait until the onMessage method completes, and the ack is sent + * before closing the connection. + * + * <p><table id="crc"><caption>CRC Card</caption> <tr><th> Responsibilities <th> Collaborations <tr><td> Check that + * closing a connection whilst handling a message, blocks till completion of the handler. </table> + */ +public class CloseBeforeAckTest extends QpidTestCase +{ + private static final Logger log = LoggerFactory.getLogger(CloseBeforeAckTest.class); + + Connection connection; + Session session; + public static final String TEST_QUEUE_NAME = "TestQueue"; + private int TEST_COUNT = 25; + + class TestThread1 extends TestRunnable implements MessageListener + { + public void runWithExceptions() throws Exception + { + // Set this up to listen for message on the test session. + session.createConsumer(session.createQueue(TEST_QUEUE_NAME)).setMessageListener(this); + } + + public void onMessage(Message message) + { + // Give thread 2 permission to close the session. + allow(new int[] { 1 }); + + // Wait until thread 2 has closed the connection, or is blocked waiting for this to complete. + waitFor(new int[] { 1 }, true); + } + } + + TestThread1 testThread1 = new TestThread1(); + + TestRunnable testThread2 = + new TestRunnable() + { + public void runWithExceptions() throws Exception + { + // Send a message to be picked up by thread 1. + session.createProducer(null).send(session.createQueue(TEST_QUEUE_NAME), + session.createTextMessage("Hi there thread 1!")); + + // Wait for thread 1 to pick up the message and give permission to continue. + waitFor(new int[] { 0 }, false); + + // Close the connection. + session.close(); + + // Allow thread 1 to continue to completion, if it is erronously still waiting. + allow(new int[] { 1 }); + } + }; + + public void testCloseBeforeAutoAck_QPID_397() throws Exception + { + // Create a session in auto acknowledge mode. This problem shows up in auto acknowledge if the client acks + // message at the end of the onMessage method, after a close has been sent. + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + ThreadTestCoordinator tt = new ThreadTestCoordinator(2); + + tt.addTestThread(testThread1, 0); + tt.addTestThread(testThread2, 1); + tt.setDeadlockTimeout(500); + tt.run(); + + String errorMessage = tt.joinAndRetrieveMessages(); + + // Print any error messages or exceptions. + log.debug(errorMessage); + + if (!tt.getExceptions().isEmpty()) + { + for (Exception e : tt.getExceptions()) + { + log.debug("Exception thrown during test thread: ", e); + } + } + + Assert.assertTrue(errorMessage, "".equals(errorMessage)); + } + + public void closeBeforeAutoAckManyTimes() throws Exception + { + for (int i = 0; i < TEST_COUNT; i++) + { + testCloseBeforeAutoAck_QPID_397(); + } + } + + protected void setUp() throws Exception + { + super.setUp(); + connection = getConnection("guest", "guest"); + } + + protected void tearDown() throws Exception + { + super.tearDown(); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java new file mode 100644 index 0000000000..579e3350ff --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java @@ -0,0 +1,372 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.AMQException; +import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpid.client.message.AbstractJMSMessage; +import org.apache.qpid.testutil.QpidClientConnection; +import org.apache.qpid.url.URLSyntaxException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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 QpidTestCase +{ + 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 = "vm://:1"; + private boolean testReception = true; + + private long[] receieved = new long[numTestMessages + 1]; + private boolean passed = false; + 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); + // wit 0_10 we can have a delivery tag of 0 + if (conn.isBroker08()) + { + 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.isBroker08()) + { + 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) + { + e.printStackTrace(); + } + } + + 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/java/systests/src/main/java/org/apache/qpid/test/unit/close/TopicPublisherCloseTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/close/TopicPublisherCloseTest.java new file mode 100644 index 0000000000..da7642fb3c --- /dev/null +++ b/java/systests/src/main/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 javax.jms.Session; +import javax.jms.Topic; +import javax.jms.TopicPublisher; +import javax.jms.TopicSession; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.test.utils.QpidTestCase; + +/** + * @author Apache Software Foundation + */ +public class TopicPublisherCloseTest extends QpidTestCase +{ + + 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/java/systests/src/main/java/org/apache/qpid/test/unit/ct/DurableSubscriberTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/ct/DurableSubscriberTest.java new file mode 100644 index 0000000000..34fbd9532f --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/ct/DurableSubscriberTest.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.unit.ct; + +import javax.jms.*; + +import org.apache.qpid.test.utils.QpidTestCase; + +/** + * Crash Recovery tests for durable subscription + * + */ +public class DurableSubscriberTest extends QpidTestCase +{ + 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 (!isBroker08()) + { + 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 + { + shutdownServer(); + } + catch (Exception e) + { + System.out.println("problems shutting down arjuna-ms"); + 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 the received the 5 expected messages + */ + public void testDurSubRestoresMessageSelector() throws Exception + { + if (!isBroker08()) + { + 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 + { + shutdownServer(); + } + catch (Exception e) + { + System.out.println("problems shutting down arjuna-ms"); + 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"); + 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(); + } + } +} + diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSDestinationTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSDestinationTest.java new file mode 100644 index 0000000000..b30e3c1c1c --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSDestinationTest.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.test.unit.message; + +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.test.utils.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; + +/** + * @author Apache Software Foundation + */ +public class JMSDestinationTest extends QpidTestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(JMSDestinationTest.class); + + + protected void setUp() throws Exception + { + super.setUp(); + } + + protected void tearDown() throws Exception + { + super.tearDown(); + } + + public void testJMSDestination() 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); + + Connection con2 = (AMQConnection) getConnection("guest", "guest"); + Session producerSession = con2.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageProducer producer = producerSession.createProducer(queue); + + TextMessage sentMsg = producerSession.createTextMessage("hello"); + assertNull(sentMsg.getJMSDestination()); + + producer.send(sentMsg); + + assertEquals(sentMsg.getJMSDestination(), queue); + + con2.close(); + + con.start(); + + TextMessage rm = (TextMessage) consumer.receive(); + assertNotNull(rm); + + assertEquals(rm.getJMSDestination(), queue); + con.close(); + } + +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java new file mode 100644 index 0000000000..5bf99e719e --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/message/JMSPropertiesTest.java @@ -0,0 +1,135 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.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.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Destination; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.ObjectMessage; +import javax.jms.Queue; +import javax.jms.Session; +import java.util.Enumeration; + +/** + * @author Apache Software Foundation + */ +public class JMSPropertiesTest extends QpidTestCase +{ + + 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 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(); + 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); + + // 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:")); + + //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); + + con.close(); + } + +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/message/StreamMessageTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/message/StreamMessageTest.java new file mode 100644 index 0000000000..3027da00c7 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/message/StreamMessageTest.java @@ -0,0 +1,160 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.client.AMQConnection; +import org.apache.qpid.client.AMQHeadersExchange; +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.framing.FieldTable; +import org.apache.qpid.url.AMQBindingURL; +import org.apache.qpid.url.BindingURL; +import org.apache.qpid.test.utils.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +import javax.jms.JMSException; +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; + +/** + * @author Apache Software Foundation + */ +public class StreamMessageTest extends QpidTestCase +{ + + private static final Logger _logger = LoggerFactory.getLogger(StreamMessageTest.class); + + public String _connectionString = "vm://:1"; + + protected void setUp() throws Exception + { + super.setUp(); + } + + protected void tearDown() throws Exception + { + super.tearDown(); + } + + public void testStreamMessageEOF() throws Exception + { + Connection 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("F1000", "1"); + MessageConsumer consumer = + consumerSession.createConsumer(queue, AMQSession.DEFAULT_PREFETCH_LOW_MARK, + AMQSession.DEFAULT_PREFETCH_HIGH_MARK, false, false, (String) null, ft); + + // 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(); + + msg2.readByte(); + try + { + msg2.readByte(); + } + catch (Exception e) + { + assertTrue("Expected MessageEOFException: " + e, e instanceof MessageEOFException); + } + con.close(); + con2.close(); + } + + public void testModifyReceivedMessageExpandsBuffer() throws Exception + { + 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) + { + StreamMessage sm = (StreamMessage) message; + try + { + sm.clearBody(); + sm.writeString("dfgjshfslfjshflsjfdlsjfhdsljkfhdsljkfhsd"); + } + catch (JMSException e) + { + _logger.error("Error when writing large string to received msg: " + e, e); + fail("Error when writing large string to received msg" + e); + } + } + }); + + Connection con2 = (AMQConnection) getConnection("guest", "guest"); + AMQSession producerSession = (AMQSession) con2.createSession(false, Session.CLIENT_ACKNOWLEDGE); + MessageProducer mandatoryProducer = producerSession.createProducer(queue); + con.start(); + StreamMessage sm = producerSession.createStreamMessage(); + sm.writeInt(42); + mandatoryProducer.send(sm); + Thread.sleep(2000); + con.close(); + con2.close(); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java new file mode 100644 index 0000000000..4897f5fa15 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java @@ -0,0 +1,347 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.QpidTestCase; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQTopic; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.Connection; +import javax.jms.InvalidDestinationException; +import javax.jms.InvalidSelectorException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.TopicSubscriber; + +/** + * @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 QpidTestCase +{ + private static final Logger _logger = LoggerFactory.getLogger(DurableSubscriptionTest.class); + + protected void setUp() throws Exception + { + super.setUp(); + } + + protected void tearDown() throws Exception + { + super.tearDown(); + } + + public void testUnsubscribe() throws Exception + { + AMQConnection con = (AMQConnection) getConnection("guest", "guest"); + 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, "MySubscription"); + + _logger.info("Starting connection"); + con.start(); + + _logger.info("Producer sending message A"); + producer.send(session1.createTextMessage("A")); + + Message msg; + _logger.info("Receive message on consumer 1:expecting A"); + msg = consumer1.receive(); + assertEquals("A", ((TextMessage) msg).getText()); + _logger.info("Receive message on consumer 1 :expecting null"); + msg = consumer1.receive(1000); + assertEquals(null, msg); + + _logger.info("Receive message on consumer 1:expecting A"); + msg = consumer2.receive(); + assertEquals("A", ((TextMessage) msg).getText()); + msg = consumer2.receive(1000); + _logger.info("Receive message on consumer 1 :expecting null"); + assertEquals(null, msg); + + _logger.info("Unsubscribe session2/consumer2"); + session2.unsubscribe("MySubscription"); + + _logger.info("Producer sending message B"); + producer.send(session1.createTextMessage("B")); + + _logger.info("Receive message on consumer 1 :expecting B"); + msg = consumer1.receive(); + assertEquals("B", ((TextMessage) msg).getText()); + _logger.info("Receive message on consumer 1 :expecting null"); + msg = consumer1.receive(1000); + assertEquals(null, msg); + + _logger.info("Receive message on consumer 2 :expecting null"); + msg = consumer2.receive(1000); + assertEquals(null, msg); + + _logger.info("Close connection"); + con.close(); + } + + public void testDurabilityAUTOACK() throws Exception + { + durabilityImpl(Session.AUTO_ACKNOWLEDGE); + } + + public void testDurabilityNOACKSessionPerConnection() throws Exception + { + durabilityImplSessionPerConnection(AMQSession.NO_ACKNOWLEDGE); + } + + public void testDurabilityAUTOACKSessionPerConnection() throws Exception + { + durabilityImplSessionPerConnection(Session.AUTO_ACKNOWLEDGE); + } + + private void durabilityImpl(int ackMode) throws Exception + { + AMQConnection con = (AMQConnection) getConnection("guest", "guest"); + AMQTopic topic = new AMQTopic(con, "MyTopic"); + Session session1 = con.createSession(false, ackMode); + MessageConsumer consumer1 = session1.createConsumer(topic); + + Session sessionProd = con.createSession(false, AMQSession.NO_ACKNOWLEDGE); + MessageProducer producer = sessionProd.createProducer(topic); + + Session session2 = con.createSession(false, AMQSession.NO_ACKNOWLEDGE); + TopicSubscriber consumer2 = session2.createDurableSubscriber(topic, "MySubscription"); + + con.start(); + + producer.send(session1.createTextMessage("A")); + + Message msg; + msg = consumer1.receive(); + assertEquals("A", ((TextMessage) msg).getText()); + msg = consumer1.receive(1000); + assertEquals(null, msg); + + msg = consumer2.receive(); + assertEquals("A", ((TextMessage) msg).getText()); + msg = consumer2.receive(1000); + assertEquals(null, msg); + + consumer2.close(); + + producer.send(session1.createTextMessage("B")); + + _logger.info("Receive message on consumer 1 :expecting B"); + msg = consumer1.receive(500); + assertNotNull("Consumer 1 should get message 'B'.", msg); + assertEquals("Incorrect Message recevied 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); + + Session session3 = con.createSession(false, ackMode); + MessageConsumer consumer3 = session3.createDurableSubscriber(topic, "MySubscription"); + + _logger.info("Receive message on consumer 3 :expecting B"); + msg = consumer3.receive(500); + assertNotNull("Consumer 3 should get message 'B'.", msg); + assertEquals("Incorrect Message recevied on consumer4.", "B", ((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(); + + con.close(); + } + + private void durabilityImplSessionPerConnection(int ackMode) throws Exception + { + Message msg; + // Create producer. + AMQConnection con0 = (AMQConnection) getConnection("guest", "guest"); + con0.start(); + Session session0 = con0.createSession(false, ackMode); + + AMQTopic topic = new AMQTopic(con0, "MyTopic"); + + Session sessionProd = con0.createSession(false, ackMode); + MessageProducer producer = sessionProd.createProducer(topic); + + // Create consumer 1. + AMQConnection con1 = (AMQConnection) getConnection("guest", "guest"); + con1.start(); + Session session1 = con1.createSession(false, ackMode); + + MessageConsumer consumer1 = session0.createConsumer(topic); + + // Create consumer 2. + AMQConnection con2 = (AMQConnection) getConnection("guest", "guest"); + con2.start(); + Session session2 = con2.createSession(false, ackMode); + + TopicSubscriber consumer2 = session2.createDurableSubscriber(topic, "MySubscription"); + + // Send message and check that both consumers get it and only it. + producer.send(session0.createTextMessage("A")); + + msg = consumer1.receive(500); + 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(); + assertNotNull(msg); + assertEquals("Consumer 2 should also received the first msg.", "A", ((TextMessage) msg).getText()); + msg = consumer2.receive(500); + assertNull("There should be no more messages for consumption on consumer2.", msg); + + // Detach the durable subscriber. + consumer2.close(); + session2.close(); + con2.close(); + + // Send message and receive on open consumer. + producer.send(session0.createTextMessage("B")); + + _logger.info("Receive message on consumer 1 :expecting B"); + msg = consumer1.receive(1000); + assertEquals("B", ((TextMessage) msg).getText()); + _logger.info("Receive message on consumer 1 :expecting null"); + msg = consumer1.receive(1000); + assertEquals(null, msg); + + // Re-attach a new consumer to the durable subscription, and check that it gets the message that it missed. + AMQConnection con3 = (AMQConnection) getConnection("guest", "guest"); + con3.start(); + Session session3 = con3.createSession(false, ackMode); + + TopicSubscriber consumer3 = session3.createDurableSubscriber(topic, "MySubscription"); + + _logger.info("Receive message on consumer 3 :expecting B"); + msg = consumer3.receive(500); + assertNotNull("Consumer 3 should get message 'B'.", msg); + assertEquals("Incorrect Message recevied on consumer4.", "B", ((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(); + + 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 (InvalidSelectorException e) + { + // This was expected + } + + TopicSubscriber liveSubscriber = session.createDurableSubscriber(topic, "testDurableWithInvalidSelectorSub"); + assertNotNull("Subscriber should have been created", liveSubscriber); + + producer.send(session.createTextMessage("testDurableWithInvalidSelector2")); + + Message msg = liveSubscriber.receive(); + assertNotNull ("Message should have been received", msg); + assertEquals ("testDurableWithInvalidSelector2", ((TextMessage) msg).getText()); + assertNull("Should not receive subsequent message", liveSubscriber.receive(200)); + } + + /*** + * 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(); + assertNotNull ("Message should have been received", msg); + assertEquals ("testDurableWithInvalidSelector2", ((TextMessage) msg).getText()); + assertNull("Should not receive subsequent message", liveSubscriber.receive(200)); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(DurableSubscriptionTest.class); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicPublisherTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicPublisherTest.java new file mode 100644 index 0000000000..6d115d1a2b --- /dev/null +++ b/java/systests/src/main/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 javax.jms.MessageConsumer; +import javax.jms.TextMessage; +import javax.jms.TopicPublisher; +import javax.jms.TopicSession; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.test.utils.QpidTestCase; + +/** + * @author Apache Software Foundation + */ +public class TopicPublisherTest extends QpidTestCase +{ + 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/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java new file mode 100644 index 0000000000..ee970759ad --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/topic/TopicSessionTest.java @@ -0,0 +1,370 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.InvalidDestinationException; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.Session; +import javax.jms.TemporaryTopic; +import javax.jms.TextMessage; +import javax.jms.TopicPublisher; +import javax.jms.TopicSession; +import javax.jms.TopicSubscriber; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.client.AMQTopic; +import org.apache.qpid.test.utils.QpidTestCase; + + +/** @author Apache Software Foundation */ +public class TopicSessionTest extends QpidTestCase +{ + + protected void setUp() throws Exception + { + super.setUp(); + } + + protected void tearDown() throws Exception + { + super.tearDown(); + } + + + public void testTopicSubscriptionUnsubscription() throws Exception + { + + AMQConnection con = (AMQConnection) getConnection("guest", "guest"); + AMQTopic topic = new AMQTopic(con.getDefaultTopicExchangeName(), "MyTopic"); + TopicSession session1 = con.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE); + TopicSubscriber sub = session1.createDurableSubscriber(topic, "subscription0"); + TopicPublisher publisher = session1.createPublisher(topic); + + con.start(); + + TextMessage tm = session1.createTextMessage("Hello"); + publisher.publish(tm); + + tm = (TextMessage) sub.receive(2000); + assertNotNull(tm); + + 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(false, AMQSession.AUTO_ACKNOWLEDGE); + TopicSubscriber sub = session1.createDurableSubscriber(topic, "subscription0"); + TopicPublisher publisher = session1.createPublisher(null); + + con.start(); + + publisher.publish(topic, session1.createTextMessage("hello")); + TextMessage m = (TextMessage) sub.receive(2000); + assertNotNull(m); + + if (shutdown) + { + session1.close(); + con.close(); + con = (AMQConnection) getConnection("guest", "guest"); + con.start(); + session1 = con.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE); + publisher = session1.createPublisher(null); + } + TopicSubscriber sub2 = session1.createDurableSubscriber(topic2, "subscription0"); + publisher.publish(topic, session1.createTextMessage("hello")); + if (!shutdown) + { + m = (TextMessage) sub.receive(2000); + assertNull(m); + } + publisher.publish(topic2, session1.createTextMessage("goodbye")); + m = (TextMessage) sub2.receive(2000); + assertNotNull(m); + assertEquals("goodbye", m.getText()); + con.close(); + } + + public void testUnsubscriptionAfterConnectionClose() throws Exception + { + AMQConnection con1 = (AMQConnection) getConnection("guest", "guest"); + AMQTopic topic = new AMQTopic(con1, "MyTopic3"); + + TopicSession session1 = con1.createTopicSession(false, AMQSession.AUTO_ACKNOWLEDGE); + TopicPublisher publisher = session1.createPublisher(topic); + + AMQConnection con2 = (AMQConnection) getConnection("guest", "guest"); + TopicSession session2 = con2.createTopicSession(false, AMQSession.AUTO_ACKNOWLEDGE); + TopicSubscriber sub = session2.createDurableSubscriber(topic, "subscription0"); + + con2.start(); + + publisher.publish(session1.createTextMessage("Hello")); + TextMessage tm = (TextMessage) sub.receive(2000); + assertNotNull(tm); + con2.close(); + publisher.publish(session1.createTextMessage("Hello2")); + con2 = (AMQConnection) getConnection("guest", "guest"); + session2 = con2.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE); + sub = session2.createDurableSubscriber(topic, "subscription0"); + con2.start(); + tm = (TextMessage) sub.receive(2000); + assertNotNull(tm); + assertEquals("Hello2", tm.getText()); + 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(false, AMQSession.NO_ACKNOWLEDGE); + TopicPublisher publisher = session1.createPublisher(topic); + MessageConsumer consumer1 = session1.createConsumer(topic); + con.start(); + TextMessage tm = session1.createTextMessage("Hello"); + publisher.publish(tm); + 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); + tm = (TextMessage) consumer1.receive(10000L); + assertNotNull(tm); + msgText = tm.getText(); + assertNull(msgText); + tm.clearBody(); + tm.setText("Now we are not null"); + publisher.publish(tm); + tm = (TextMessage) consumer1.receive(2000); + assertNotNull(tm); + 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); + tm = (TextMessage) consumer1.receive(2000); + assertNotNull(tm); + assertEquals("Empty string not returned", "", msgText); + con.close(); + } + + public void testSendingSameMessage() throws Exception + { + AMQConnection conn = (AMQConnection) getConnection("guest", "guest"); + TopicSession session = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + TemporaryTopic topic = session.createTemporaryTopic(); + assertNotNull(topic); + TopicPublisher producer = session.createPublisher(topic); + MessageConsumer consumer = session.createConsumer(topic); + conn.start(); + TextMessage sentMessage = session.createTextMessage("Test Message"); + producer.send(sentMessage); + TextMessage receivedMessage = (TextMessage) consumer.receive(2000); + assertNotNull(receivedMessage); + assertEquals(sentMessage.getText(), receivedMessage.getText()); + producer.send(sentMessage); + receivedMessage = (TextMessage) consumer.receive(2000); + assertNotNull(receivedMessage); + assertEquals(sentMessage.getText(), receivedMessage.getText()); + + conn.close(); + + } + + public void testTemporaryTopic() throws Exception + { + AMQConnection conn = (AMQConnection) getConnection("guest", "guest"); + TopicSession session = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + TemporaryTopic topic = session.createTemporaryTopic(); + assertNotNull(topic); + TopicPublisher producer = session.createPublisher(topic); + MessageConsumer consumer = session.createConsumer(topic); + conn.start(); + producer.send(session.createTextMessage("hello")); + TextMessage tm = (TextMessage) consumer.receive(2000); + assertNotNull(tm); + assertEquals("hello", tm.getText()); + + try + { + topic.delete(); + fail("Expected JMSException : should not be able to delete while there are active consumers"); + } + catch (JMSException je) + { + ; //pass + } + + consumer.close(); + + try + { + topic.delete(); + } + catch (JMSException je) + { + fail("Unexpected Exception: " + je.getMessage()); + } + + TopicSession session2 = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); + try + { + session2.createConsumer(topic); + fail("Expected a JMSException when subscribing to a temporary topic created on adifferent session"); + } + catch (JMSException je) + { + ; // pass + } + + + conn.close(); + } + + + public void testNoLocal() throws Exception + { + + AMQConnection con = (AMQConnection) getConnection("guest", "guest"); + + AMQTopic topic = new AMQTopic(con, "testNoLocal"); + + TopicSession session1 = con.createTopicSession(false, AMQSession.NO_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")); + + //test normal subscriber gets message + m = (TextMessage) normal.receive(1000); + assertNotNull(m); + + //test selector subscriber doesn't message + m = (TextMessage) select.receive(1000); + assertNull(m); + + //test nolocal subscriber doesn't message + m = (TextMessage) noLocal.receive(1000); + if (m != null) + { + System.out.println("Message:" + m.getText()); + } + assertNull(m); + + //send message to all consumers + message = session1.createTextMessage("hello2"); + message.setStringProperty("Selector", "select"); + + publisher.publish(message); + + //test normal subscriber gets message + m = (TextMessage) normal.receive(1000); + assertNotNull(m); + + //test selector subscriber does get message + m = (TextMessage) select.receive(1000); + assertNotNull(m); + + //test nolocal subscriber doesn't message + m = (TextMessage) noLocal.receive(100); + assertNull(m); + + AMQConnection con2 = (AMQConnection) getConnection("guest", "guest", "foo"); + TopicSession session2 = con2.createTopicSession(false, AMQSession.NO_ACKNOWLEDGE); + TopicPublisher publisher2 = session2.createPublisher(topic); + + + message = session2.createTextMessage("hello2"); + message.setStringProperty("Selector", "select"); + + publisher2.publish(message); + + //test normal subscriber gets message + m = (TextMessage) normal.receive(1000); + assertNotNull(m); + + //test selector subscriber does get message + m = (TextMessage) select.receive(1000); + assertNotNull(m); + + //test nolocal subscriber does message + m = (TextMessage) noLocal.receive(100); + assertNotNull(m); + + + con.close(); + con2.close(); + } + + public static junit.framework.Test suite() + { + return new junit.framework.TestSuite(TopicSessionTest.class); + } +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java new file mode 100644 index 0000000000..b2797e2535 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java @@ -0,0 +1,506 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.QpidTestCase; +import org.apache.qpid.client.AMQConnection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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; + +/** + * This class tests a number of commits and roll back scenarios + * + * Assumptions; - Assumes empty Queue + */ +public class CommitRollbackTest extends QpidTestCase +{ + protected AMQConnection conn; + protected String queue = "direct://amq.direct//Qpid.Client.Transacted.CommitRollback.queue"; + protected static int testMethod = 0; + protected String payload = "xyzzy"; + private Session _session; + private MessageProducer _publisher; + private Session _pubSession; + private MessageConsumer _consumer; + Queue _jmsQueue; + + private static final Logger _logger = LoggerFactory.getLogger(CommitRollbackTest.class); + private boolean _gotone = false; + private boolean _gottwo = false; + private boolean _gottwoRedelivered = false; + + protected void setUp() throws Exception + { + super.setUp(); + testMethod++; + queue += testMethod; + newConnection(); + } + + private void newConnection() throws Exception + { + conn = (AMQConnection) getConnection("guest", "guest"); + + _session = conn.createSession(true, Session.CLIENT_ACKNOWLEDGE); + + _jmsQueue = _session.createQueue(queue); + _consumer = _session.createConsumer(_jmsQueue); + + _pubSession = conn.createSession(true, Session.CLIENT_ACKNOWLEDGE); + + _publisher = _pubSession.createProducer(_pubSession.createQueue(queue)); + + conn.start(); + } + + protected void tearDown() throws Exception + { + conn.close(); + super.tearDown(); + } + + /** + * PUT a text message, disconnect before commit, confirm it is gone. + * + * @throws Exception On error + */ + public void testPutThenDisconnect() throws Exception + { + 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(1000); + + // 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, disconnect before commit, confirm it is gone. + * + * @throws Exception On error + */ + public void testPutThenCloseDisconnect() throws Exception + { + 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("closing publisher without commit"); + _publisher.close(); + + _logger.info("reconnecting without commit"); + conn.close(); + + newConnection(); + + _logger.info("receiving result"); + Message result = _consumer.receive(1000); + + // 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 + { + 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(1000); + + 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 + { + 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(1000); + assertNotNull("retrieved message is null", msg); + + _logger.info("closing connection"); + conn.close(); + + newConnection(); + + _logger.info("receiving result"); + Message result = _consumer.receive(1000); + + _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 + { + 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(1000); + 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(1000); + + _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 + { + 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(1000); + + 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(1000); + + _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 + { + 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(1000); + + 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(1000); + + _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()); + } + + /** + * Test that rolling back a session purges the dispatcher queue, and the messages arrive in the correct order + * + * @throws Exception On error + */ + public void testSend2ThenRollback() throws Exception + { + int run = 0; + while (run < 10) + { + run++; + _logger.info("Run:" + run); + 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"); + assertEquals("1", ((TextMessage) _consumer.receive(1000)).getText()); + + _logger.info("rolling back"); + _session.rollback(); + + _logger.info("receiving result"); + Message result = _consumer.receive(1000); + + assertNotNull("test message was consumed and rolled back, but is gone", result); + + // Message Order is: + + // Send 1 , 2 + // Retrieve 1 and then rollback + // Receieve 1 (redelivered) , 2 (may or may not be redelivered??) + + verifyMessages(result); + + // Occassionally get message 2 first! +// assertEquals("Should get message one first", "1", ((TextMessage) result).getText()); +// assertTrue("Message is not marked as redelivered", result.getJMSRedelivered()); +// +// result = _consumer.receive(1000); +// assertEquals("Second message should be message 2", "2", ((TextMessage) result).getText()); +// assertTrue("Message is not marked as redelivered", result.getJMSRedelivered()); +// +// result = _consumer.receive(1000); +// assertNull("There should be no more messages", result); + + _session.commit(); + } + } + + private void verifyMessages(Message result) throws JMSException + { + + if (result == null) + { + assertTrue("Didn't receive redelivered message one", _gotone); + assertTrue("Didn't receive message two at all", _gottwo | _gottwoRedelivered); + _gotone = false; + _gottwo = false; + _gottwoRedelivered = false; + return; + } + + if (((TextMessage) result).getText().equals("1")) + { + _logger.info("Got 1 redelivered"); + assertTrue("Message is not marked as redelivered", result.getJMSRedelivered()); + assertFalse("Already received message one", _gotone); + _gotone = true; + + } + else + { + assertEquals("2", ((TextMessage) result).getText()); + + if (result.getJMSRedelivered()) + { + _logger.info("Got 2 redelivered, message was prefetched"); + assertFalse("Already received message redelivered two", _gottwoRedelivered); + + _gottwoRedelivered = true; + } + else + { + _logger.warn("Got 2, message prefetched wasn't cleared or messages was in transit when rollback occured"); + assertFalse("Already received message two", _gottwo); + assertFalse("Already received message redelivered two", _gottwoRedelivered); + _gottwo = true; + } + } + + verifyMessages(_consumer.receive(1000)); + } + + /** + * This test sends two messages receives on 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 + { + 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(5000); + + assertNotNull("Message received should not be null", result); + assertEquals("1", ((TextMessage) result).getText()); + assertTrue("Messasge 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(5000); + 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 recieved again"); + } + + result = _consumer.receive(1000); + assertNull("test message should be null:" + result, result); + + _session.commit(); + } + + public void testPutThenRollbackThenGet() throws Exception + { + 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(100)); + + _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); + + _logger.info("rolling back"); + _pubSession.rollback(); + + _logger.info("receiving result"); + Message result = _consumer.receive(1000); + assertNull("test message was put and rolled back, but is still present", result); + + _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); + + _pubSession.commit(); + + assertNotNull(_consumer.receive(100)); + + _session.commit(); + } + +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java new file mode 100644 index 0000000000..1eec6dd17c --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java @@ -0,0 +1,348 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.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.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.TextMessage; + +public class TransactedTest extends QpidTestCase +{ + 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) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + } + finally + { + super.tearDown(); + } + } + + public void testCommit() throws Exception + { + try + { +// add some messages + _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)); + } + catch (Throwable e) + { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + public void testRollback() throws Exception + { + try + { +// 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), 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)); + } + catch (Throwable e) + { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + public void testResendsMsgsAfterSessionClose() throws Exception + { + try + { + 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(); + } + catch (Throwable e) + { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + 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/java/systests/src/main/java/org/apache/qpid/test/unit/xa/AbstractXATestCase.java b/java/systests/src/main/java/org/apache/qpid/test/unit/xa/AbstractXATestCase.java new file mode 100644 index 0000000000..42811ed390 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/xa/AbstractXATestCase.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.test.unit.xa; + +import org.apache.qpidity.dtx.XidImpl; +import org.apache.qpid.test.utils.QpidTestCase; + +import javax.transaction.xa.Xid; +import javax.transaction.xa.XAResource; +import javax.jms.*; +import java.util.Random; + +/** + * + * + */ +public abstract class AbstractXATestCase extends QpidTestCase +{ + 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) + { + e.printStackTrace(); + 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/java/systests/src/main/java/org/apache/qpid/test/unit/xa/FaultTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/xa/FaultTest.java new file mode 100644 index 0000000000..0adf39980b --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/xa/FaultTest.java @@ -0,0 +1,364 @@ +package org.apache.qpid.test.unit.xa; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jms.*; +import javax.transaction.xa.Xid; +import javax.transaction.xa.XAResource; +import javax.transaction.xa.XAException; + +import junit.framework.TestSuite; + + +public class FaultTest extends AbstractXATestCase +{ + /* this clas logger */ + 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(); + _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(), 0); + } + + /** + * Strategy: + * Check that a transaction timeout as expected + * - set timeout to 10ms + * - sleep 1000ms + * - call end and check that the expected exception is thrown + */ + public void testTransactionTimeout() throws Exception + { + Xid xid = getNewXid(); + try + { + _xaResource.start(xid, XAResource.TMNOFLAGS); + assertEquals("Wrong timeout", _xaResource.getTransactionTimeout(), 0); + _xaResource.setTransactionTimeout(10); + Thread.sleep(1000); + _xaResource.end(xid, XAResource.TMSUCCESS); + } + catch (XAException e) + { + assertEquals("Wrong error code: ", XAException.XA_RBTIMEOUT, e.errorCode); + } + } + +} diff --git a/java/systests/src/main/java/org/apache/qpid/test/unit/xa/QueueTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/xa/QueueTest.java new file mode 100644 index 0000000000..740f9e72ad --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/xa/QueueTest.java @@ -0,0 +1,657 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 javax.jms.*; +import javax.transaction.xa.XAResource; +import javax.transaction.xa.Xid; +import javax.transaction.xa.XAException; + +import junit.framework.TestSuite; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class QueueTest extends AbstractXATestCase +{ + /* this clas logger */ + 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(); + _nonXASession = _queueConnection.createQueueSession(true, Session.AUTO_ACKNOWLEDGE); + } + catch (JMSException 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) + { + e.printStackTrace(); + 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"); + shutdownServer(); + 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)) + { + System.out.println("commit xid1 "); + try + { + _xaResource.commit(anInDoubt, false); + } + catch (Exception e) + { + System.out.println("PB when aborted xid1"); + } + } + else + { + fail("did not receive right xid "); + } + } + } + catch (XAException e) + { + e.printStackTrace(); + 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"); + shutdownServer(); + 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) + { + System.out.println("PB when aborted xid1"); + } + } + else if (anInDoubt.equals(xid2)) + { + _logger.debug("commit xid2 "); + try + { + _xaResource.commit(anInDoubt, false); + } + catch (Exception e) + { + System.out.println("PB when commiting xid2"); + } + } + } + } + catch (XAException e) + { + e.printStackTrace(); + 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! "); + } + } + 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/java/systests/src/main/java/org/apache/qpid/test/unit/xa/TopicTest.java b/java/systests/src/main/java/org/apache/qpid/test/unit/xa/TopicTest.java new file mode 100644 index 0000000000..027257d761 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/unit/xa/TopicTest.java @@ -0,0 +1,1711 @@ +/* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 javax.jms.*; +import javax.transaction.xa.XAResource; +import javax.transaction.xa.Xid; +import javax.transaction.xa.XAException; + +import junit.framework.TestSuite; + +import java.util.concurrent.atomic.AtomicBoolean; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * + */ +public class TopicTest extends AbstractXATestCase +{ + /* this clas 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.getStackTrace()); + } + } + super.tearDown(); + } + + /** + * Initialize standard actors + */ + public void init() + { + if (!isBroker08()) + { + // 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) + { + e.printStackTrace(); //To change body of catch statement use Options | File Templates. + } + 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) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + fail("Exception when working with xid4: " + e.getMessage()); + } + } + catch (Exception e) + { + e.printStackTrace(); + fail("problem when creating dur sub: " + e.getMessage()); + } + finally + { + try + { + _session.unsubscribe(durSubName); + } + catch (JMSException e) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + 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); + _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) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + fail("Exception when working with xid6: " + e.getMessage()); + } + } + catch (Exception e) + { + e.printStackTrace(); + fail("problem when creating dur sub: " + e.getMessage()); + } + finally + { + try + { + _session.unsubscribe(durSubName); + } + catch (JMSException e) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + fail("Exception thrown when consumming 6 first messages: " + e.getMessage()); + } + /////// stop the broker now !! + try + { + shutdownServer(); + 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) + { + e.printStackTrace(); + 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 + message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received! expected: " + 3); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != 3) + { + fail("wrong sequence number: " + message + .getLongProperty(_sequenceNumberPropertyName) + " 3 was expected"); + } + message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received! expected: " + 4); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != 4) + { + fail("wrong sequence number: " + message + .getLongProperty(_sequenceNumberPropertyName) + " 4 was expected"); + } + message = (TextMessage) xaDurSub.receive(1000); + if (message == null) + { + fail("no message received! expected: " + 7); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != 7) + { + fail("wrong sequence number: " + message + .getLongProperty(_sequenceNumberPropertyName) + " 7 was expected"); + } + } + catch (Exception e) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + fail("XAException thrown when committing tx3 or aborting tx1: " + e.getMessage()); + } + + try + { + // consume messages 1 - 4 + //----- start xid1 + _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); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != i) + { + fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); + } + } + _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 (message.getLongProperty(_sequenceNumberPropertyName) != i) + { + fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); + } + } + _xaResource.end(xid5, XAResource.TMSUSPEND); + // abort tx4 + _xaResource.prepare(xid4); + _xaResource.rollback(xid4); + // 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 (message.getLongProperty(_sequenceNumberPropertyName) != i) + { + fail("wrong sequence number: " + message.getLongProperty(_sequenceNumberPropertyName)); + } + } + _xaResource.end(xid5, XAResource.TMSUSPEND); + // commit tx5 + _xaResource.prepare(xid5); + _xaResource.commit(xid5, false); + } + catch (Exception e) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + fail("Exception when working with xid6: " + e.getMessage()); + } + } + catch (Exception e) + { + e.printStackTrace(); + fail("problem when creating dur sub: " + e.getMessage()); + } + finally + { + try + { + _session.unsubscribe(durSubName); + } + catch (JMSException e) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + fail("Exception when working with xid2: " + e.getMessage()); + } + + /////// stop the server now !! + try + { + shutdownServer(); + 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)) + { + System.out.println("aborting xid2 "); + try + { + _xaResource.rollback(anInDoubt); + } + catch (Exception e) + { + e.printStackTrace(); + fail("exception when aborting xid2 "); + } + } + else + { + System.out.println("XID2 is not in doubt "); + } + } + } + catch (XAException e) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + fail("Exception when working with xid4: " + e.getMessage()); + } + } + catch (Exception e) + { + e.printStackTrace(); + fail("problem when creating dur sub: " + e.getMessage()); + } + finally + { + try + { + _session.unsubscribe(durSubName); + } + catch (JMSException e) + { + e.printStackTrace(); + 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 + { + shutdownServer(); + 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.debug("PB when aborted xid1"); + e.printStackTrace(); + fail("exception when committing xid1 "); + } + } + else + { + _logger.debug("XID1 is not in doubt "); + } + } + } + catch (XAException e) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + fail("Exception thrown when testin that queue test is empty: " + e.getMessage()); + } + } + catch (JMSException e) + { + e.printStackTrace(); + 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) + { + System.out.println("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) + { + System.out.println("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) + { + System.out.println("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) + { + System.out.println("no message received "); + } + else if (message.getLongProperty(_sequenceNumberPropertyName) != i) + { + System.out.println("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); + } + catch (Exception e) + { + e.printStackTrace(); + 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) + { + e.printStackTrace(); + TopicTest.failure(); + _lock.set(false); + synchronized (_lock) + { + _lock.notifyAll(); + } + } + if (seq != _counter) + { + System.out.println("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/java/systests/src/main/java/org/apache/qpid/test/utils/ConversationFactory.java b/java/systests/src/main/java/org/apache/qpid/test/utils/ConversationFactory.java new file mode 100644 index 0000000000..f1a9a5d309 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/utils/ConversationFactory.java @@ -0,0 +1,480 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 org.apache.qpid.util.ReflectionUtils; + +import javax.jms.*; + +import java.util.*; +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. + * + * <p/>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): + * + * <p/><pre> + * 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(); + * } + * } + * } + * </pre> + * + * <p/>Conversation correlation id's are generated on a per thread basis. + * + * <p/>The same controlSession is shared amongst all conversations. Calls to send are therefore synchronized because JMS + * sessions are not multi-threaded. + * + * <p/><table id="crc"><caption>CRC Card</caption> + * <tr><th> Responsibilities <th> Collaborations + * <tr><td> Associate messages to an ongoing conversation using correlation ids. + * <tr><td> Auto manage sessions for conversations. + * <tr><td> Store messages not in a conversation in dead letter box. + * </table> + */ +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<Long, BlockingQueue<Message>> idsToQueues = new HashMap<Long, BlockingQueue<Message>>(); + + /** 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. */ + MessageConsumer consumer; + + /** The message producer for outgoing messages. */ + MessageProducer producer; + + /** The well-known or temporary destination to receive replies on. */ + Destination receiveDestination; + + /** Holds the queue implementation class for the reply queue. */ + Class<? extends BlockingQueue> queueClass; + + /** Used to hold any replies that are received outside of the context of a conversation. */ + BlockingQueue<Message> deadLetterBox = new LinkedBlockingQueue<Message>(); + + /* Used to hold conversation state on a per thread basis. */ + /* + ThreadLocal<Conversation> threadLocals = + new ThreadLocal<Conversation>() + { + protected Conversation initialValue() + { + Conversation settings = new Conversation(); + settings.conversationId = conversationIdGenerator.getAndIncrement(); + + return settings; + } + }; + */ + + /** Generates new coversation id's as needed. */ + 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<? extends BlockingQueue> queueClass) throws JMSException + { + log.debug("public ConversationFactory(Connection connection, Destination receiveDestination = " + receiveDestination + + ", Class<? extends BlockingQueue> 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.<BlockingQueue>newInstance(queueClass)); + } + } + + /** + * Clears the dead letter box, returning all messages that were in it. + * + * @return All messages in the dead letter box. + */ + public Collection<Message> emptyDeadLetterBox() + { + log.debug("public Collection<Message> emptyDeadLetterBox(): called"); + + Collection<Message> result = new ArrayList<Message>(); + 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. */ + long conversationId; + + /** + * Holds the send destination for the context. This will automatically be updated to the most recently received + * reply-to destination. + */ + 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 + + "): 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 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<Message> 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<Message> receiveAll(int num, long timeout) throws JMSException + { + log.debug("public Collection<Message> 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<Message> queue = idsToQueues.get(conversationId); + + // Used to collect the received messages in. + Collection<Message> result = new ArrayList<Message>(); + + // 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<Message> 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<Message> 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/java/systests/src/main/java/org/apache/qpid/test/FailoverBaseCase.java b/java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java index e939a06719..2fa6f4f417 100644 --- a/java/systests/src/main/java/org/apache/qpid/test/FailoverBaseCase.java +++ b/java/systests/src/main/java/org/apache/qpid/test/utils/FailoverBaseCase.java @@ -18,25 +18,31 @@ * under the License. * */ -package org.apache.qpid.test; +package org.apache.qpid.test.utils; import org.apache.qpid.client.transport.TransportConnection; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.testutil.QpidTestCase; import javax.jms.Connection; public class FailoverBaseCase extends QpidTestCase { - protected long RECEIVE_TIMEOUT = 1000l; + private boolean failedOver = true; + protected void setUp() throws java.lang.Exception { super.setUp(); - if( _broker.equals(VM) ) + + try + { + TransportConnection.createVMBroker(2); + } + catch (Exception e) { - System.getProperties().setProperty("amqj.AutoCreateVMBroker", "true"); + fail("Unable to create broker: " + e); } + } /** @@ -60,13 +66,24 @@ public class FailoverBaseCase extends QpidTestCase return conn; } + public void tearDown() throws Exception + { + if (!failedOver) + { + TransportConnection.killVMBroker(2); + ApplicationRegistry.remove(2); + } + super.tearDown(); + } + + /** * Only used of VM borker. - * // TODO: update the failover mechanism once 0.10 provides support for failover. */ public void failBroker() { - TransportConnection.killVMBroker(1); - ApplicationRegistry.remove(1); + failedOver = true; + TransportConnection.killVMBroker(2); + ApplicationRegistry.remove(2); } } diff --git a/java/systests/src/main/java/org/apache/qpid/test/utils/QpidClientConnection.java b/java/systests/src/main/java/org/apache/qpid/test/utils/QpidClientConnection.java new file mode 100644 index 0000000000..35cab0fd33 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/utils/QpidClientConnection.java @@ -0,0 +1,289 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.qpid.client.AMQConnection; +import org.apache.qpid.client.JMSAMQException; +import org.apache.qpid.test.utils.QpidTestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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 QpidTestCase 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/java/systests/src/main/java/org/apache/qpid/test/utils/QpidClientConnectionHelper.java b/java/systests/src/main/java/org/apache/qpid/test/utils/QpidClientConnectionHelper.java new file mode 100644 index 0000000000..72003ed7d7 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/utils/QpidClientConnectionHelper.java @@ -0,0 +1,295 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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 org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQConnectionFactory; +import org.apache.qpid.client.AMQConnectionURL; +import org.apache.qpid.client.JMSAMQException; +import org.apache.qpid.url.URLSyntaxException; + +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; + +/** + * @todo This was originally cut and paste from the client module leading to a duplicate class, then altered very + * slightly. To avoid the duplicate class the name was altered slightly to have 'Helper' on the end in order + * to distinguish it from the original. Delete this class and use the original instead, just upgrade it to + * provide the new features needed. + */ +public class QpidClientConnectionHelper implements ExceptionListener +{ + + private static final Logger _logger = Logger.getLogger(QpidClientConnectionHelper.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 QpidClientConnectionHelper(String broker) + { + super(); + setVirtualHost("/test"); + setBrokerList(broker); + setPrefetch(5000); + } + + 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 + { + AMQConnectionFactory factory = new AMQConnectionFactory(new AMQConnectionURL(brokerUrl)); + _logger.info("connecting to Qpid :" + brokerUrl); + connection = factory.createConnection(); + + // register exception listener + connection.setExceptionListener(this); + + session = ((AMQConnection) connection).createSession(transacted, ackMode, prefetch); + + _logger.info("starting connection"); + connection.start(); + + connected = true; + } + catch (URLSyntaxException e) + { + throw new JMSAMQException("URL syntax error in [" + brokerUrl + "]: " + e.getMessage(), e); + } + } + } + + public void disconnect() throws JMSException + { + 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, int deliveryMode) throws JMSException + { + if (!connected) + { + connect(); + } + + _logger.info("putting to queue " + queueName); + Queue queue = session.createQueue(queueName); + + final MessageProducer sender = session.createProducer(queue); + + sender.setDeliveryMode(deliveryMode); + + 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/java/client/src/main/java/org/apache/qpid/testutil/QpidTestCase.java b/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java index a241fd61af..39655ec845 100644 --- a/java/client/src/main/java/org/apache/qpid/testutil/QpidTestCase.java +++ b/java/systests/src/main/java/org/apache/qpid/test/utils/QpidTestCase.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.qpid.testutil; +package org.apache.qpid.test.utils; import junit.framework.TestCase; import junit.framework.TestResult; @@ -46,6 +46,8 @@ public class QpidTestCase extends TestCase private static final Logger _logger = LoggerFactory.getLogger(QpidTestCase.class); + protected long RECEIVE_TIMEOUT = 1000l; + /** * Some tests are excluded when the property test.excludes is set to true. * An exclusion list is either a file (prop test.excludesfile) which contains one test name @@ -333,6 +335,7 @@ public class QpidTestCase extends TestCase else if (_broker.equals(VM)) { TransportConnection.killAllVMBrokers(); + //ApplicationRegistry.removeAll(); } _brokerStarted = false; } diff --git a/java/systests/src/main/java/org/apache/qpid/test/utils/protocol/TestIoSession.java b/java/systests/src/main/java/org/apache/qpid/test/utils/protocol/TestIoSession.java new file mode 100644 index 0000000000..f1eb8159b6 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/utils/protocol/TestIoSession.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.utils.protocol; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; + +import org.apache.mina.common.IoFilterChain; +import org.apache.mina.common.IoHandler; +import org.apache.mina.common.IoService; +import org.apache.mina.common.IoServiceConfig; +import org.apache.mina.common.IoSessionConfig; +import org.apache.mina.common.TransportType; +import org.apache.mina.common.support.BaseIoSession; + +public class TestIoSession extends BaseIoSession { + + private String _stringLocalAddress; + private int _localPort; + + public SocketAddress getLocalAddress() + { + //create a new address for testing purposes using member variables + return new InetSocketAddress(_stringLocalAddress,_localPort); + } + + protected void updateTrafficMask() { + //dummy + } + + public IoService getService() { + return null; + } + + public IoServiceConfig getServiceConfig() { + return null; + } + + public IoHandler getHandler() { + return null; + } + + public IoSessionConfig getConfig() { + return null; + } + + public IoFilterChain getFilterChain() { + return null; + } + + public TransportType getTransportType() { + return null; + } + + public SocketAddress getRemoteAddress() { + return null; + } + + public SocketAddress getServiceAddress() { + return null; + } + + public int getScheduledWriteRequests() { + return 0; + } + + public int getScheduledWriteBytes() { + return 0; + } + + public String getStringLocalAddress() { + return _stringLocalAddress; + } + + public void setStringLocalAddress(String _stringLocalAddress) { + this._stringLocalAddress = _stringLocalAddress; + } + + public int getLocalPort() { + return _localPort; + } + + public void setLocalPort(int _localPort) { + this._localPort = _localPort; + } +} |
