summaryrefslogtreecommitdiff
path: root/java/broker/src/test/java/org/apache
diff options
context:
space:
mode:
Diffstat (limited to 'java/broker/src/test/java/org/apache')
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java91
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/ExtractResendAndRequeueTest.java255
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/RunBrokerWithCommand.java132
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/SelectorParserTest.java128
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/ack/AcknowledgeTest.java120
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/ack/TxAckTest.java283
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/configuration/QueueConfigurationTest.java136
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java867
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/configuration/TestPropertyUtils.java50
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java124
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java562
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/exchange/DestWildExchangeTest.java595
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java145
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java199
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java106
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/logging/management/LoggingManagementMBeanTest.java413
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/plugins/MockPluginManager.java51
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/plugins/PluginTest.java53
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java124
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java180
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/protocol/MaxChannelsTest.java86
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/protocol/TestIoSession.java328
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java107
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java354
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java85
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java349
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/AckTest.java420
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessage.java49
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessageHandle.java37
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java335
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/MockMessagePublishInfo.java52
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/MockProtocolSession.java262
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java197
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java435
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueThreadPoolTest.java60
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryShutdownTest.java120
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/access/ACLManagerTest.java99
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java62
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java156
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java68
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBeanTest.java271
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/access/plugins/network/FirewallPluginTest.java295
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabaseTest.java447
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/auth/database/HashedUserTest.java95
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabaseTest.java396
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainUserTest.java78
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java267
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/SaslServerTestCase.java66
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/TestPrincipalDatabase.java91
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/amqplain/AMQPlainSaslServerTest.java43
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerTest.java39
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreShutdownTest.java81
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java646
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/store/SkeletonMessageStore.java156
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/store/TestMemoryMessageStore.java51
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/store/TestReferenceCounting.java169
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java92
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java180
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/subscription/QueueBrowserUsesNoAckTest.java77
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/txn/TxnBufferTest.java306
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java214
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/util/LoggingProxyTest.java88
-rw-r--r--java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java137
-rw-r--r--java/broker/src/test/java/org/apache/qpid/util/MockChannel.java43
64 files changed, 12603 insertions, 0 deletions
diff --git a/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java b/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java
new file mode 100644
index 0000000000..b94f2ef76f
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java
@@ -0,0 +1,91 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server;
+
+import junit.framework.TestCase;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.exchange.ExchangeRegistry;
+import org.apache.qpid.server.management.ManagedBroker;
+import org.apache.qpid.server.queue.QueueRegistry;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+public class AMQBrokerManagerMBeanTest extends TestCase
+{
+ private QueueRegistry _queueRegistry;
+ private ExchangeRegistry _exchangeRegistry;
+
+ public void testExchangeOperations() throws Exception
+ {
+ String exchange1 = "testExchange1_" + System.currentTimeMillis();
+ String exchange2 = "testExchange2_" + System.currentTimeMillis();
+ String exchange3 = "testExchange3_" + System.currentTimeMillis();
+
+ assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange1)) == null);
+ assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange2)) == null);
+ assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange3)) == null);
+
+ VirtualHost vHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test");
+
+ ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHost.VirtualHostMBean) vHost.getManagedObject());
+ mbean.createNewExchange(exchange1, "direct", false);
+ mbean.createNewExchange(exchange2, "topic", false);
+ mbean.createNewExchange(exchange3, "headers", false);
+
+ assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange1)) != null);
+ assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange2)) != null);
+ assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange3)) != null);
+
+ mbean.unregisterExchange(exchange1);
+ mbean.unregisterExchange(exchange2);
+ mbean.unregisterExchange(exchange3);
+
+ assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange1)) == null);
+ assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange2)) == null);
+ assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange3)) == null);
+ }
+
+ public void testQueueOperations() throws Exception
+ {
+ String queueName = "testQueue_" + System.currentTimeMillis();
+ VirtualHost vHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test");
+
+ ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHost.VirtualHostMBean) vHost.getManagedObject());
+
+ assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) == null);
+
+ mbean.createNewQueue(queueName, "test", false);
+ assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) != null);
+
+ mbean.deleteQueue(queueName);
+ assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) == null);
+ }
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ IApplicationRegistry appRegistry = ApplicationRegistry.getInstance();
+ _queueRegistry = appRegistry.getVirtualHostRegistry().getVirtualHost("test").getQueueRegistry();
+ _exchangeRegistry = appRegistry.getVirtualHostRegistry().getVirtualHost("test").getExchangeRegistry();
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/ExtractResendAndRequeueTest.java b/java/broker/src/test/java/org/apache/qpid/server/ExtractResendAndRequeueTest.java
new file mode 100644
index 0000000000..5fbf9484f7
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/ExtractResendAndRequeueTest.java
@@ -0,0 +1,255 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server;
+
+import junit.framework.TestCase;
+import org.apache.qpid.server.ack.UnacknowledgedMessageMapImpl;
+import org.apache.qpid.server.queue.MockQueueEntry;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.queue.SimpleQueueEntryList;
+import org.apache.qpid.server.queue.MockAMQMessage;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.MockAMQQueue;
+import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.QueueEntryIterator;
+import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.MockSubscription;
+import org.apache.qpid.AMQException;
+
+import java.util.Map;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Iterator;
+
+/**
+ * QPID-1385 : Race condition between added to unacked map and resending due to a rollback.
+ *
+ * In AMQChannel _unackedMap.clear() was done after the visit. This meant that the clear was not in the same
+ * synchronized block as as the preparation to resend.
+ *
+ * This clearing/prep for resend was done as a result of the rollback call. HOWEVER, the delivery thread was still
+ * in the process of sending messages to the client. It is therefore possible that a message could block on the
+ * _unackedMap lock waiting for the visit to compelete so that it can add the new message to the unackedMap....
+ * which is then cleared by the resend/rollback thread.
+ *
+ * This problem was encountered by the testSend2ThenRollback test.
+ *
+ * To try and increase the chance of the race condition occuring this test will send multiple messages so that the
+ * delivery thread will be in progress while the rollback method is called. Hopefully this will cause the
+ * deliveryTag to be lost
+ */
+public class ExtractResendAndRequeueTest extends TestCase
+{
+
+ UnacknowledgedMessageMapImpl _unacknowledgedMessageMap;
+ private static final int INITIAL_MSG_COUNT = 10;
+ private AMQQueue _queue = new MockAMQQueue();
+ private LinkedList<QueueEntry> _referenceList = new LinkedList<QueueEntry>();
+
+ @Override
+ public void setUp() throws AMQException
+ {
+ _unacknowledgedMessageMap = new UnacknowledgedMessageMapImpl(100);
+
+ long id = 0;
+ SimpleQueueEntryList list = new SimpleQueueEntryList(_queue);
+
+ // Add initial messages to QueueEntryList
+ for (int count = 0; count < INITIAL_MSG_COUNT; count++)
+ {
+ AMQMessage msg = new MockAMQMessage(id);
+
+ list.add(msg);
+
+ //Increment ID;
+ id++;
+ }
+
+ // Iterate through the QueueEntryList and add entries to unacknowledgeMessageMap and referecenList
+ QueueEntryIterator queueEntries = list.iterator();
+ while(queueEntries.advance())
+ {
+ QueueEntry entry = queueEntries.getNode();
+ _unacknowledgedMessageMap.add(entry.getMessage().getMessageId(), entry);
+
+ // Store the entry for future inspection
+ _referenceList.add(entry);
+ }
+
+ assertEquals("Map does not contain correct setup data", INITIAL_MSG_COUNT, _unacknowledgedMessageMap.size());
+ }
+
+ /**
+ * Helper method to create a new subscription and aquire the given messages.
+ *
+ * @param messageList The messages to aquire
+ *
+ * @return Subscription that performed the aquire
+ */
+ private Subscription createSubscriptionAndAquireMessages(LinkedList<QueueEntry> messageList)
+ {
+ Subscription subscription = new MockSubscription();
+
+ // Aquire messages in subscription
+ for (QueueEntry entry : messageList)
+ {
+ entry.acquire(subscription);
+ }
+
+ return subscription;
+ }
+
+ /**
+ * This is the normal consumer rollback method.
+ *
+ * An active consumer that has aquired messages expects those messasges to be reset when rollback is requested.
+ *
+ * This test validates that the msgToResend map includes all the messages and none are left behind.
+ *
+ * @throws AMQException the visit interface throws this
+ */
+ public void testResend() throws AMQException
+ {
+ //We don't need the subscription object here.
+ createSubscriptionAndAquireMessages(_referenceList);
+
+ final Map<Long, QueueEntry> msgToRequeue = new LinkedHashMap<Long, QueueEntry>();
+ final Map<Long, QueueEntry> msgToResend = new LinkedHashMap<Long, QueueEntry>();
+
+ // requeueIfUnabletoResend doesn't matter here.
+ _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue,
+ msgToResend, true, new StoreContext()));
+
+ assertEquals("Message count for resend not correct.", INITIAL_MSG_COUNT, msgToResend.size());
+ assertEquals("Message count for requeue not correct.", 0, msgToRequeue.size());
+ assertEquals("Map was not emptied", 0, _unacknowledgedMessageMap.size());
+ }
+
+ /**
+ * This is the normal consumer close method.
+ *
+ * When a consumer that has aquired messages expects closes the messages that it has aquired should be removed from
+ * the unacknowledgeMap and placed in msgToRequeue
+ *
+ * This test validates that the msgToRequeue map includes all the messages and none are left behind.
+ *
+ * @throws AMQException the visit interface throws this
+ */
+ public void testRequeueDueToSubscriptionClosure() throws AMQException
+ {
+ Subscription subscription = createSubscriptionAndAquireMessages(_referenceList);
+
+ // Close subscription
+ subscription.close();
+
+ final Map<Long, QueueEntry> msgToRequeue = new LinkedHashMap<Long, QueueEntry>();
+ final Map<Long, QueueEntry> msgToResend = new LinkedHashMap<Long, QueueEntry>();
+
+ // requeueIfUnabletoResend doesn't matter here.
+ _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue,
+ msgToResend, true, new StoreContext()));
+
+ assertEquals("Message count for resend not correct.", 0, msgToResend.size());
+ assertEquals("Message count for requeue not correct.", INITIAL_MSG_COUNT, msgToRequeue.size());
+ assertEquals("Map was not emptied", 0, _unacknowledgedMessageMap.size());
+ }
+
+ /**
+ * If the subscription is null, due to message being retrieved via a GET, And we request that messages are requeued
+ * requeueIfUnabletoResend(set to true) then all messages should be sent to the msgToRequeue map.
+ *
+ * @throws AMQException the visit interface throws this
+ */
+
+ public void testRequeueDueToMessageHavingNoConsumerTag() throws AMQException
+ {
+ final Map<Long, QueueEntry> msgToRequeue = new LinkedHashMap<Long, QueueEntry>();
+ final Map<Long, QueueEntry> msgToResend = new LinkedHashMap<Long, QueueEntry>();
+
+ // requeueIfUnabletoResend = true so all messages should go to msgToRequeue
+ _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue,
+ msgToResend, true, new StoreContext()));
+
+ assertEquals("Message count for resend not correct.", 0, msgToResend.size());
+ assertEquals("Message count for requeue not correct.", INITIAL_MSG_COUNT, msgToRequeue.size());
+ assertEquals("Map was not emptied", 0, _unacknowledgedMessageMap.size());
+ }
+
+ /**
+ * If the subscription is null, due to message being retrieved via a GET, And we request that we don't
+ * requeueIfUnabletoResend(set to false) then all messages should be dropped as we do not have a dead letter queue.
+ *
+ * @throws AMQException the visit interface throws this
+ */
+
+ public void testDrop() throws AMQException
+ {
+ final Map<Long, QueueEntry> msgToRequeue = new LinkedHashMap<Long, QueueEntry>();
+ final Map<Long, QueueEntry> msgToResend = new LinkedHashMap<Long, QueueEntry>();
+
+ // requeueIfUnabletoResend = false so all messages should be dropped all maps should be empty
+ _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue,
+ msgToResend, false, new StoreContext()));
+
+ assertEquals("Message count for resend not correct.", 0, msgToResend.size());
+ assertEquals("Message count for requeue not correct.", 0, msgToRequeue.size());
+ assertEquals("Map was not emptied", 0, _unacknowledgedMessageMap.size());
+
+
+ for (QueueEntry entry : _referenceList)
+ {
+ assertTrue("Message was not discarded", entry.isDeleted());
+ }
+
+ }
+
+ /**
+ * If the subscription is null, due to message being retrieved via a GET, AND the queue upon which the message was
+ * delivered has been deleted then it is not possible to requeue. Currently we simply discar the message but in the
+ * future we may wish to dead letter the message.
+ *
+ * Validate that at the end of the visit all Maps are empty and all messages are marked as deleted
+ *
+ * @throws AMQException the visit interface throws this
+ */
+ public void testDiscard() throws AMQException
+ {
+ final Map<Long, QueueEntry> msgToRequeue = new LinkedHashMap<Long, QueueEntry>();
+ final Map<Long, QueueEntry> msgToResend = new LinkedHashMap<Long, QueueEntry>();
+
+ _queue.delete();
+
+ // requeueIfUnabletoResend : value doesn't matter here as queue has been deleted
+ _unacknowledgedMessageMap.visit(new ExtractResendAndRequeue(_unacknowledgedMessageMap, msgToRequeue,
+ msgToResend, false, new StoreContext()));
+
+ assertEquals("Message count for resend not correct.", 0, msgToResend.size());
+ assertEquals("Message count for requeue not correct.", 0, msgToRequeue.size());
+ assertEquals("Map was not emptied", 0, _unacknowledgedMessageMap.size());
+
+ for (QueueEntry entry : _referenceList)
+ {
+ assertTrue("Message was not discarded", entry.isDeleted());
+ }
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/RunBrokerWithCommand.java b/java/broker/src/test/java/org/apache/qpid/server/RunBrokerWithCommand.java
new file mode 100644
index 0000000000..59543874b4
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/RunBrokerWithCommand.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.server;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.Level;
+
+import java.io.InputStream;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+
+public class RunBrokerWithCommand
+{
+ public static void main(String[] args)
+ {
+ //Start the broker
+ try
+ {
+ String[] fudge = args.clone();
+
+ // Override the first value which is the command we are going to run later.
+ fudge[0] = "-v";
+ new Main(fudge).startup();
+ }
+ catch (Exception e)
+ {
+ System.err.println("Unable to start broker due to: " + e.getMessage());
+
+ e.printStackTrace();
+ exit(1);
+ }
+
+ Logger.getRootLogger().setLevel(Level.ERROR);
+
+ //run command
+ try
+ {
+ Process task = Runtime.getRuntime().exec(args[0]);
+ System.err.println("Started Proccess: " + args[0]);
+
+ InputStream inputStream = task.getInputStream();
+
+ InputStream errorStream = task.getErrorStream();
+
+ Thread out = new Thread(new Outputter("[OUT]", new BufferedReader(new InputStreamReader(inputStream))));
+ Thread err = new Thread(new Outputter("[ERR]", new BufferedReader(new InputStreamReader(errorStream))));
+
+ out.start();
+ err.start();
+
+ out.join();
+ err.join();
+
+ System.err.println("Waiting for process to exit: " + args[0]);
+ task.waitFor();
+ System.err.println("Done Proccess: " + args[0]);
+
+ }
+ catch (IOException e)
+ {
+ System.err.println("Proccess had problems: " + e.getMessage());
+ e.printStackTrace(System.err);
+ exit(1);
+ }
+ catch (InterruptedException e)
+ {
+ System.err.println("Proccess had problems: " + e.getMessage());
+ e.printStackTrace(System.err);
+
+ exit(1);
+ }
+
+
+ exit(0);
+ }
+
+ private static void exit(int i)
+ {
+ Logger.getRootLogger().setLevel(Level.INFO);
+ System.exit(i);
+ }
+
+ static class Outputter implements Runnable
+ {
+
+ BufferedReader reader;
+ String prefix;
+
+ Outputter(String s, BufferedReader r)
+ {
+ prefix = s;
+ reader = r;
+ }
+
+ public void run()
+ {
+ String line;
+ try
+ {
+ while ((line = reader.readLine()) != null)
+ {
+ System.out.println(prefix + line);
+ }
+ }
+ catch (IOException e)
+ {
+ System.out.println("Error occured reading; " + e.getMessage());
+ }
+ }
+
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/SelectorParserTest.java b/java/broker/src/test/java/org/apache/qpid/server/SelectorParserTest.java
new file mode 100644
index 0000000000..a0304a7b01
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/SelectorParserTest.java
@@ -0,0 +1,128 @@
+package org.apache.qpid.server;
+
+import junit.framework.TestCase;
+import org.apache.qpid.server.filter.JMSSelectorFilter;
+import org.apache.qpid.AMQException;/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+public class SelectorParserTest extends TestCase
+{
+ public void testSelectorWithHyphen()
+ {
+ testPass("Cost = 2 AND \"property-with-hyphen\" = 'wibble'");
+ }
+
+ public void testLike()
+ {
+ testFail("Cost LIKE 2");
+ testPass("Cost LIKE 'Hello'");
+ }
+
+ public void testStringQuoted()
+ {
+ testPass("string = 'Test'");
+ }
+
+ public void testProperty()
+ {
+ testPass("prop1 = prop2");
+ }
+
+ public void testPropertyNames()
+ {
+ testPass("$min= TRUE AND _max= FALSE AND Prop_2 = true AND prop$3 = false");
+ }
+
+ public void testProtected()
+ {
+ testFail("NULL = 0 ");
+ testFail("TRUE = 0 ");
+ testFail("FALSE = 0 ");
+ testFail("NOT = 0 ");
+ testFail("AND = 0 ");
+ testFail("OR = 0 ");
+ testFail("BETWEEN = 0 ");
+ testFail("LIKE = 0 ");
+ testFail("IN = 0 ");
+ testFail("IS = 0 ");
+ testFail("ESCAPE = 0 ");
+ }
+
+
+ public void testBoolean()
+ {
+ testPass("min= TRUE AND max= FALSE ");
+ testPass("min= true AND max= false");
+ }
+
+ public void testDouble()
+ {
+ testPass("positive=31E2 AND negative=-31.4E3");
+ testPass("min=" + Double.MIN_VALUE + " AND max=" + Double.MAX_VALUE);
+ }
+
+ public void testLong()
+ {
+ testPass("minLong=" + Long.MIN_VALUE + "L AND maxLong=" + Long.MAX_VALUE + "L");
+ }
+
+ public void testInt()
+ {
+ testPass("minInt=" + Integer.MIN_VALUE + " AND maxInt=" + Integer.MAX_VALUE);
+ }
+
+ public void testSigned()
+ {
+ testPass("negative=-42 AND positive=+42");
+ }
+
+ public void testOctal()
+ {
+ testPass("octal=042");
+ }
+
+
+ private void testPass(String selector)
+ {
+ try
+ {
+ new JMSSelectorFilter(selector);
+ }
+ catch (AMQException e)
+ {
+ fail("Selector '" + selector + "' was not parsed :" + e.getMessage());
+ }
+ }
+
+ private void testFail(String selector)
+ {
+ try
+ {
+ new JMSSelectorFilter(selector);
+ fail("Selector '" + selector + "' was parsed ");
+ }
+ catch (AMQException e)
+ {
+ //normal path
+ }
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/ack/AcknowledgeTest.java b/java/broker/src/test/java/org/apache/qpid/server/ack/AcknowledgeTest.java
new file mode 100644
index 0000000000..9ef4af2932
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/ack/AcknowledgeTest.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.server.ack;
+
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.protocol.InternalTestProtocolSession;
+import org.apache.qpid.server.util.InternalBrokerBaseCase;
+
+import java.util.List;
+
+public class AcknowledgeTest extends InternalBrokerBaseCase
+{
+
+ public void testTransactionalSingleAck() throws AMQException
+ {
+ _channel.setLocalTransactional();
+ runMessageAck(1, 1, 1, false, 0);
+ }
+
+ public void testTransactionalMultiAck() throws AMQException
+ {
+ _channel.setLocalTransactional();
+ runMessageAck(10, 1, 5, true, 5);
+ }
+
+ public void testTransactionalAckAll() throws AMQException
+ {
+ _channel.setLocalTransactional();
+ runMessageAck(10, 1, 0, true, 0);
+ }
+
+ public void testNonTransactionalSingleAck() throws AMQException
+ {
+ runMessageAck(1, 1, 1, false, 0);
+ }
+
+ public void testNonTransactionalMultiAck() throws AMQException
+ {
+ runMessageAck(10, 1, 5, true, 5);
+ }
+
+ public void testNonTransactionalAckAll() throws AMQException
+ {
+ runMessageAck(10, 1, 0, true, 0);
+ }
+
+ protected void runMessageAck(int sendMessageCount, long firstDeliveryTag, long acknowledgeDeliveryTag, boolean acknowldegeMultiple, int remainingUnackedMessages) throws AMQException
+ {
+ //Check store is empty
+ checkStoreContents(0);
+
+ //Send required messsages to the queue
+ publishMessages(_session, _channel, sendMessageCount);
+
+ if (_channel.isTransactional())
+ {
+ _channel.commit();
+ }
+
+ //Ensure they are stored
+ checkStoreContents(sendMessageCount);
+
+ //Check that there are no unacked messages
+ assertEquals("Channel should have no unacked msgs ", 0, _channel.getUnacknowledgedMessageMap().size());
+
+ //Subscribe to the queue
+ AMQShortString subscriber = subscribe(_session, _channel, _queue);
+
+ _queue.deliverAsync();
+
+ //Wait for the messages to be delivered
+ _session.awaitDelivery(sendMessageCount);
+
+ //Check that they are all waiting to be acknoledged
+ assertEquals("Channel should have unacked msgs", sendMessageCount, _channel.getUnacknowledgedMessageMap().size());
+
+ List<InternalTestProtocolSession.DeliveryPair> messages = _session.getDelivers(_channel.getChannelId(), subscriber, sendMessageCount);
+
+ //Double check we received the right number of messages
+ assertEquals(sendMessageCount, messages.size());
+
+ //Check that the first message has the expected deliveryTag
+ assertEquals("First message does not have expected deliveryTag", firstDeliveryTag, messages.get(0).getDeliveryTag());
+
+ //Send required Acknowledgement
+ _channel.acknowledgeMessage(acknowledgeDeliveryTag, acknowldegeMultiple);
+
+ if (_channel.isTransactional())
+ {
+ _channel.commit();
+ }
+
+ // Check Remaining Acknowledgements
+ assertEquals("Channel unacked msgs count incorrect", remainingUnackedMessages, _channel.getUnacknowledgedMessageMap().size());
+
+ //Check store contents are also correct.
+ checkStoreContents(remainingUnackedMessages);
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/ack/TxAckTest.java b/java/broker/src/test/java/org/apache/qpid/server/ack/TxAckTest.java
new file mode 100644
index 0000000000..dfbbd56d6f
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/ack/TxAckTest.java
@@ -0,0 +1,283 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.ack;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.server.RequiredDeliveryException;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
+import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.MessageHandleFactory;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.queue.AMQMessageHandle;
+import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.store.TestMemoryMessageStore;
+import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.store.MemoryMessageStore;
+import org.apache.qpid.server.txn.NonTransactionalContext;
+import org.apache.qpid.server.txn.TransactionalContext;
+
+import java.util.*;
+
+public class TxAckTest extends TestCase
+{
+ private Scenario individual;
+ private Scenario multiple;
+ private Scenario combined;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ //ack only 5th msg
+ individual = new Scenario(10, Arrays.asList(5l), Arrays.asList(1l, 2l, 3l, 4l, 6l, 7l, 8l, 9l, 10l));
+ individual.update(5, false);
+
+ //ack all up to and including 5th msg
+ multiple = new Scenario(10, Arrays.asList(1l, 2l, 3l, 4l, 5l), Arrays.asList(6l, 7l, 8l, 9l, 10l));
+ multiple.update(5, true);
+
+ //leave only 8th and 9th unacked
+ combined = new Scenario(10, Arrays.asList(1l, 2l, 3l, 4l, 5l, 6l, 7l, 10l), Arrays.asList(8l, 9l));
+ combined.update(3, false);
+ combined.update(5, true);
+ combined.update(7, true);
+ combined.update(2, true);//should be ignored
+ combined.update(1, false);//should be ignored
+ combined.update(10, false);
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ individual.stop();
+ multiple.stop();
+ combined.stop();
+ }
+
+ public void testPrepare() throws AMQException
+ {
+ individual.prepare();
+ multiple.prepare();
+ combined.prepare();
+ }
+
+ public void testUndoPrepare() throws AMQException
+ {
+ individual.undoPrepare();
+ multiple.undoPrepare();
+ combined.undoPrepare();
+ }
+
+ public void testCommit() throws AMQException
+ {
+ individual.commit();
+ multiple.commit();
+ combined.commit();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(TxAckTest.class);
+ }
+
+ private class Scenario
+ {
+ private final UnacknowledgedMessageMap _map = new UnacknowledgedMessageMapImpl(5000);
+ private final TxAck _op = new TxAck(_map);
+ private final List<Long> _acked;
+ private final List<Long> _unacked;
+ private StoreContext _storeContext = new StoreContext();
+ private AMQQueue _queue;
+
+ Scenario(int messageCount, List<Long> acked, List<Long> unacked) throws Exception
+ {
+ TransactionalContext txnContext = new NonTransactionalContext(new TestMemoryMessageStore(),
+ _storeContext, null,
+ new LinkedList<RequiredDeliveryException>()
+ );
+
+ PropertiesConfiguration env = new PropertiesConfiguration();
+ env.setProperty("name", "test");
+ VirtualHost virtualHost = new VirtualHost(new VirtualHostConfiguration("test", env), null);
+
+ _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("test"), false, null, false,
+ virtualHost, null);
+
+ for (int i = 0; i < messageCount; i++)
+ {
+ long deliveryTag = i + 1;
+
+ MessagePublishInfo info = new MessagePublishInfo()
+ {
+
+ public AMQShortString getExchange()
+ {
+ return null;
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isImmediate()
+ {
+ return false;
+ }
+
+ public boolean isMandatory()
+ {
+ return false;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return null;
+ }
+ };
+
+ TestMessage message = new TestMessage(deliveryTag, i, info, txnContext.getStoreContext());
+ _map.add(deliveryTag, _queue.enqueue(new StoreContext(), message));
+ }
+ _acked = acked;
+ _unacked = unacked;
+ }
+
+ void update(long deliverytag, boolean multiple)
+ {
+ _op.update(deliverytag, multiple);
+ }
+
+ private void assertCount(List<Long> tags, int expected)
+ {
+ for (long tag : tags)
+ {
+ QueueEntry u = _map.get(tag);
+ assertTrue("Message not found for tag " + tag, u != null);
+ ((TestMessage) u.getMessage()).assertCountEquals(expected);
+ }
+ }
+
+ void prepare() throws AMQException
+ {
+ _op.consolidate();
+ _op.prepare(_storeContext);
+
+ assertCount(_acked, -1);
+ assertCount(_unacked, 0);
+
+ }
+
+ void undoPrepare()
+ {
+ _op.consolidate();
+ _op.undoPrepare();
+
+ assertCount(_acked, 1);
+ assertCount(_unacked, 0);
+ }
+
+ void commit()
+ {
+ _op.consolidate();
+ _op.commit(_storeContext);
+
+ //check acked messages are removed from map
+ Set<Long> keys = new HashSet<Long>(_map.getDeliveryTags());
+ keys.retainAll(_acked);
+ assertTrue("Expected messages with following tags to have been removed from map: " + keys, keys.isEmpty());
+ //check unacked messages are still in map
+ keys = new HashSet<Long>(_unacked);
+ keys.removeAll(_map.getDeliveryTags());
+ assertTrue("Expected messages with following tags to still be in map: " + keys, keys.isEmpty());
+ }
+
+ public void stop()
+ {
+ _queue.stop();
+ }
+ }
+
+ private static AMQMessageHandle createMessageHandle(final long messageId, final MessagePublishInfo publishBody)
+ {
+ final AMQMessageHandle amqMessageHandle = (new MessageHandleFactory()).createMessageHandle(messageId,
+ null,
+ false);
+ try
+ {
+ amqMessageHandle.setPublishAndContentHeaderBody(new StoreContext(),
+ publishBody,
+ new ContentHeaderBody()
+ {
+ public int getSize()
+ {
+ return 1;
+ }
+ });
+ }
+ catch (AMQException e)
+ {
+ // won't happen
+ }
+
+
+ return amqMessageHandle;
+ }
+
+
+ private class TestMessage extends AMQMessage
+ {
+ private final long _tag;
+ private int _count;
+
+ TestMessage(long tag, long messageId, MessagePublishInfo publishBody, StoreContext storeContext)
+ throws AMQException
+ {
+ super(createMessageHandle(messageId, publishBody), storeContext, publishBody);
+ _tag = tag;
+ }
+
+
+ public boolean incrementReference()
+ {
+ _count++;
+ return true;
+ }
+
+ public void decrementReference(StoreContext context)
+ {
+ _count--;
+ }
+
+ void assertCountEquals(int expected)
+ {
+ assertEquals("Wrong count for message with tag " + _tag, expected, _count);
+ }
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/configuration/QueueConfigurationTest.java b/java/broker/src/test/java/org/apache/qpid/server/configuration/QueueConfigurationTest.java
new file mode 100644
index 0000000000..9692cf2727
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/configuration/QueueConfigurationTest.java
@@ -0,0 +1,136 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.configuration;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.configuration.PropertiesConfiguration;
+
+public class QueueConfigurationTest extends TestCase
+{
+
+ private VirtualHostConfiguration _emptyConf;
+ private PropertiesConfiguration _env;
+ private ServerConfiguration _fullServerConf;
+ private VirtualHostConfiguration _fullHostConf;
+
+ public void setUp() throws Exception
+ {
+ _env = new PropertiesConfiguration();
+ _emptyConf = new VirtualHostConfiguration("test", _env);
+
+ PropertiesConfiguration fullEnv = new PropertiesConfiguration();
+ fullEnv.setProperty("queues.maximumMessageAge", 1);
+ fullEnv.setProperty("queues.maximumQueueDepth", 1);
+ fullEnv.setProperty("queues.maximumMessageSize", 1);
+ fullEnv.setProperty("queues.maximumMessageCount", 1);
+ fullEnv.setProperty("queues.minimumAlertRepeatGap", 1);
+
+ _fullHostConf = new VirtualHostConfiguration("test", fullEnv);
+
+ }
+
+ public void testGetMaximumMessageAge()
+ {
+ // Check default value
+ QueueConfiguration qConf = new QueueConfiguration("test", _env, _emptyConf);
+ assertEquals(0, qConf.getMaximumMessageAge());
+
+ // Check explicit value
+ PropertiesConfiguration fullEnv = new PropertiesConfiguration();
+ fullEnv.setProperty("maximumMessageAge", 2);
+ qConf = new QueueConfiguration("test", fullEnv, _fullHostConf);
+ assertEquals(2, qConf.getMaximumMessageAge());
+
+ // Check inherited value
+ qConf = new QueueConfiguration("test", _env, _fullHostConf);
+ assertEquals(1, qConf.getMaximumMessageAge());
+ }
+
+ public void testGetMaximumQueueDepth()
+ {
+ // Check default value
+ QueueConfiguration qConf = new QueueConfiguration("test", _env, _emptyConf);
+ assertEquals(0, qConf.getMaximumQueueDepth());
+
+ // Check explicit value
+ PropertiesConfiguration fullEnv = new PropertiesConfiguration();
+ fullEnv.setProperty("maximumQueueDepth", 2);
+ qConf = new QueueConfiguration("test", fullEnv, _fullHostConf);
+ assertEquals(2, qConf.getMaximumQueueDepth());
+
+ // Check inherited value
+ qConf = new QueueConfiguration("test", _env, _fullHostConf);
+ assertEquals(1, qConf.getMaximumQueueDepth());
+ }
+
+ public void testGetMaximumMessageSize()
+ {
+ // Check default value
+ QueueConfiguration qConf = new QueueConfiguration("test", _env, _emptyConf);
+ assertEquals(0, qConf.getMaximumMessageSize());
+
+ // Check explicit value
+ PropertiesConfiguration fullEnv = new PropertiesConfiguration();
+ fullEnv.setProperty("maximumMessageSize", 2);
+ qConf = new QueueConfiguration("test", fullEnv, _fullHostConf);
+ assertEquals(2, qConf.getMaximumMessageSize());
+
+ // Check inherited value
+ qConf = new QueueConfiguration("test", _env, _fullHostConf);
+ assertEquals(1, qConf.getMaximumMessageSize());
+ }
+
+ public void testGetMaximumMessageCount()
+ {
+ // Check default value
+ QueueConfiguration qConf = new QueueConfiguration("test", _env, _emptyConf);
+ assertEquals(0, qConf.getMaximumMessageCount());
+
+ // Check explicit value
+ PropertiesConfiguration fullEnv = new PropertiesConfiguration();
+ fullEnv.setProperty("maximumMessageCount", 2);
+ qConf = new QueueConfiguration("test", fullEnv, _fullHostConf);
+ assertEquals(2, qConf.getMaximumMessageCount());
+
+ // Check inherited value
+ qConf = new QueueConfiguration("test", _env, _fullHostConf);
+ assertEquals(1, qConf.getMaximumMessageCount());
+ }
+
+ public void testGetMinimumAlertRepeatGap()
+ {
+ // Check default value
+ QueueConfiguration qConf = new QueueConfiguration("test", _env, _emptyConf);
+ assertEquals(0, qConf.getMinimumAlertRepeatGap());
+
+ // Check explicit value
+ PropertiesConfiguration fullEnv = new PropertiesConfiguration();
+ fullEnv.setProperty("minimumAlertRepeatGap", 2);
+ qConf = new QueueConfiguration("test", fullEnv, _fullHostConf);
+ assertEquals(2, qConf.getMinimumAlertRepeatGap());
+
+ // Check inherited value
+ qConf = new QueueConfiguration("test", _env, _fullHostConf);
+ assertEquals(1, qConf.getMinimumAlertRepeatGap());
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java b/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java
new file mode 100644
index 0000000000..2c39d006b9
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java
@@ -0,0 +1,867 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.configuration;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.List;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.configuration.SystemConfiguration;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.codec.AMQCodecFactory;
+import org.apache.qpid.server.protocol.AMQMinaProtocolSession;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.protocol.TestIoSession;
+import org.apache.qpid.server.queue.MockProtocolSession;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry;
+import org.apache.qpid.server.security.access.ACLManager;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
+
+import junit.framework.TestCase;
+
+public class ServerConfigurationTest extends TestCase
+{
+
+ private XMLConfiguration _config;
+
+ @Override
+ public void setUp()
+ {
+ _config = new XMLConfiguration();
+ }
+
+ @Override
+ public void tearDown()
+ {
+ ApplicationRegistry.removeAll();
+ }
+
+ public void testSetJMXManagementPort() throws ConfigurationException
+ {
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ serverConfig.setJMXManagementPort(23);
+ assertEquals(23, serverConfig.getJMXManagementPort());
+ }
+
+ public void testGetJMXManagementPort() throws ConfigurationException
+ {
+ _config.setProperty("management.jmxport", 42);
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(42, serverConfig.getJMXManagementPort());
+ }
+
+ public void testGetPlatformMbeanserver() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getPlatformMbeanserver());
+
+ // Check value we set
+ _config.setProperty("management.platform-mbeanserver", false);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getPlatformMbeanserver());
+ }
+
+ public void testGetPluginDirectory() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(null, serverConfig.getPluginDirectory());
+
+ // Check value we set
+ _config.setProperty("plugin-directory", "/path/to/plugins");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals("/path/to/plugins", serverConfig.getPluginDirectory());
+ }
+
+ public void testGetPrincipalDatabaseNames() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getPrincipalDatabaseNames().size());
+
+ // Check value we set
+ _config.setProperty("security.principal-databases.principal-database(0).name", "a");
+ _config.setProperty("security.principal-databases.principal-database(1).name", "b");
+ serverConfig = new ServerConfiguration(_config);
+ List<String> dbs = serverConfig.getPrincipalDatabaseNames();
+ assertEquals(2, dbs.size());
+ assertEquals("a", dbs.get(0));
+ assertEquals("b", dbs.get(1));
+ }
+
+ public void testGetPrincipalDatabaseClass() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getPrincipalDatabaseClass().size());
+
+ // Check value we set
+ _config.setProperty("security.principal-databases.principal-database(0).class", "a");
+ _config.setProperty("security.principal-databases.principal-database(1).class", "b");
+ serverConfig = new ServerConfiguration(_config);
+ List<String> dbs = serverConfig.getPrincipalDatabaseClass();
+ assertEquals(2, dbs.size());
+ assertEquals("a", dbs.get(0));
+ assertEquals("b", dbs.get(1));
+ }
+
+ public void testGetPrincipalDatabaseAttributeNames() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getPrincipalDatabaseAttributeNames(1).size());
+
+ // Check value we set
+ _config.setProperty("security.principal-databases.principal-database(0).attributes(0).attribute.name", "a");
+ _config.setProperty("security.principal-databases.principal-database(0).attributes(1).attribute.name", "b");
+ serverConfig = new ServerConfiguration(_config);
+ List<String> dbs = serverConfig.getPrincipalDatabaseAttributeNames(0);
+ assertEquals(2, dbs.size());
+ assertEquals("a", dbs.get(0));
+ assertEquals("b", dbs.get(1));
+ }
+
+ public void testGetPrincipalDatabaseAttributeValues() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getPrincipalDatabaseAttributeValues(1).size());
+
+ // Check value we set
+ _config.setProperty("security.principal-databases.principal-database(0).attributes(0).attribute.value", "a");
+ _config.setProperty("security.principal-databases.principal-database(0).attributes(1).attribute.value", "b");
+ serverConfig = new ServerConfiguration(_config);
+ List<String> dbs = serverConfig.getPrincipalDatabaseAttributeValues(0);
+ assertEquals(2, dbs.size());
+ assertEquals("a", dbs.get(0));
+ assertEquals("b", dbs.get(1));
+ }
+
+ public void testGetManagementAccessList() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getManagementAccessList().size());
+
+ // Check value we set
+ _config.setProperty("security.jmx.access(0)", "a");
+ _config.setProperty("security.jmx.access(1)", "b");
+ serverConfig = new ServerConfiguration(_config);
+ List<String> dbs = serverConfig.getManagementAccessList();
+ assertEquals(2, dbs.size());
+ assertEquals("a", dbs.get(0));
+ assertEquals("b", dbs.get(1));
+ }
+
+ public void testGetFrameSize() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(65536, serverConfig.getFrameSize());
+
+ // Check value we set
+ _config.setProperty("advanced.framesize", "23");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(23, serverConfig.getFrameSize());
+ }
+
+ public void testGetProtectIOEnabled() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getProtectIOEnabled());
+
+ // Check value we set
+ _config.setProperty("broker.connector.protectio.enabled", true);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getProtectIOEnabled());
+ }
+
+ public void testGetBufferReadLimit() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(262144, serverConfig.getBufferReadLimit());
+
+ // Check value we set
+ _config.setProperty("broker.connector.protectio.readBufferLimitSize", 23);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(23, serverConfig.getBufferReadLimit());
+ }
+
+ public void testGetBufferWriteLimit() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(262144, serverConfig.getBufferWriteLimit());
+
+ // Check value we set
+ _config.setProperty("broker.connector.protectio.writeBufferLimitSize", 23);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(23, serverConfig.getBufferWriteLimit());
+ }
+
+ public void testGetSynchedClocks() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getSynchedClocks());
+
+ // Check value we set
+ _config.setProperty("advanced.synced-clocks", true);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getSynchedClocks());
+ }
+
+ public void testGetMsgAuth() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getMsgAuth());
+
+ // Check value we set
+ _config.setProperty("security.msg-auth", true);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getMsgAuth());
+ }
+
+ public void testGetJMXPrincipalDatabase() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(null, serverConfig.getJMXPrincipalDatabase());
+
+ // Check value we set
+ _config.setProperty("security.jmx.principal-database", "a");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals("a", serverConfig.getJMXPrincipalDatabase());
+ }
+
+ public void testGetManagementKeyStorePath() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(null, serverConfig.getManagementKeyStorePath());
+
+ // Check value we set
+ _config.setProperty("management.ssl.keyStorePath", "a");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals("a", serverConfig.getManagementKeyStorePath());
+ }
+
+ public void testGetManagementSSLEnabled() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getManagementSSLEnabled());
+
+ // Check value we set
+ _config.setProperty("management.ssl.enabled", false);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getManagementSSLEnabled());
+ }
+
+ public void testGetManagementKeyStorePassword() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(null, serverConfig.getManagementKeyStorePassword());
+
+ // Check value we set
+ _config.setProperty("management.ssl.keyStorePassword", "a");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals("a", serverConfig.getManagementKeyStorePassword());
+ }
+
+ public void testGetQueueAutoRegister() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getQueueAutoRegister());
+
+ // Check value we set
+ _config.setProperty("queue.auto_register", false);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getQueueAutoRegister());
+ }
+
+ public void testGetManagementEnabled() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getManagementEnabled());
+
+ // Check value we set
+ _config.setProperty("management.enabled", false);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getManagementEnabled());
+ }
+
+ public void testSetManagementEnabled() throws ConfigurationException
+ {
+ // Check value we set
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ serverConfig.setManagementEnabled(false);
+ assertEquals(false, serverConfig.getManagementEnabled());
+ }
+
+ public void testGetHeartBeatDelay() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(5, serverConfig.getHeartBeatDelay());
+
+ // Check value we set
+ _config.setProperty("heartbeat.delay", 23);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(23, serverConfig.getHeartBeatDelay());
+ }
+
+ public void testGetHeartBeatTimeout() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(2.0, serverConfig.getHeartBeatTimeout());
+
+ // Check value we set
+ _config.setProperty("heartbeat.timeoutFactor", 2.3);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(2.3, serverConfig.getHeartBeatTimeout());
+ }
+
+ public void testGetMaximumMessageAge() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getMaximumMessageAge());
+
+ // Check value we set
+ _config.setProperty("maximumMessageAge", 10L);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(10, serverConfig.getMaximumMessageAge());
+ }
+
+ public void testGetMaximumMessageCount() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getMaximumMessageCount());
+
+ // Check value we set
+ _config.setProperty("maximumMessageCount", 10L);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(10, serverConfig.getMaximumMessageCount());
+ }
+
+ public void testGetMaximumQueueDepth() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getMaximumQueueDepth());
+
+ // Check value we set
+ _config.setProperty("maximumQueueDepth", 10L);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(10, serverConfig.getMaximumQueueDepth());
+ }
+
+ public void testGetMaximumMessageSize() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getMaximumMessageSize());
+
+ // Check value we set
+ _config.setProperty("maximumMessageSize", 10L);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(10, serverConfig.getMaximumMessageSize());
+ }
+
+ public void testGetMinimumAlertRepeatGap() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(0, serverConfig.getMinimumAlertRepeatGap());
+
+ // Check value we set
+ _config.setProperty("minimumAlertRepeatGap", 10L);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(10, serverConfig.getMinimumAlertRepeatGap());
+ }
+
+ public void testGetProcessors() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(4, serverConfig.getProcessors());
+
+ // Check value we set
+ _config.setProperty("connector.processors", 10);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(10, serverConfig.getProcessors());
+ }
+
+ public void testGetPort() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(5672, serverConfig.getPort());
+
+ // Check value we set
+ _config.setProperty("connector.port", 10);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(10, serverConfig.getPort());
+ }
+
+ public void testGetBind() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals("wildcard", serverConfig.getBind());
+
+ // Check value we set
+ _config.setProperty("connector.bind", "a");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals("a", serverConfig.getBind());
+ }
+
+ public void testGetReceiveBufferSize() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(32767, serverConfig.getReceiveBufferSize());
+
+ // Check value we set
+ _config.setProperty("connector.socketReceiveBuffer", "23");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(23, serverConfig.getReceiveBufferSize());
+ }
+
+ public void testGetWriteBufferSize() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(32767, serverConfig.getWriteBufferSize());
+
+ // Check value we set
+ _config.setProperty("connector.socketWriteBuffer", "23");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(23, serverConfig.getWriteBufferSize());
+ }
+
+ public void testGetTcpNoDelay() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getTcpNoDelay());
+
+ // Check value we set
+ _config.setProperty("connector.tcpNoDelay", false);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getTcpNoDelay());
+ }
+
+ public void testGetEnableExecutorPool() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getEnableExecutorPool());
+
+ // Check value we set
+ _config.setProperty("advanced.filterchain[@enableExecutorPool]", true);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getEnableExecutorPool());
+ }
+
+ public void testGetEnablePooledAllocator() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getEnablePooledAllocator());
+
+ // Check value we set
+ _config.setProperty("advanced.enablePooledAllocator", true);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getEnablePooledAllocator());
+ }
+
+ public void testGetEnableDirectBuffers() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getEnableDirectBuffers());
+
+ // Check value we set
+ _config.setProperty("advanced.enableDirectBuffers", true);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getEnableDirectBuffers());
+ }
+
+ public void testGetEnableSSL() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getEnableSSL());
+
+ // Check value we set
+ _config.setProperty("connector.ssl.enabled", true);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getEnableSSL());
+ }
+
+ public void testGetSSLOnly() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getSSLOnly());
+
+ // Check value we set
+ _config.setProperty("connector.ssl.sslOnly", false);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getSSLOnly());
+ }
+
+ public void testGetSSLPort() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(8672, serverConfig.getSSLPort());
+
+ // Check value we set
+ _config.setProperty("connector.ssl.port", 23);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(23, serverConfig.getSSLPort());
+ }
+
+ public void testGetKeystorePath() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals("none", serverConfig.getKeystorePath());
+
+ // Check value we set
+ _config.setProperty("connector.ssl.keystorePath", "a");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals("a", serverConfig.getKeystorePath());
+ }
+
+ public void testGetKeystorePassword() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals("none", serverConfig.getKeystorePassword());
+
+ // Check value we set
+ _config.setProperty("connector.ssl.keystorePassword", "a");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals("a", serverConfig.getKeystorePassword());
+ }
+
+ public void testGetCertType() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals("SunX509", serverConfig.getCertType());
+
+ // Check value we set
+ _config.setProperty("connector.ssl.certType", "a");
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals("a", serverConfig.getCertType());
+ }
+
+ public void testGetQpidNIO() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getQpidNIO());
+
+ // Check value we set
+ _config.setProperty("connector.qpidnio", true);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getQpidNIO());
+ }
+
+ public void testGetUseBiasedWrites() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(false, serverConfig.getUseBiasedWrites());
+
+ // Check value we set
+ _config.setProperty("advanced.useWriteBiasedPool", true);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(true, serverConfig.getUseBiasedWrites());
+ }
+
+ public void testGetHousekeepingExpiredMessageCheckPeriod() throws ConfigurationException
+ {
+ // Check default
+ ServerConfiguration serverConfig = new ServerConfiguration(_config);
+ assertEquals(30000, serverConfig.getHousekeepingCheckPeriod());
+
+ // Check value we set
+ _config.setProperty("housekeeping.expiredMessageCheckPeriod", 23L);
+ serverConfig = new ServerConfiguration(_config);
+ assertEquals(23, serverConfig.getHousekeepingCheckPeriod());
+ serverConfig.setHousekeepingExpiredMessageCheckPeriod(42L);
+ assertEquals(42, serverConfig.getHousekeepingCheckPeriod());
+ }
+
+ public void testSingleConfiguration() throws IOException, ConfigurationException
+ {
+ File fileA = File.createTempFile(getClass().getName(), null);
+ fileA.deleteOnExit();
+ FileWriter out = new FileWriter(fileA);
+ out.write("<broker><connector><port>2342</port><ssl><port>4235</port></ssl></connector></broker>");
+ out.close();
+ ServerConfiguration conf = new ServerConfiguration(fileA);
+ assertEquals(4235, conf.getSSLPort());
+ }
+
+ public void testCombinedConfiguration() throws IOException, ConfigurationException
+ {
+ File mainFile = File.createTempFile(getClass().getName(), null);
+ File fileA = File.createTempFile(getClass().getName(), null);
+ File fileB = File.createTempFile(getClass().getName(), null);
+
+ mainFile.deleteOnExit();
+ fileA.deleteOnExit();
+ fileB.deleteOnExit();
+
+ FileWriter out = new FileWriter(mainFile);
+ out.write("<configuration><system/>");
+ out.write("<xml fileName=\"" + fileA.getAbsolutePath() + "\"/>");
+ out.write("<xml fileName=\"" + fileB.getAbsolutePath() + "\"/>");
+ out.write("</configuration>");
+ out.close();
+
+ out = new FileWriter(fileA);
+ out.write("<broker><connector><port>2342</port><ssl><port>4235</port></ssl></connector></broker>");
+ out.close();
+
+ out = new FileWriter(fileB);
+ out.write("<broker><connector><ssl><port>2345</port></ssl><qpidnio>true</qpidnio></connector></broker>");
+ out.close();
+
+ ServerConfiguration config = new ServerConfiguration(mainFile.getAbsoluteFile());
+ assertEquals(4235, config.getSSLPort()); // From first file, not
+ // overriden by second
+ assertEquals(2342, config.getPort()); // From the first file, not
+ // present in the second
+ assertEquals(true, config.getQpidNIO()); // From the second file, not
+ // present in the first
+ }
+
+ public void testVariableInterpolation() throws Exception
+ {
+ File mainFile = File.createTempFile(getClass().getName(), null);
+
+ mainFile.deleteOnExit();
+
+ FileWriter out = new FileWriter(mainFile);
+ out.write("<broker>\n");
+ out.write("\t<work>foo</work>\n");
+ out.write("\t<management><ssl><keyStorePath>${work}</keyStorePath></ssl></management>\n");
+ out.write("</broker>\n");
+ out.close();
+
+ ServerConfiguration config = new ServerConfiguration(mainFile.getAbsoluteFile());
+ assertEquals("Did not get correct interpolated value",
+ "foo", config.getManagementKeyStorePath());
+ }
+
+ public void testCombinedConfigurationFirewall() throws Exception
+ {
+ // Write out config
+ File mainFile = File.createTempFile(getClass().getName(), null);
+ File fileA = File.createTempFile(getClass().getName(), null);
+ File fileB = File.createTempFile(getClass().getName(), null);
+
+ mainFile.deleteOnExit();
+ fileA.deleteOnExit();
+ fileB.deleteOnExit();
+
+ FileWriter out = new FileWriter(mainFile);
+ out.write("<configuration><system/>");
+ out.write("<xml fileName=\"" + fileA.getAbsolutePath() + "\"/>");
+ out.write("</configuration>");
+ out.close();
+
+ out = new FileWriter(fileA);
+ out.write("<broker>\n");
+ out.write("\t<management><enabled>false</enabled></management>\n");
+ out.write("\t<security>\n");
+ out.write("\t\t<principal-databases>\n");
+ out.write("\t\t\t<principal-database>\n");
+ out.write("\t\t\t\t<name>passwordfile</name>\n");
+ out.write("\t\t\t\t<class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>\n");
+ out.write("\t\t\t\t<attributes>\n");
+ out.write("\t\t\t\t\t<attribute>\n");
+ out.write("\t\t\t\t\t\t<name>passwordFile</name>\n");
+ out.write("\t\t\t\t\t\t<value>/dev/null</value>\n");
+ out.write("\t\t\t\t\t</attribute>\n");
+ out.write("\t\t\t\t</attributes>\n");
+ out.write("\t\t\t</principal-database>\n");
+ out.write("\t\t</principal-databases>\n");
+ out.write("\t\t<jmx>\n");
+ out.write("\t\t\t<access>/dev/null</access>\n");
+ out.write("\t\t\t<principal-database>passwordfile</principal-database>\n");
+ out.write("\t\t</jmx>\n");
+ out.write("\t\t<firewall>\n");
+ out.write("\t\t\t<xml fileName=\"" + fileB.getAbsolutePath() + "\"/>");
+ out.write("\t\t</firewall>\n");
+ out.write("\t</security>\n");
+ out.write("\t<virtualhosts>\n");
+ out.write("\t\t<virtualhost>\n");
+ out.write("\t\t\t<name>test</name>\n");
+ out.write("\t\t</virtualhost>\n");
+ out.write("\t</virtualhosts>\n");
+ out.write("</broker>\n");
+ out.close();
+
+ out = new FileWriter(fileB);
+ out.write("<firewall>\n");
+ out.write("\t<rule access=\"deny\" network=\"127.0.0.1\"/>");
+ out.write("</firewall>\n");
+ out.close();
+
+ // Load config
+ ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile);
+ ApplicationRegistry.initialise(reg, 1);
+
+ // Test config
+ TestIoSession iosession = new TestIoSession();
+ iosession.setAddress("127.0.0.1");
+ VirtualHostRegistry virtualHostRegistry = reg.getVirtualHostRegistry();
+ VirtualHost virtualHost = virtualHostRegistry.getVirtualHost("test");
+ AMQCodecFactory codecFactory = new AMQCodecFactory(true);
+ AMQProtocolSession session = new AMQMinaProtocolSession(iosession, virtualHostRegistry, codecFactory);
+ assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost));
+ }
+
+ public void testCombinedConfigurationFirewallReload() throws Exception
+ {
+ // Write out config
+ File mainFile = File.createTempFile(getClass().getName(), null);
+ File fileA = File.createTempFile(getClass().getName(), null);
+ File fileB = File.createTempFile(getClass().getName(), null);
+
+ mainFile.deleteOnExit();
+ fileA.deleteOnExit();
+ fileB.deleteOnExit();
+
+ FileWriter out = new FileWriter(mainFile);
+ out.write("<configuration><system/>");
+ out.write("<xml fileName=\"" + fileA.getAbsolutePath() + "\"/>");
+ out.write("</configuration>");
+ out.close();
+
+ out = new FileWriter(fileA);
+ out.write("<broker>\n");
+ out.write("\t<management><enabled>false</enabled></management>\n");
+ out.write("\t<security>\n");
+ out.write("\t\t<principal-databases>\n");
+ out.write("\t\t\t<principal-database>\n");
+ out.write("\t\t\t\t<name>passwordfile</name>\n");
+ out.write("\t\t\t\t<class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>\n");
+ out.write("\t\t\t\t<attributes>\n");
+ out.write("\t\t\t\t\t<attribute>\n");
+ out.write("\t\t\t\t\t\t<name>passwordFile</name>\n");
+ out.write("\t\t\t\t\t\t<value>/dev/null</value>\n");
+ out.write("\t\t\t\t\t</attribute>\n");
+ out.write("\t\t\t\t</attributes>\n");
+ out.write("\t\t\t</principal-database>\n");
+ out.write("\t\t</principal-databases>\n");
+ out.write("\t\t<jmx>\n");
+ out.write("\t\t\t<access>/dev/null</access>\n");
+ out.write("\t\t\t<principal-database>passwordfile</principal-database>\n");
+ out.write("\t\t</jmx>\n");
+ out.write("\t\t<firewall>\n");
+ out.write("\t\t\t<xml fileName=\"" + fileB.getAbsolutePath() + "\"/>");
+ out.write("\t\t</firewall>\n");
+ out.write("\t</security>\n");
+ out.write("\t<virtualhosts>\n");
+ out.write("\t\t<virtualhost>\n");
+ out.write("\t\t\t<name>test</name>\n");
+ out.write("\t\t</virtualhost>\n");
+ out.write("\t</virtualhosts>\n");
+ out.write("</broker>\n");
+ out.close();
+
+ out = new FileWriter(fileB);
+ out.write("<firewall>\n");
+ out.write("\t<rule access=\"deny\" network=\"127.0.0.1\"/>");
+ out.write("</firewall>\n");
+ out.close();
+
+ // Load config
+ ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile);
+ ApplicationRegistry.initialise(reg, 1);
+
+ // Test config
+ TestIoSession iosession = new TestIoSession();
+ iosession.setAddress("127.0.0.1");
+ VirtualHostRegistry virtualHostRegistry = reg.getVirtualHostRegistry();
+ VirtualHost virtualHost = virtualHostRegistry.getVirtualHost("test");
+ AMQCodecFactory codecFactory = new AMQCodecFactory(true);
+ AMQProtocolSession session = new AMQMinaProtocolSession(iosession, virtualHostRegistry, codecFactory);
+ assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost));
+
+ RandomAccessFile fileBRandom = new RandomAccessFile(fileB, "rw");
+ fileBRandom.setLength(0);
+ fileBRandom.seek(0);
+ fileBRandom.close();
+
+ out = new FileWriter(fileB);
+ out.write("<firewall>\n");
+ out.write("\t<rule access=\"allow\" network=\"127.0.0.1\"/>");
+ out.write("</firewall>\n");
+ out.close();
+
+ reg.getConfiguration().reparseConfigFile();
+
+ assertTrue(reg.getAccessManager().authoriseConnect(session, virtualHost));
+
+ fileBRandom = new RandomAccessFile(fileB, "rw");
+ fileBRandom.setLength(0);
+ fileBRandom.seek(0);
+ fileBRandom.close();
+
+ out = new FileWriter(fileB);
+ out.write("<firewall>\n");
+ out.write("\t<rule access=\"deny\" network=\"127.0.0.1\"/>");
+ out.write("</firewall>\n");
+ out.close();
+
+ reg.getConfiguration().reparseConfigFile();
+
+ assertFalse(reg.getAccessManager().authoriseConnect(session, virtualHost));
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/configuration/TestPropertyUtils.java b/java/broker/src/test/java/org/apache/qpid/server/configuration/TestPropertyUtils.java
new file mode 100644
index 0000000000..3b83190e42
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/configuration/TestPropertyUtils.java
@@ -0,0 +1,50 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.configuration;
+
+import org.apache.qpid.configuration.PropertyException;
+import org.apache.qpid.configuration.PropertyUtils;
+
+import junit.framework.TestCase;
+
+// TODO: This belongs in the "common" module.
+public class TestPropertyUtils extends TestCase
+{
+ public void testSimpleExpansion() throws PropertyException
+ {
+ System.setProperty("banana", "fruity");
+ String expandedProperty = PropertyUtils.replaceProperties("${banana}");
+ assertEquals(expandedProperty, "fruity");
+ }
+
+ public void testDualExpansion() throws PropertyException
+ {
+ System.setProperty("banana", "fruity");
+ System.setProperty("concrete", "horrible");
+ String expandedProperty = PropertyUtils.replaceProperties("${banana}xyz${concrete}");
+ assertEquals(expandedProperty, "fruityxyzhorrible");
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(TestPropertyUtils.class);
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java b/java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java
new file mode 100644
index 0000000000..ba504d3064
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/configuration/VirtualHostConfigurationTest.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.configuration;
+
+
+import junit.framework.TestCase;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.queue.AMQPriorityQueue;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+public class VirtualHostConfigurationTest extends TestCase
+{
+
+ private VirtualHostConfiguration vhostConfig;
+ private XMLConfiguration configXml;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ // Fill config file with stuff
+ configXml = new XMLConfiguration();
+ configXml.setRootElementName("virtualhosts");
+ configXml.addProperty("virtualhost(-1).name", "test");
+ }
+
+ public void testQueuePriority() throws Exception
+ {
+ // Set up queue with 5 priorities
+ configXml.addProperty("virtualhost.test.queues(-1).queue(-1).name(-1)",
+ "atest");
+ configXml.addProperty("virtualhost.test.queues.queue.atest(-1).exchange",
+ "amq.direct");
+ configXml.addProperty("virtualhost.test.queues.queue.atest.priorities",
+ "5");
+
+ // Set up queue with JMS style priorities
+ configXml.addProperty("virtualhost.test.queues(-1).queue(-1).name(-1)",
+ "ptest");
+ configXml.addProperty("virtualhost.test.queues.queue.ptest(-1).exchange",
+ "amq.direct");
+ configXml.addProperty("virtualhost.test.queues.queue.ptest.priority",
+ "true");
+
+ // Set up queue with no priorities
+ configXml.addProperty("virtualhost.test.queues(-1).queue(-1).name(-1)",
+ "ntest");
+ configXml.addProperty("virtualhost.test.queues.queue.ntest(-1).exchange",
+ "amq.direct");
+ configXml.addProperty("virtualhost.test.queues.queue.ntest.priority",
+ "false");
+
+ VirtualHost vhost = new VirtualHost(new VirtualHostConfiguration("test", configXml.subset("virtualhost.test")));
+
+ // Check that atest was a priority queue with 5 priorities
+ AMQQueue atest = vhost.getQueueRegistry().getQueue(new AMQShortString("atest"));
+ assertTrue(atest instanceof AMQPriorityQueue);
+ assertEquals(5, ((AMQPriorityQueue) atest).getPriorities());
+
+ // Check that ptest was a priority queue with 10 priorities
+ AMQQueue ptest = vhost.getQueueRegistry().getQueue(new AMQShortString("ptest"));
+ assertTrue(ptest instanceof AMQPriorityQueue);
+ assertEquals(10, ((AMQPriorityQueue) ptest).getPriorities());
+
+ // Check that ntest wasn't a priority queue
+ AMQQueue ntest = vhost.getQueueRegistry().getQueue(new AMQShortString("ntest"));
+ assertFalse(ntest instanceof AMQPriorityQueue);
+ }
+
+ public void testQueueAlerts() throws Exception
+ {
+ // Set up queue with 5 priorities
+ configXml.addProperty("virtualhost.test.queues.exchange", "amq.topic");
+ configXml.addProperty("virtualhost.test.queues.maximumQueueDepth", "1");
+ configXml.addProperty("virtualhost.test.queues.maximumMessageSize", "2");
+ configXml.addProperty("virtualhost.test.queues.maximumMessageAge", "3");
+
+ configXml.addProperty("virtualhost.test.queues(-1).queue(1).name(1)", "atest");
+ configXml.addProperty("virtualhost.test.queues.queue.atest(-1).exchange", "amq.direct");
+ configXml.addProperty("virtualhost.test.queues.queue.atest(-1).maximumQueueDepth", "4");
+ configXml.addProperty("virtualhost.test.queues.queue.atest(-1).maximumMessageSize", "5");
+ configXml.addProperty("virtualhost.test.queues.queue.atest(-1).maximumMessageAge", "6");
+
+ configXml.addProperty("virtualhost.test.queues(-1).queue(-1).name(-1)", "btest");
+
+ VirtualHost vhost = new VirtualHost(new VirtualHostConfiguration("test", configXml.subset("virtualhost.test")));
+
+ // Check specifically configured values
+ AMQQueue aTest = vhost.getQueueRegistry().getQueue(new AMQShortString("atest"));
+ assertEquals(4, aTest.getMaximumQueueDepth());
+ assertEquals(5, aTest.getMaximumMessageSize());
+ assertEquals(6, aTest.getMaximumMessageAge());
+
+ // Check default values
+ AMQQueue bTest = vhost.getQueueRegistry().getQueue(new AMQShortString("btest"));
+ assertEquals(1, bTest.getMaximumQueueDepth());
+ assertEquals(2, bTest.getMaximumMessageSize());
+ assertEquals(3, bTest.getMaximumMessageAge());
+
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java b/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java
new file mode 100644
index 0000000000..6dcb187a37
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java
@@ -0,0 +1,562 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.exchange;
+
+import junit.framework.TestCase;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.server.queue.*;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.SkeletonMessageStore;
+import org.apache.qpid.server.store.MemoryMessageStore;
+import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.txn.NonTransactionalContext;
+import org.apache.qpid.server.txn.TransactionalContext;
+import org.apache.qpid.server.RequiredDeliveryException;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.log4j.Logger;
+
+import java.util.*;
+
+public class AbstractHeadersExchangeTestBase extends TestCase
+{
+ private static final Logger _log = Logger.getLogger(AbstractHeadersExchangeTestBase.class);
+
+ private final HeadersExchange exchange = new HeadersExchange();
+ protected final Set<TestQueue> queues = new HashSet<TestQueue>();
+
+ /**
+ * Not used in this test, just there to stub out the routing calls
+ */
+ private MessageStore _store = new MemoryMessageStore();
+
+ private StoreContext _storeContext = new StoreContext();
+
+ private MessageHandleFactory _handleFactory = new MessageHandleFactory();
+
+ private int count;
+
+ public void testDoNothing()
+ {
+ // this is here only to make junit under Eclipse happy
+ }
+
+ protected TestQueue bindDefault(String... bindings) throws AMQException
+ {
+ return bind("Queue" + (++count), bindings);
+ }
+
+ protected TestQueue bind(String queueName, String... bindings) throws AMQException
+ {
+ return bind(queueName, getHeaders(bindings));
+ }
+
+ protected TestQueue bind(String queue, FieldTable bindings) throws AMQException
+ {
+ return bind(new TestQueue(new AMQShortString(queue)), bindings);
+ }
+
+ protected TestQueue bind(TestQueue queue, String... bindings) throws AMQException
+ {
+ return bind(queue, getHeaders(bindings));
+ }
+
+ protected TestQueue bind(TestQueue queue, FieldTable bindings) throws AMQException
+ {
+ queues.add(queue);
+ exchange.registerQueue(null, queue, bindings);
+ return queue;
+ }
+
+
+ protected void route(Message m) throws AMQException
+ {
+ m.route(exchange);
+ m.getIncomingMessage().routingComplete(_store, _handleFactory);
+ if(m.getIncomingMessage().allContentReceived())
+ {
+ m.getIncomingMessage().deliverToQueues();
+ }
+ }
+
+ protected void routeAndTest(Message m, TestQueue... expected) throws AMQException
+ {
+ routeAndTest(m, false, Arrays.asList(expected));
+ }
+
+ protected void routeAndTest(Message m, boolean expectReturn, TestQueue... expected) throws AMQException
+ {
+ routeAndTest(m, expectReturn, Arrays.asList(expected));
+ }
+
+ protected void routeAndTest(Message m, List<TestQueue> expected) throws AMQException
+ {
+ routeAndTest(m, false, expected);
+ }
+
+ protected void routeAndTest(Message m, boolean expectReturn, List<TestQueue> expected) throws AMQException
+ {
+ try
+ {
+ route(m);
+ assertFalse("Expected "+m+" to be returned due to manadatory flag, and lack of routing",expectReturn);
+ for (TestQueue q : queues)
+ {
+ if (expected.contains(q))
+ {
+ assertTrue("Expected " + m + " to be delivered to " + q, q.isInQueue(m));
+ //assert m.isInQueue(q) : "Expected " + m + " to be delivered to " + q;
+ }
+ else
+ {
+ assertFalse("Did not expect " + m + " to be delivered to " + q, q.isInQueue(m));
+ //assert !m.isInQueue(q) : "Did not expect " + m + " to be delivered to " + q;
+ }
+ }
+ }
+
+ catch (NoRouteException ex)
+ {
+ assertTrue("Expected "+m+" not to be returned",expectReturn);
+ }
+
+ }
+
+ static FieldTable getHeaders(String... entries)
+ {
+ FieldTable headers = FieldTableFactory.newFieldTable();
+ for (String s : entries)
+ {
+ String[] parts = s.split("=", 2);
+ headers.setObject(parts[0], parts.length > 1 ? parts[1] : "");
+ }
+ return headers;
+ }
+
+
+ static final class MessagePublishInfoImpl implements MessagePublishInfo
+ {
+ private AMQShortString _exchange;
+ private boolean _immediate;
+ private boolean _mandatory;
+ private AMQShortString _routingKey;
+
+ public MessagePublishInfoImpl(AMQShortString routingKey)
+ {
+ _routingKey = routingKey;
+ }
+
+ public MessagePublishInfoImpl(AMQShortString exchange, boolean immediate, boolean mandatory, AMQShortString routingKey)
+ {
+ _exchange = exchange;
+ _immediate = immediate;
+ _mandatory = mandatory;
+ _routingKey = routingKey;
+ }
+
+ public AMQShortString getExchange()
+ {
+ return _exchange;
+ }
+
+ public boolean isImmediate()
+ {
+ return _immediate;
+
+ }
+
+ public boolean isMandatory()
+ {
+ return _mandatory;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return _routingKey;
+ }
+
+
+ public void setExchange(AMQShortString exchange)
+ {
+ _exchange = exchange;
+ }
+
+ public void setImmediate(boolean immediate)
+ {
+ _immediate = immediate;
+ }
+
+ public void setMandatory(boolean mandatory)
+ {
+ _mandatory = mandatory;
+ }
+
+ public void setRoutingKey(AMQShortString routingKey)
+ {
+ _routingKey = routingKey;
+ }
+ }
+
+ static MessagePublishInfo getPublishRequest(final String id)
+ {
+ return new MessagePublishInfoImpl(null, false, false, new AMQShortString(id));
+ }
+
+ static ContentHeaderBody getContentHeader(FieldTable headers)
+ {
+ ContentHeaderBody header = new ContentHeaderBody();
+ header.properties = getProperties(headers);
+ return header;
+ }
+
+ static BasicContentHeaderProperties getProperties(FieldTable headers)
+ {
+ BasicContentHeaderProperties properties = new BasicContentHeaderProperties();
+ properties.setHeaders(headers);
+ return properties;
+ }
+
+ static class TestQueue extends SimpleAMQQueue
+ {
+ final List<HeadersExchangeTest.Message> messages = new ArrayList<HeadersExchangeTest.Message>();
+
+ public TestQueue(AMQShortString name) throws AMQException
+ {
+ super(name, false, new AMQShortString("test"), true, ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test"));
+ ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test").getQueueRegistry().registerQueue(this);
+ }
+
+ /**
+ * We override this method so that the default behaviour, which attempts to use a delivery manager, is
+ * not invoked. It is unnecessary since for this test we only care to know whether the message was
+ * sent to the queue; the queue processing logic is not being tested.
+ * @param msg
+ * @throws AMQException
+ */
+ @Override
+ public QueueEntry enqueue(StoreContext context, AMQMessage msg) throws AMQException
+ {
+ messages.add( new HeadersExchangeTest.Message(msg));
+ return new QueueEntry()
+ {
+
+ public AMQQueue getQueue()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public AMQMessage getMessage()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getSize()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean getDeliveredToConsumer()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean expired() throws AMQException
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isAcquired()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean acquire()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean acquire(Subscription sub)
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean delete()
+ {
+ return false;
+ }
+
+ public boolean isDeleted()
+ {
+ return false;
+ }
+
+ public boolean acquiredBySubscription()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setDeliveredToSubscription()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void release()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public String debugIdentity()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean immediateAndNotDelivered()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setRedelivered(boolean b)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Subscription getDeliveredSubscription()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void reject()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void reject(Subscription subscription)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isRejectedBy(Subscription subscription)
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void requeue(StoreContext storeContext) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void dequeue(final StoreContext storeContext) throws FailedDequeueException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void dispose(final StoreContext storeContext) throws MessageCleanupException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void restoreCredit()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isQueueDeleted()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void addStateChangeListener(StateChangeListener listener)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean removeStateChangeListener(StateChangeListener listener)
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int compareTo(final QueueEntry o)
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+ };
+ }
+
+ boolean isInQueue(Message msg)
+ {
+ return messages.contains(msg);
+ }
+
+ }
+
+ /**
+ * Just add some extra utility methods to AMQMessage to aid testing.
+ */
+ static class Message extends AMQMessage
+ {
+ private class TestIncomingMessage extends IncomingMessage
+ {
+
+ public TestIncomingMessage(final long messageId,
+ final MessagePublishInfo info,
+ final TransactionalContext txnContext,
+ final AMQProtocolSession publisher)
+ {
+ super(messageId, info, txnContext, publisher);
+ }
+
+
+ public AMQMessage getUnderlyingMessage()
+ {
+ return Message.this;
+ }
+
+
+ public ContentHeaderBody getContentHeaderBody()
+ {
+ try
+ {
+ return Message.this.getContentHeaderBody();
+ }
+ catch (AMQException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private IncomingMessage _incoming;
+
+ private static MessageStore _messageStore = new SkeletonMessageStore();
+
+ private static StoreContext _storeContext = new StoreContext();
+
+
+ private static TransactionalContext _txnContext = new NonTransactionalContext(_messageStore, _storeContext,
+ null,
+ new LinkedList<RequiredDeliveryException>()
+ );
+
+ Message(String id, String... headers) throws AMQException
+ {
+ this(id, getHeaders(headers));
+ }
+
+ Message(String id, FieldTable headers) throws AMQException
+ {
+ this(_messageStore.getNewMessageId(),getPublishRequest(id), getContentHeader(headers), null);
+ }
+
+ public IncomingMessage getIncomingMessage()
+ {
+ return _incoming;
+ }
+
+ private Message(long messageId,
+ MessagePublishInfo publish,
+ ContentHeaderBody header,
+ List<ContentBody> bodies) throws AMQException
+ {
+ super(createMessageHandle(messageId, publish, header), _txnContext.getStoreContext(), publish);
+
+
+
+ _incoming = new TestIncomingMessage(getMessageId(),publish,_txnContext,new MockProtocolSession(_messageStore));
+ _incoming.setContentHeaderBody(header);
+
+
+ }
+
+ private static AMQMessageHandle createMessageHandle(final long messageId,
+ final MessagePublishInfo publish,
+ final ContentHeaderBody header)
+ {
+
+ final AMQMessageHandle amqMessageHandle = (new MessageHandleFactory()).createMessageHandle(messageId,
+ _messageStore,
+ true);
+
+ try
+ {
+ amqMessageHandle.setPublishAndContentHeaderBody(new StoreContext(),publish,header);
+ }
+ catch (AMQException e)
+ {
+
+ }
+ return amqMessageHandle;
+ }
+
+ private Message(AMQMessage msg) throws AMQException
+ {
+ super(msg);
+ }
+
+
+
+ void route(Exchange exchange) throws AMQException
+ {
+ exchange.route(_incoming);
+ }
+
+
+ public int hashCode()
+ {
+ return getKey().hashCode();
+ }
+
+ public boolean equals(Object o)
+ {
+ return o instanceof HeadersExchangeTest.Message && equals((HeadersExchangeTest.Message) o);
+ }
+
+ private boolean equals(HeadersExchangeTest.Message m)
+ {
+ return getKey().equals(m.getKey());
+ }
+
+ public String toString()
+ {
+ return getKey().toString();
+ }
+
+ private Object getKey()
+ {
+ try
+ {
+ return getMessagePublishInfo().getRoutingKey();
+ }
+ catch (AMQException e)
+ {
+ _log.error("Error getting routing key: " + e, e);
+ return null;
+ }
+ }
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/exchange/DestWildExchangeTest.java b/java/broker/src/test/java/org/apache/qpid/server/exchange/DestWildExchangeTest.java
new file mode 100644
index 0000000000..aa25e207a9
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/exchange/DestWildExchangeTest.java
@@ -0,0 +1,595 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.exchange;
+
+import junit.framework.TestCase;
+import junit.framework.Assert;
+import org.apache.qpid.server.queue.*;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.txn.NonTransactionalContext;
+import org.apache.qpid.server.txn.TransactionalContext;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.MemoryMessageStore;
+import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.RequiredDeliveryException;
+import org.apache.qpid.server.protocol.InternalTestProtocolSession;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+
+import java.util.LinkedList;
+
+public class DestWildExchangeTest extends TestCase
+{
+
+ TopicExchange _exchange;
+
+ VirtualHost _vhost;
+ MessageStore _store;
+ StoreContext _context;
+
+ InternalTestProtocolSession _protocolSession;
+
+
+ public void setUp() throws AMQException
+ {
+ _exchange = new TopicExchange();
+ _vhost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHosts().iterator().next();
+ _store = new MemoryMessageStore();
+ _context = new StoreContext();
+ _protocolSession = new InternalTestProtocolSession();
+ }
+
+ public void tearDown()
+ {
+ ApplicationRegistry.remove(1);
+ }
+
+
+ public void testNoRoute() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a*#b"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.*.#.b"), queue, null);
+
+
+ MessagePublishInfo info = new PublishInfo(new AMQShortString("a.b"));
+
+ IncomingMessage message = new IncomingMessage(0L, info, null, _protocolSession);
+
+ _exchange.route(message);
+
+ Assert.assertEquals(0, queue.getMessageCount());
+ }
+
+ public void testDirectMatch() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("ab"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.b"), queue, null);
+
+
+ IncomingMessage message = createMessage("a.b");
+
+ try
+ {
+ routeMessage(message);
+ }
+ catch (AMQException nre)
+ {
+ fail("Message has route and should be routed");
+ }
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
+
+ queue.deleteMessageFromTop(_context);
+ Assert.assertEquals(0, queue.getMessageCount());
+
+
+ message = createMessage("a.c");
+
+ try
+ {
+ routeMessage(message);
+ fail("Message has no route and should fail to be routed");
+ }
+ catch (AMQException nre)
+ {
+ }
+
+ Assert.assertEquals(0, queue.getMessageCount());
+ }
+
+
+ public void testStarMatch() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a*"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.*"), queue, null);
+
+
+ IncomingMessage message = createMessage("a.b");
+
+ try
+ {
+ routeMessage(message);
+ }
+ catch (AMQException nre)
+ {
+ fail("Message has route and should be routed");
+ }
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
+
+ queue.deleteMessageFromTop(_context);
+ Assert.assertEquals(0, queue.getMessageCount());
+
+
+ message = createMessage("a.c");
+
+ try
+ {
+ routeMessage(message);
+ }
+ catch (AMQException nre)
+ {
+ fail("Message has route and should be routed");
+ }
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
+
+ queue.deleteMessageFromTop(_context);
+ Assert.assertEquals(0, queue.getMessageCount());
+
+
+ message = createMessage("a");
+
+ try
+ {
+ routeMessage(message);
+ fail("Message has no route and should fail to be routed");
+ }
+ catch (AMQException nre)
+ {
+ }
+
+ Assert.assertEquals(0, queue.getMessageCount());
+ }
+
+ public void testHashMatch() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.#"), queue, null);
+
+
+ IncomingMessage message = createMessage("a.b.c");
+
+ try
+ {
+ routeMessage(message);
+ }
+ catch (AMQException nre)
+ {
+ fail("Message has route and should be routed");
+ }
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
+
+ queue.deleteMessageFromTop(_context);
+ Assert.assertEquals(0, queue.getMessageCount());
+
+
+ message = createMessage("a.b");
+
+ try
+ {
+ routeMessage(message);
+ }
+ catch (AMQException nre)
+ {
+ fail("Message has route and should be routed");
+ }
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
+
+ queue.deleteMessageFromTop(_context);
+ Assert.assertEquals(0, queue.getMessageCount());
+
+
+ message = createMessage("a.c");
+
+ try
+ {
+ routeMessage(message);
+ }
+ catch (AMQException nre)
+ {
+ fail("Message has route and should be routed");
+ }
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
+
+ queue.deleteMessageFromTop(_context);
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ message = createMessage("a");
+
+ try
+ {
+ routeMessage(message);
+ }
+ catch (AMQException nre)
+ {
+ fail("Message has route and should be routed");
+ }
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
+
+ queue.deleteMessageFromTop(_context);
+ Assert.assertEquals(0, queue.getMessageCount());
+
+
+ message = createMessage("b");
+
+ try
+ {
+ routeMessage(message);
+ fail("Message has no route and should fail to be routed");
+ }
+ catch (AMQException nre)
+ {
+ }
+
+ Assert.assertEquals(0, queue.getMessageCount());
+ }
+
+
+ public void testMidHash() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.*.#.b"), queue, null);
+
+
+ IncomingMessage message = createMessage("a.c.d.b");
+
+ try
+ {
+ routeMessage(message);
+ }
+ catch (AMQException nre)
+ {
+ fail("Message has no route and should be routed");
+ }
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
+
+ queue.deleteMessageFromTop(_context);
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ message = createMessage("a.c.b");
+
+ try
+ {
+ routeMessage(message);
+ }
+ catch (AMQException nre)
+ {
+ fail("Message has no route and should be routed");
+ }
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
+
+ queue.deleteMessageFromTop(_context);
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ }
+
+ public void testMatchafterHash() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.*.#.b.c"), queue, null);
+
+
+ IncomingMessage message = createMessage("a.c.b.b");
+
+ try
+ {
+ routeMessage(message);
+ fail("Message has route and should not be routed");
+ }
+ catch (AMQException nre)
+ {
+ }
+
+ Assert.assertEquals(0, queue.getMessageCount());
+
+
+ message = createMessage("a.a.b.c");
+
+ try
+ {
+ routeMessage(message);
+ }
+ catch (AMQException nre)
+ {
+ fail("Message has no route and should be routed");
+ }
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
+
+ queue.deleteMessageFromTop(_context);
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ message = createMessage("a.b.c.b");
+
+ try
+ {
+ routeMessage(message);
+ fail("Message has route and should not be routed");
+ }
+ catch (AMQException nre)
+ {
+ }
+
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ message = createMessage("a.b.c.b.c");
+
+ try
+ {
+ routeMessage(message);
+ }
+ catch (AMQException nre)
+ {
+ fail("Message has no route and should be routed");
+
+ }
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
+
+ queue.deleteMessageFromTop(_context);
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ }
+
+
+ public void testHashAfterHash() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.*.#.b.c.#.d"), queue, null);
+
+
+ IncomingMessage message = createMessage("a.c.b.b.c");
+
+ try
+ {
+ routeMessage(message);
+ fail("Message has route and should not be routed");
+ }
+ catch (AMQException nre)
+ {
+ }
+
+ Assert.assertEquals(0, queue.getMessageCount());
+
+
+ message = createMessage("a.a.b.c.d");
+
+ try
+ {
+ routeMessage(message);
+ }
+ catch (AMQException nre)
+ {
+ fail("Message has no route and should be routed");
+ }
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
+
+ queue.deleteMessageFromTop(_context);
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ }
+
+ public void testHashHash() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a#"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.#.*.#.d"), queue, null);
+
+
+ IncomingMessage message = createMessage("a.c.b.b.c");
+
+ try
+ {
+ routeMessage(message);
+ fail("Message has route and should not be routed");
+ }
+ catch (AMQException nre)
+ {
+ }
+
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ message = createMessage("a.a.b.c.d");
+
+ try
+ {
+ routeMessage(message);
+ }
+ catch (AMQException nre)
+ {
+ fail("Message has no route and should be routed");
+ }
+
+ Assert.assertEquals(1, queue.getMessageCount());
+
+ Assert.assertEquals("Wrong message recevied", (Object) message.getMessageId(), queue.getMessagesOnTheQueue().get(0).getMessage().getMessageId());
+
+ queue.deleteMessageFromTop(_context);
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ }
+
+ public void testSubMatchFails() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.b.c.d"), queue, null);
+
+
+ IncomingMessage message = createMessage("a.b.c");
+
+ try
+ {
+ routeMessage(message);
+ fail("Message has route and should not be routed");
+ }
+ catch (AMQException nre)
+ {
+ }
+
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ }
+
+ private void routeMessage(final IncomingMessage message)
+ throws AMQException
+ {
+ _exchange.route(message);
+ message.routingComplete(_store, new MessageHandleFactory());
+ message.deliverToQueues();
+ }
+
+ public void testMoreRouting() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.b"), queue, null);
+
+
+ IncomingMessage message = createMessage("a.b.c");
+
+ try
+ {
+ routeMessage(message);
+ fail("Message has route and should not be routed");
+ }
+ catch (AMQException nre)
+ {
+ }
+
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ }
+
+ public void testMoreQueue() throws AMQException
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("a"), false, null, false, _vhost, null);
+ _exchange.registerQueue(new AMQShortString("a.b"), queue, null);
+
+
+ IncomingMessage message = createMessage("a");
+
+ try
+ {
+ routeMessage(message);
+ fail("Message has route and should not be routed");
+ }
+ catch (AMQException nre)
+ {
+ }
+
+ Assert.assertEquals(0, queue.getMessageCount());
+
+ }
+
+ private IncomingMessage createMessage(String s) throws AMQException
+ {
+ MessagePublishInfo info = new PublishInfo(new AMQShortString(s));
+
+ TransactionalContext trancontext = new NonTransactionalContext(_store, _context, null,
+ new LinkedList<RequiredDeliveryException>()
+ );
+
+ IncomingMessage message = new IncomingMessage(0L, info, trancontext,_protocolSession);
+ message.setContentHeaderBody( new ContentHeaderBody());
+
+
+ return message;
+ }
+
+
+ class PublishInfo implements MessagePublishInfo
+ {
+ AMQShortString _routingkey;
+
+ PublishInfo(AMQShortString routingkey)
+ {
+ _routingkey = routingkey;
+ }
+
+ public AMQShortString getExchange()
+ {
+ return null;
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+
+ }
+
+ public boolean isImmediate()
+ {
+ return false;
+ }
+
+ public boolean isMandatory()
+ {
+ return true;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return _routingkey;
+ }
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java b/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java
new file mode 100644
index 0000000000..8ce7b4c0e1
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java
@@ -0,0 +1,145 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.exchange;
+
+import junit.framework.TestCase;
+import org.apache.qpid.server.queue.QueueRegistry;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.apache.qpid.server.management.ManagedObject;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.framing.AMQShortString;
+
+import javax.management.openmbean.TabularData;
+import java.util.ArrayList;
+
+/**
+ * Unit test class for testing different Exchange MBean operations
+ */
+public class ExchangeMBeanTest extends TestCase
+{
+ private AMQQueue _queue;
+ private QueueRegistry _queueRegistry;
+ private VirtualHost _virtualHost;
+
+ /**
+ * Test for direct exchange mbean
+ * @throws Exception
+ */
+
+ public void testDirectExchangeMBean() throws Exception
+ {
+ DirectExchange exchange = new DirectExchange();
+ exchange.initialise(_virtualHost, ExchangeDefaults.DIRECT_EXCHANGE_NAME, false, 0, true);
+ ManagedObject managedObj = exchange.getManagedObject();
+ ManagedExchange mbean = (ManagedExchange)managedObj;
+
+ mbean.createNewBinding(_queue.getName().toString(), "binding1");
+ mbean.createNewBinding(_queue.getName().toString(), "binding2");
+
+ TabularData data = mbean.bindings();
+ ArrayList<Object> list = new ArrayList<Object>(data.values());
+ assertTrue(list.size() == 2);
+
+ // test general exchange properties
+ assertEquals(mbean.getName(), "amq.direct");
+ assertEquals(mbean.getExchangeType(), "direct");
+ assertTrue(mbean.getTicketNo() == 0);
+ assertTrue(!mbean.isDurable());
+ assertTrue(mbean.isAutoDelete());
+ }
+
+ /**
+ * Test for "topic" exchange mbean
+ * @throws Exception
+ */
+
+ public void testTopicExchangeMBean() throws Exception
+ {
+ TopicExchange exchange = new TopicExchange();
+ exchange.initialise(_virtualHost,ExchangeDefaults.TOPIC_EXCHANGE_NAME, false, 0, true);
+ ManagedObject managedObj = exchange.getManagedObject();
+ ManagedExchange mbean = (ManagedExchange)managedObj;
+
+ mbean.createNewBinding(_queue.getName().toString(), "binding1");
+ mbean.createNewBinding(_queue.getName().toString(), "binding2");
+
+ TabularData data = mbean.bindings();
+ ArrayList<Object> list = new ArrayList<Object>(data.values());
+ assertTrue(list.size() == 2);
+
+ // test general exchange properties
+ assertEquals(mbean.getName(), "amq.topic");
+ assertEquals(mbean.getExchangeType(), "topic");
+ assertTrue(mbean.getTicketNo() == 0);
+ assertTrue(!mbean.isDurable());
+ assertTrue(mbean.isAutoDelete());
+ }
+
+ /**
+ * Test for "Headers" exchange mbean
+ * @throws Exception
+ */
+
+ public void testHeadersExchangeMBean() throws Exception
+ {
+ HeadersExchange exchange = new HeadersExchange();
+ exchange.initialise(_virtualHost,ExchangeDefaults.HEADERS_EXCHANGE_NAME, false, 0, true);
+ ManagedObject managedObj = exchange.getManagedObject();
+ ManagedExchange mbean = (ManagedExchange)managedObj;
+
+ mbean.createNewBinding(_queue.getName().toString(), "key1=binding1,key2=binding2");
+ mbean.createNewBinding(_queue.getName().toString(), "key3=binding3");
+
+ TabularData data = mbean.bindings();
+ ArrayList<Object> list = new ArrayList<Object>(data.values());
+ assertTrue(list.size() == 2);
+
+ // test general exchange properties
+ assertEquals(mbean.getName(), "amq.match");
+ assertEquals(mbean.getExchangeType(), "headers");
+ assertTrue(mbean.getTicketNo() == 0);
+ assertTrue(!mbean.isDurable());
+ assertTrue(mbean.isAutoDelete());
+ }
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ IApplicationRegistry applicationRegistry = ApplicationRegistry.getInstance(1);
+ _virtualHost = applicationRegistry.getVirtualHostRegistry().getVirtualHost("test");
+ _queueRegistry = _virtualHost.getQueueRegistry();
+ _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue"), false, new AMQShortString("ExchangeMBeanTest"), false, _virtualHost,
+ null);
+ _queueRegistry.registerQueue(_queue);
+ }
+
+ protected void tearDown()
+ {
+ ApplicationRegistry.remove(1);
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java b/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java
new file mode 100644
index 0000000000..86ba96bf5d
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java
@@ -0,0 +1,199 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.exchange;
+
+import java.util.Map;
+import java.util.HashMap;
+
+import junit.framework.TestCase;
+import org.apache.qpid.framing.FieldTable;
+
+/**
+ */
+public class HeadersBindingTest extends TestCase
+{
+ private FieldTable bindHeaders = new FieldTable();
+ private FieldTable matchHeaders = new FieldTable();
+
+ public void testDefault_1()
+ {
+ bindHeaders.setString("A", "Value of A");
+
+ matchHeaders.setString("A", "Value of A");
+
+ assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ }
+
+ public void testDefault_2()
+ {
+ bindHeaders.setString("A", "Value of A");
+
+ matchHeaders.setString("A", "Value of A");
+ matchHeaders.setString("B", "Value of B");
+
+ assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ }
+
+ public void testDefault_3()
+ {
+ bindHeaders.setString("A", "Value of A");
+
+ matchHeaders.setString("A", "Altered value of A");
+
+ assertFalse(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ }
+
+ public void testAll_1()
+ {
+ bindHeaders.setString("X-match", "all");
+ bindHeaders.setString("A", "Value of A");
+
+ matchHeaders.setString("A", "Value of A");
+
+ assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ }
+
+ public void testAll_2()
+ {
+ bindHeaders.setString("X-match", "all");
+ bindHeaders.setString("A", "Value of A");
+ bindHeaders.setString("B", "Value of B");
+
+ matchHeaders.setString("A", "Value of A");
+
+ assertFalse(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ }
+
+ public void testAll_3()
+ {
+ bindHeaders.setString("X-match", "all");
+ bindHeaders.setString("A", "Value of A");
+ bindHeaders.setString("B", "Value of B");
+
+ matchHeaders.setString("A", "Value of A");
+ matchHeaders.setString("B", "Value of B");
+
+ assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ }
+
+ public void testAll_4()
+ {
+ bindHeaders.setString("X-match", "all");
+ bindHeaders.setString("A", "Value of A");
+ bindHeaders.setString("B", "Value of B");
+
+ matchHeaders.setString("A", "Value of A");
+ matchHeaders.setString("B", "Value of B");
+ matchHeaders.setString("C", "Value of C");
+
+ assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ }
+
+ public void testAll_5()
+ {
+ bindHeaders.setString("X-match", "all");
+ bindHeaders.setString("A", "Value of A");
+ bindHeaders.setString("B", "Value of B");
+
+ matchHeaders.setString("A", "Value of A");
+ matchHeaders.setString("B", "Altered value of B");
+ matchHeaders.setString("C", "Value of C");
+
+ assertFalse(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ }
+
+ public void testAny_1()
+ {
+ bindHeaders.setString("X-match", "any");
+ bindHeaders.setString("A", "Value of A");
+
+ matchHeaders.setString("A", "Value of A");
+
+ assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ }
+
+ public void testAny_2()
+ {
+ bindHeaders.setString("X-match", "any");
+ bindHeaders.setString("A", "Value of A");
+ bindHeaders.setString("B", "Value of B");
+
+ matchHeaders.setString("A", "Value of A");
+
+ assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ }
+
+ public void testAny_3()
+ {
+ bindHeaders.setString("X-match", "any");
+ bindHeaders.setString("A", "Value of A");
+ bindHeaders.setString("B", "Value of B");
+
+ matchHeaders.setString("A", "Value of A");
+ matchHeaders.setString("B", "Value of B");
+
+ assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ }
+
+ public void testAny_4()
+ {
+ bindHeaders.setString("X-match", "any");
+ bindHeaders.setString("A", "Value of A");
+ bindHeaders.setString("B", "Value of B");
+
+ matchHeaders.setString("A", "Value of A");
+ matchHeaders.setString("B", "Value of B");
+ matchHeaders.setString("C", "Value of C");
+
+ assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ }
+
+ public void testAny_5()
+ {
+ bindHeaders.setString("X-match", "any");
+ bindHeaders.setString("A", "Value of A");
+ bindHeaders.setString("B", "Value of B");
+
+ matchHeaders.setString("A", "Value of A");
+ matchHeaders.setString("B", "Altered value of B");
+ matchHeaders.setString("C", "Value of C");
+
+ assertTrue(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ }
+
+ public void testAny_6()
+ {
+ bindHeaders.setString("X-match", "any");
+ bindHeaders.setString("A", "Value of A");
+ bindHeaders.setString("B", "Value of B");
+
+ matchHeaders.setString("A", "Altered value of A");
+ matchHeaders.setString("B", "Altered value of B");
+ matchHeaders.setString("C", "Value of C");
+
+ assertFalse(new HeadersBinding(bindHeaders).matches(matchHeaders));
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(HeadersBindingTest.class);
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java b/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java
new file mode 100644
index 0000000000..fd11ddeae2
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersExchangeTest.java
@@ -0,0 +1,106 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.exchange;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.util.NullApplicationRegistry;
+import org.apache.qpid.framing.BasicPublishBody;
+
+public class HeadersExchangeTest extends AbstractHeadersExchangeTestBase
+{
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ ApplicationRegistry.initialise(new NullApplicationRegistry(), 1);
+ }
+
+ protected void tearDown()
+ {
+ ApplicationRegistry.remove(1);
+ }
+
+ public void testSimple() throws AMQException
+ {
+ TestQueue q1 = bindDefault("F0000");
+ TestQueue q2 = bindDefault("F0000=Aardvark");
+ TestQueue q3 = bindDefault("F0001");
+ TestQueue q4 = bindDefault("F0001=Bear");
+ TestQueue q5 = bindDefault("F0000", "F0001");
+ TestQueue q6 = bindDefault("F0000=Aardvark", "F0001=Bear");
+ TestQueue q7 = bindDefault("F0000", "F0001=Bear");
+ TestQueue q8 = bindDefault("F0000=Aardvark", "F0001");
+
+ routeAndTest(new Message("Message1", "F0000"), q1);
+ routeAndTest(new Message("Message2", "F0000=Aardvark"), q1, q2);
+ routeAndTest(new Message("Message3", "F0000=Aardvark", "F0001"), q1, q2, q3, q5, q8);
+ routeAndTest(new Message("Message4", "F0000", "F0001=Bear"), q1, q3, q4, q5, q7);
+ routeAndTest(new Message("Message5", "F0000=Aardvark", "F0001=Bear"),
+ q1, q2, q3, q4, q5, q6, q7, q8);
+ routeAndTest(new Message("Message6", "F0002"));
+
+ Message m7 = new Message("Message7", "XXXXX");
+
+ MessagePublishInfoImpl pb7 = (MessagePublishInfoImpl) (m7.getMessagePublishInfo());
+ pb7.setMandatory(true);
+ routeAndTest(m7,true);
+
+ Message m8 = new Message("Message8", "F0000");
+ MessagePublishInfoImpl pb8 = (MessagePublishInfoImpl)(m8.getMessagePublishInfo());
+ pb8.setMandatory(true);
+ routeAndTest(m8,false,q1);
+
+
+ }
+
+ public void testAny() throws AMQException
+ {
+ TestQueue q1 = bindDefault("F0000", "F0001", "X-match=any");
+ TestQueue q2 = bindDefault("F0000=Aardvark", "F0001=Bear", "X-match=any");
+ TestQueue q3 = bindDefault("F0000", "F0001=Bear", "X-match=any");
+ TestQueue q4 = bindDefault("F0000=Aardvark", "F0001", "X-match=any");
+ TestQueue q6 = bindDefault("F0000=Apple", "F0001", "X-match=any");
+
+ routeAndTest(new Message("Message1", "F0000"), q1, q3);
+ routeAndTest(new Message("Message2", "F0000=Aardvark"), q1, q2, q3, q4);
+ routeAndTest(new Message("Message3", "F0000=Aardvark", "F0001"), q1, q2, q3, q4, q6);
+ routeAndTest(new Message("Message4", "F0000", "F0001=Bear"), q1, q2, q3, q4, q6);
+ routeAndTest(new Message("Message5", "F0000=Aardvark", "F0001=Bear"), q1, q2, q3, q4, q6);
+ routeAndTest(new Message("Message6", "F0002"));
+ }
+
+ public void testMandatory() throws AMQException
+ {
+ bindDefault("F0000");
+ Message m1 = new Message("Message1", "XXXXX");
+ Message m2 = new Message("Message2", "F0000");
+ MessagePublishInfoImpl pb1 = (MessagePublishInfoImpl) (m1.getMessagePublishInfo());
+ pb1.setMandatory(true);
+ MessagePublishInfoImpl pb2 = (MessagePublishInfoImpl) (m2.getMessagePublishInfo());
+ pb2.setMandatory(true);
+ routeAndTest(m1,true);
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(HeadersExchangeTest.class);
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/logging/management/LoggingManagementMBeanTest.java b/java/broker/src/test/java/org/apache/qpid/server/logging/management/LoggingManagementMBeanTest.java
new file mode 100644
index 0000000000..40153be331
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/logging/management/LoggingManagementMBeanTest.java
@@ -0,0 +1,413 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.logging.management;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.management.JMException;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularDataSupport;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+
+import junit.framework.TestCase;
+
+public class LoggingManagementMBeanTest extends TestCase
+{
+ private static final String TEST_LOGGER = "LoggingManagementMBeanTestLogger";
+ private static final String TEST_LOGGER_CHILD1 = "LoggingManagementMBeanTestLogger.child1";
+ private static final String TEST_LOGGER_CHILD2 = "LoggingManagementMBeanTestLogger.child2";
+
+ private static final String CATEGORY_PRIORITY = "LogManMBeanTest.category.priority";
+ private static final String CATEGORY_LEVEL = "LogManMBeanTest.category.level";
+ private static final String LOGGER_LEVEL = "LogManMBeanTest.logger.level";
+
+ private static final String NAME_INDEX = LoggingManagement.COMPOSITE_ITEM_NAMES[0];
+ private static final String LEVEL_INDEX = LoggingManagement.COMPOSITE_ITEM_NAMES[1];
+
+ private static final String NEWLINE = System.getProperty("line.separator");
+
+ private File _testConfigFile;
+
+ protected void setUp() throws Exception
+ {
+ _testConfigFile = createTempTestLog4JConfig();
+ }
+
+ private File createTempTestLog4JConfig()
+ {
+ File tmpFile = null;
+ try
+ {
+ tmpFile = File.createTempFile("LogManMBeanTestLog4jConfig", ".tmp");
+ tmpFile.deleteOnExit();
+
+ FileWriter fstream = new FileWriter(tmpFile);
+ BufferedWriter writer = new BufferedWriter(fstream);
+
+ writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+NEWLINE);
+ writer.write("<!DOCTYPE log4j:configuration SYSTEM \"log4j.dtd\">"+NEWLINE);
+
+ writer.write("<log4j:configuration xmlns:log4j=\"http://jakarta.apache.org/log4j/\" debug=\"null\" " +
+ "threshold=\"null\">"+NEWLINE);
+
+ writer.write(" <appender class=\"org.apache.log4j.ConsoleAppender\" name=\"STDOUT\">"+NEWLINE);
+ writer.write(" <layout class=\"org.apache.log4j.PatternLayout\">"+NEWLINE);
+ writer.write(" <param name=\"ConversionPattern\" value=\"%d %-5p [%t] %C{2} (%F:%L) - %m%n\"/>"+NEWLINE);
+ writer.write(" </layout>"+NEWLINE);
+ writer.write(" </appender>"+NEWLINE);
+
+ //Example of a 'category' with a 'priority'
+ writer.write(" <category additivity=\"true\" name=\"" + CATEGORY_PRIORITY +"\">"+NEWLINE);
+ writer.write(" <priority value=\"info\"/>"+NEWLINE);
+ writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
+ writer.write(" </category>"+NEWLINE);
+
+ //Example of a 'category' with a 'level'
+ writer.write(" <category additivity=\"true\" name=\"" + CATEGORY_LEVEL +"\">"+NEWLINE);
+ writer.write(" <level value=\"warn\"/>"+NEWLINE);
+ writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
+ writer.write(" </category>"+NEWLINE);
+
+ //Example of a 'logger' with a 'level'
+ writer.write(" <logger additivity=\"true\" name=\"" + LOGGER_LEVEL + "\">"+NEWLINE);
+ writer.write(" <level value=\"error\"/>"+NEWLINE);
+ writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
+ writer.write(" </logger>"+NEWLINE);
+
+ //'root' logger
+ writer.write(" <root>"+NEWLINE);
+ writer.write(" <priority value=\"info\"/>"+NEWLINE);
+ writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE);
+ writer.write(" </root>"+NEWLINE);
+
+ writer.write("</log4j:configuration>"+NEWLINE);
+
+ writer.flush();
+ writer.close();
+ }
+ catch (IOException e)
+ {
+ fail("Unable to create temporary test log4j configuration");
+ }
+
+ return tmpFile;
+ }
+
+
+
+ //******* Test Methods ******* //
+
+ public void testSetRuntimeLoggerLevel()
+ {
+ LoggingManagementMBean lm = null;
+ try
+ {
+ lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0);
+ }
+ catch (JMException e)
+ {
+ fail("Could not create test LoggingManagementMBean");
+ }
+
+ //create a parent test logger, set its level explicitly
+ Logger log = Logger.getLogger(TEST_LOGGER);
+ log.setLevel(Level.toLevel("info"));
+
+ //create child1 test logger, check its *effective* level is the same as the parent, "info"
+ Logger log1 = Logger.getLogger(TEST_LOGGER_CHILD1);
+ assertTrue("Test logger's level was not the expected value",
+ log1.getEffectiveLevel().toString().equalsIgnoreCase("info"));
+
+ //now change its level to "warn"
+ assertTrue("Failed to set logger level", lm.setRuntimeLoggerLevel(TEST_LOGGER_CHILD1, "warn"));
+
+ //check the change, see its actual level is "warn
+ assertTrue("Test logger's level was not the expected value",
+ log1.getLevel().toString().equalsIgnoreCase("warn"));
+
+ //try an invalid level
+ assertFalse("Trying to set an invalid level succeded", lm.setRuntimeLoggerLevel(TEST_LOGGER_CHILD1, "made.up.level"));
+ }
+
+ public void testSetRuntimeRootLoggerLevel()
+ {
+ LoggingManagementMBean lm = null;
+ try
+ {
+ lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0);
+ }
+ catch (JMException e)
+ {
+ fail("Could not create test LoggingManagementMBean");
+ }
+
+ Logger log = Logger.getRootLogger();
+
+ //get current root logger level
+ Level origLevel = log.getLevel();
+
+ //change level twice to ensure a new level is actually selected
+
+ //set root loggers level to info
+ assertTrue("Failed to set root logger level", lm.setRuntimeRootLoggerLevel("debug"));
+ //check it is now actually info
+ Level currentLevel = log.getLevel();
+ assertTrue("Logger level was not expected value", currentLevel.equals(Level.toLevel("debug")));
+
+ //try an invalid level
+ assertFalse("Trying to set an invalid level succeded", lm.setRuntimeRootLoggerLevel("made.up.level"));
+
+ //set root loggers level to warn
+ assertTrue("Failed to set logger level", lm.setRuntimeRootLoggerLevel("info"));
+ //check it is now actually warn
+ currentLevel = log.getLevel();
+ assertTrue("Logger level was not expected value", currentLevel.equals(Level.toLevel("info")));
+
+ //restore original level
+ log.setLevel(origLevel);
+ }
+
+ public void testGetRuntimeRootLoggerLevel()
+ {
+ LoggingManagementMBean lm = null;
+ try
+ {
+ lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0);
+ }
+ catch (JMException e)
+ {
+ fail("Could not create test LoggingManagementMBean");
+ }
+
+ Logger log = Logger.getRootLogger();
+
+ //get current root logger level
+ Level origLevel = log.getLevel();
+
+ //change level twice to ensure a new level is actually selected
+
+ //set root loggers level to debug
+ log.setLevel(Level.toLevel("debug"));
+ //check it is now actually debug
+ assertTrue("Logger level was not expected value", lm.getRuntimeRootLoggerLevel().equalsIgnoreCase("debug"));
+
+
+ //set root loggers level to warn
+ log.setLevel(Level.toLevel("info"));
+ //check it is now actually warn
+ assertTrue("Logger level was not expected value", lm.getRuntimeRootLoggerLevel().equalsIgnoreCase("info"));
+
+ //restore original level
+ log.setLevel(origLevel);
+ }
+
+ public void testViewEffectiveRuntimeLoggerLevels()
+ {
+ LoggingManagementMBean lm = null;
+ try
+ {
+ lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0);
+ }
+ catch (JMException e)
+ {
+ fail("Could not create test LoggingManagementMBean");
+ }
+
+ //(re)create a parent test logger, set its level explicitly
+ Logger log = Logger.getLogger(TEST_LOGGER);
+ log.setLevel(Level.toLevel("info"));
+
+ //retrieve the current effective runtime logger level values
+ TabularDataSupport levels = (TabularDataSupport) lm.viewEffectiveRuntimeLoggerLevels();
+ Collection<Object> records = levels.values();
+ Map<String,String> list = new HashMap<String,String>();
+ for (Object o : records)
+ {
+ CompositeData data = (CompositeData) o;
+ list.put(data.get(NAME_INDEX).toString(), data.get(LEVEL_INDEX).toString());
+ }
+
+ //check child2 does not exist already
+ assertFalse("Did not expect this logger to exist already", list.containsKey(TEST_LOGGER_CHILD2));
+
+ //create child2 test logger
+ Logger log2 = Logger.getLogger(TEST_LOGGER_CHILD2);
+
+ //retrieve the current effective runtime logger level values
+ levels = (TabularDataSupport) lm.viewEffectiveRuntimeLoggerLevels();
+ records = levels.values();
+ list = new HashMap<String,String>();
+ for (Object o : records)
+ {
+ CompositeData data = (CompositeData) o;
+ list.put(data.get(NAME_INDEX).toString(), data.get(LEVEL_INDEX).toString());
+ }
+
+ //verify the parent and child2 loggers are present in returned values
+ assertTrue(TEST_LOGGER + " logger was not in the returned list", list.containsKey(TEST_LOGGER));
+ assertTrue(TEST_LOGGER_CHILD2 + " logger was not in the returned list", list.containsKey(TEST_LOGGER_CHILD2));
+
+ //check child2's effective level is the same as the parent, "info"
+ assertTrue("Test logger's level was not the expected value",
+ list.get(TEST_LOGGER_CHILD2).equalsIgnoreCase("info"));
+
+ //now change its level explicitly to "warn"
+ log2.setLevel(Level.toLevel("warn"));
+
+ //retrieve the current effective runtime logger level values
+ levels = (TabularDataSupport) lm.viewEffectiveRuntimeLoggerLevels();
+ records = levels.values();
+ list = new HashMap<String,String>();
+ for (Object o : records)
+ {
+ CompositeData data = (CompositeData) o;
+ list.put(data.get(NAME_INDEX).toString(), data.get(LEVEL_INDEX).toString());
+ }
+
+ //check child2's effective level is now "warn"
+ assertTrue("Test logger's level was not the expected value",
+ list.get(TEST_LOGGER_CHILD2).equalsIgnoreCase("warn"));
+ }
+
+ public void testViewAndSetConfigFileLoggerLevel() throws Exception
+ {
+ LoggingManagementMBean lm =null;
+ try
+ {
+ lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0);
+ }
+ catch (JMException e)
+ {
+ fail("Could not create test LoggingManagementMBean");
+ }
+
+ //retrieve the current values
+ TabularDataSupport levels = (TabularDataSupport) lm.viewConfigFileLoggerLevels();
+ Collection<Object> records = levels.values();
+ Map<String,String> list = new HashMap<String,String>();
+ for (Object o : records)
+ {
+ CompositeData data = (CompositeData) o;
+ list.put(data.get(NAME_INDEX).toString(), data.get(LEVEL_INDEX).toString());
+ }
+
+ //check the 3 different types of logger definition are successfully retrieved before update
+ assertTrue("Wrong number of items in returned list", list.size() == 3);
+ assertTrue(CATEGORY_PRIORITY + " logger was not in the returned list", list.containsKey(CATEGORY_PRIORITY));
+ assertTrue(CATEGORY_LEVEL + " logger was not in the returned list", list.containsKey(CATEGORY_LEVEL));
+ assertTrue(LOGGER_LEVEL + " logger was not in the returned list", list.containsKey(LOGGER_LEVEL));
+
+ //check that their level is as expected
+ assertTrue(CATEGORY_PRIORITY + " logger's level was incorrect", list.get(CATEGORY_PRIORITY).equalsIgnoreCase("info"));
+ assertTrue(CATEGORY_LEVEL + " logger's level was incorrect", list.get(CATEGORY_LEVEL).equalsIgnoreCase("warn"));
+ assertTrue(LOGGER_LEVEL + " logger's level was incorrect", list.get(LOGGER_LEVEL).equalsIgnoreCase("error"));
+
+ //increase their levels a notch to test the 3 different types of logger definition are successfully updated
+ //change the category+priority to warn
+ assertTrue("failed to set new level", lm.setConfigFileLoggerLevel(CATEGORY_PRIORITY, "warn"));
+ //change the category+level to error
+ assertTrue("failed to set new level", lm.setConfigFileLoggerLevel(CATEGORY_LEVEL, "error"));
+ //change the logger+level to trace
+ assertTrue("failed to set new level", lm.setConfigFileLoggerLevel(LOGGER_LEVEL, "trace"));
+
+ //try an invalid level
+ assertFalse("Use of an invalid logger level was successfull", lm.setConfigFileLoggerLevel(LOGGER_LEVEL, "made.up.level"));
+
+ //try an invalid logger name
+ assertFalse("Use of an invalid logger name was successfull", lm.setConfigFileLoggerLevel("made.up.logger.name", "info"));
+
+ //retrieve the new values from the file and check them
+ levels = (TabularDataSupport) lm.viewConfigFileLoggerLevels();
+ records = levels.values();
+ list = new HashMap<String,String>();
+ for (Object o : records)
+ {
+ CompositeData data = (CompositeData) o;
+ list.put(data.get(NAME_INDEX).toString(), data.get(LEVEL_INDEX).toString());
+ }
+
+ //check the 3 different types of logger definition are successfully retrieved after update
+ assertTrue("Wrong number of items in returned list", list.size() == 3);
+ assertTrue(CATEGORY_PRIORITY + " logger was not in the returned list", list.containsKey(CATEGORY_PRIORITY));
+ assertTrue(CATEGORY_LEVEL + " logger was not in the returned list", list.containsKey(CATEGORY_LEVEL));
+ assertTrue(LOGGER_LEVEL + " logger was not in the returned list", list.containsKey(LOGGER_LEVEL));
+
+ //check that their level is as expected after the changes
+ assertTrue(CATEGORY_PRIORITY + " logger's level was incorrect", list.get(CATEGORY_PRIORITY).equalsIgnoreCase("warn"));
+ assertTrue(CATEGORY_LEVEL + " logger's level was incorrect", list.get(CATEGORY_LEVEL).equalsIgnoreCase("error"));
+ assertTrue(LOGGER_LEVEL + " logger's level was incorrect", list.get(LOGGER_LEVEL).equalsIgnoreCase("trace"));
+ }
+
+ public void testGetAndSetConfigFileRootLoggerLevel() throws Exception
+ {
+ LoggingManagementMBean lm =null;
+ try
+ {
+ lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0);
+ }
+ catch (JMException e)
+ {
+ fail("Could not create test LoggingManagementMBean");
+ }
+
+ //retrieve the current value
+ String level = lm.getConfigFileRootLoggerLevel();
+
+ //check the value was successfully retrieved before update
+ assertTrue("Retrieved RootLogger level was incorrect", level.equalsIgnoreCase("info"));
+
+ //try an invalid level
+ assertFalse("Use of an invalid RootLogger level was successfull", lm.setConfigFileRootLoggerLevel("made.up.level"));
+
+ //change the level to warn
+ assertTrue("Failed to set new RootLogger level", lm.setConfigFileRootLoggerLevel("warn"));
+
+ //retrieve the current value
+ level = lm.getConfigFileRootLoggerLevel();
+
+ //check the value was successfully retrieved after update
+ assertTrue("Retrieved RootLogger level was incorrect", level.equalsIgnoreCase("warn"));
+ }
+
+ public void testGetLog4jLogWatchInterval()
+ {
+ LoggingManagementMBean lm =null;
+ try
+ {
+ lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 5000);
+ }
+ catch (JMException e)
+ {
+ fail("Could not create test LoggingManagementMBean");
+ }
+
+ assertTrue("Wrong value returned for logWatch period", lm.getLog4jLogWatchInterval() == 5000);
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/plugins/MockPluginManager.java b/java/broker/src/test/java/org/apache/qpid/server/plugins/MockPluginManager.java
new file mode 100644
index 0000000000..9599848dde
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/plugins/MockPluginManager.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.server.plugins;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpid.server.exchange.ExchangeType;
+import org.apache.qpid.server.security.access.ACLPlugin;
+import org.apache.qpid.server.security.access.ACLPluginFactory;
+import org.apache.qpid.server.security.access.QueueDenier;
+
+public class MockPluginManager extends PluginManager
+{
+
+ private Map<String, ACLPluginFactory> _securityPlugins = new HashMap<String, ACLPluginFactory>();
+
+ public MockPluginManager(String plugindir) throws Exception
+ {
+ super(plugindir);
+ _securityPlugins.put("org.apache.qpid.server.security.access.QueueDenier", QueueDenier.FACTORY);
+ }
+
+ @Override
+ public Map<String, ExchangeType<?>> getExchanges()
+ {
+ return null;
+ }
+
+ @Override
+ public Map<String, ACLPluginFactory> getSecurityPlugins()
+ {
+ return _securityPlugins;
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/plugins/PluginTest.java b/java/broker/src/test/java/org/apache/qpid/server/plugins/PluginTest.java
new file mode 100644
index 0000000000..11d6105704
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/plugins/PluginTest.java
@@ -0,0 +1,53 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.plugins;
+
+import java.util.Map;
+
+import org.apache.qpid.server.exchange.ExchangeType;
+
+import junit.framework.TestCase;
+
+public class PluginTest extends TestCase
+{
+
+ private static final String TEST_EXCHANGE_CLASS = "org.apache.qpid.extras.exchanges.example.TestExchangeType";
+ private static final String PLUGIN_DIRECTORY = System.getProperty("example.plugin.target");
+
+ public void testLoadExchanges() throws Exception
+ {
+ PluginManager manager = new PluginManager(PLUGIN_DIRECTORY);
+ Map<String, ExchangeType<?>> exchanges = manager.getExchanges();
+ assertNotNull("No exchanges found in "+PLUGIN_DIRECTORY, exchanges);
+ assertEquals("Wrong number of exchanges found in "+PLUGIN_DIRECTORY,
+ 2, exchanges.size());
+ assertNotNull("Wrong exchange found in "+PLUGIN_DIRECTORY,
+ exchanges.get(TEST_EXCHANGE_CLASS));
+ }
+
+ public void testNoExchanges() throws Exception
+ {
+ PluginManager manager = new PluginManager("/path/to/nowhere");
+ Map<String, ExchangeType<?>> exchanges = manager.getExchanges();
+ assertEquals("Exchanges found", 0, exchanges.size());
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java b/java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java
new file mode 100644
index 0000000000..d5db87350b
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java
@@ -0,0 +1,124 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.protocol;
+
+import junit.framework.TestCase;
+
+import org.apache.log4j.Logger;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.codec.AMQCodecFactory;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.SkeletonMessageStore;
+
+import javax.management.JMException;
+
+/**
+ * Test class to test MBean operations for AMQMinaProtocolSession.
+ */
+public class AMQProtocolSessionMBeanTest extends TestCase
+{
+ /** Used for debugging. */
+ private static final Logger log = Logger.getLogger(AMQProtocolSessionMBeanTest.class);
+
+ private MessageStore _messageStore = new SkeletonMessageStore();
+ private AMQMinaProtocolSession _protocolSession;
+ private AMQChannel _channel;
+ private AMQProtocolSessionMBean _mbean;
+
+ public void testChannels() throws Exception
+ {
+ // check the channel count is correct
+ int channelCount = _mbean.channels().size();
+ assertTrue(channelCount == 1);
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue_" + System.currentTimeMillis()),
+ false,
+ new AMQShortString("test"),
+ true,
+ _protocolSession.getVirtualHost(), null);
+ AMQChannel channel = new AMQChannel(_protocolSession,2, _messageStore);
+ channel.setDefaultQueue(queue);
+ _protocolSession.addChannel(channel);
+ channelCount = _mbean.channels().size();
+ assertTrue(channelCount == 2);
+
+ // general properties test
+ _mbean.setMaximumNumberOfChannels(1000L);
+ assertTrue(_mbean.getMaximumNumberOfChannels() == 1000L);
+
+ // check APIs
+ AMQChannel channel3 = new AMQChannel(_protocolSession, 3, _messageStore);
+ channel3.setLocalTransactional();
+ _protocolSession.addChannel(channel3);
+ _mbean.rollbackTransactions(2);
+ _mbean.rollbackTransactions(3);
+ _mbean.commitTransactions(2);
+ _mbean.commitTransactions(3);
+
+ // This should throw exception, because the channel does't exist
+ try
+ {
+ _mbean.commitTransactions(4);
+ fail();
+ }
+ catch (JMException ex)
+ {
+ log.debug("expected exception is thrown :" + ex.getMessage());
+ }
+
+ // check if closing of session works
+ _protocolSession.addChannel(new AMQChannel(_protocolSession, 5, _messageStore));
+ _mbean.closeConnection();
+ try
+ {
+ channelCount = _mbean.channels().size();
+ assertTrue(channelCount == 0);
+ // session is now closed so adding another channel should throw an exception
+ _protocolSession.addChannel(new AMQChannel(_protocolSession, 6, _messageStore));
+ fail();
+ }
+ catch (AMQException ex)
+ {
+ log.debug("expected exception is thrown :" + ex.getMessage());
+ }
+ }
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ IApplicationRegistry appRegistry = ApplicationRegistry.getInstance();
+ _protocolSession =
+ new AMQMinaProtocolSession(new TestIoSession(), appRegistry.getVirtualHostRegistry(), new AMQCodecFactory(true),
+ null);
+ _protocolSession.setVirtualHost(appRegistry.getVirtualHostRegistry().getVirtualHost("test"));
+ _channel = new AMQChannel(_protocolSession, 1, _messageStore);
+ _protocolSession.addChannel(_channel);
+ _mbean = (AMQProtocolSessionMBean) _protocolSession.getManagedObject();
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java b/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java
new file mode 100644
index 0000000000..da35ddc594
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java
@@ -0,0 +1,180 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.protocol;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.codec.AMQCodecFactory;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.output.ProtocolOutputConverter;
+import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.AMQChannel;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class InternalTestProtocolSession extends AMQMinaProtocolSession implements ProtocolOutputConverter
+{
+ // ChannelID(LIST) -> LinkedList<Pair>
+ final Map<Integer, Map<AMQShortString, LinkedList<DeliveryPair>>> _channelDelivers;
+ private AtomicInteger _deliveryCount = new AtomicInteger(0);
+
+ public InternalTestProtocolSession() throws AMQException
+ {
+ super(new TestIoSession(),
+ ApplicationRegistry.getInstance().getVirtualHostRegistry(),
+ new AMQCodecFactory(true));
+
+ _channelDelivers = new HashMap<Integer, Map<AMQShortString, LinkedList<DeliveryPair>>>();
+
+ }
+
+ public ProtocolOutputConverter getProtocolOutputConverter()
+ {
+ return this;
+ }
+
+ public byte getProtocolMajorVersion()
+ {
+ return (byte) 8;
+ }
+
+ public byte getProtocolMinorVersion()
+ {
+ return (byte) 0;
+ }
+
+ // ***
+
+ public List<DeliveryPair> getDelivers(int channelId, AMQShortString consumerTag, int count)
+ {
+ synchronized (_channelDelivers)
+ {
+ List<DeliveryPair> all =_channelDelivers.get(channelId).get(consumerTag);
+
+ if (all == null)
+ {
+ return new ArrayList<DeliveryPair>(0);
+ }
+
+ List<DeliveryPair> msgs = all.subList(0, count);
+
+ List<DeliveryPair> response = new ArrayList<DeliveryPair>(msgs);
+
+ //Remove the msgs from the receivedList.
+ msgs.clear();
+
+ return response;
+ }
+ }
+
+ // *** ProtocolOutputConverter Implementation
+ public void writeReturn(AMQMessage message, int channelId, int replyCode, AMQShortString replyText) throws AMQException
+ {
+ }
+
+ public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag)
+ {
+ }
+
+ public void writeDeliver(AMQMessage message, int channelId, long deliveryTag, AMQShortString consumerTag) throws AMQException
+ {
+ _deliveryCount.incrementAndGet();
+
+ synchronized (_channelDelivers)
+ {
+ Map<AMQShortString, LinkedList<DeliveryPair>> consumers = _channelDelivers.get(channelId);
+
+ if (consumers == null)
+ {
+ consumers = new HashMap<AMQShortString, LinkedList<DeliveryPair>>();
+ _channelDelivers.put(channelId, consumers);
+ }
+
+ LinkedList<DeliveryPair> consumerDelivers = consumers.get(consumerTag);
+
+ if (consumerDelivers == null)
+ {
+ consumerDelivers = new LinkedList<DeliveryPair>();
+ consumers.put(consumerTag, consumerDelivers);
+ }
+
+ consumerDelivers.add(new DeliveryPair(deliveryTag, message));
+ }
+ }
+
+ public void writeGetOk(AMQMessage message, int channelId, long deliveryTag, int queueSize) throws AMQException
+ {
+ }
+
+ public void awaitDelivery(int msgs)
+ {
+ while (msgs > _deliveryCount.get())
+ {
+ try
+ {
+ Thread.sleep(100);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public class DeliveryPair
+ {
+ private long _deliveryTag;
+ private AMQMessage _message;
+
+ public DeliveryPair(long deliveryTag, AMQMessage message)
+ {
+ _deliveryTag = deliveryTag;
+ _message = message;
+ }
+
+ public AMQMessage getMessage()
+ {
+ return _message;
+ }
+
+ public long getDeliveryTag()
+ {
+ return _deliveryTag;
+ }
+ }
+
+ public boolean isClosed()
+ {
+ return _closed;
+ }
+
+ public void closeProtocolSession(boolean waitLast)
+ {
+ // Override as we don't have a real IOSession to close.
+ // The alternative is to fully implement the TestIOSession to return a CloseFuture from close();
+ // Then the AMQMinaProtocolSession can join on the returning future without a NPE.
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/protocol/MaxChannelsTest.java b/java/broker/src/test/java/org/apache/qpid/server/protocol/MaxChannelsTest.java
new file mode 100644
index 0000000000..1bdabf345b
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/protocol/MaxChannelsTest.java
@@ -0,0 +1,86 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.protocol;
+
+import junit.framework.TestCase;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.codec.AMQCodecFactory;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.protocol.AMQConstant;
+
+/** Test class to test MBean operations for AMQMinaProtocolSession. */
+public class MaxChannelsTest extends TestCase
+{
+ private IApplicationRegistry _appRegistry;
+ private AMQMinaProtocolSession _session;
+
+ public void testChannels() throws Exception
+ {
+ _session = new AMQMinaProtocolSession(new TestIoSession(), _appRegistry
+ .getVirtualHostRegistry(), new AMQCodecFactory(true), null);
+ _session.setVirtualHost(_appRegistry.getVirtualHostRegistry().getVirtualHost("test"));
+
+ // check the channel count is correct
+ int channelCount = _session.getChannels().size();
+ assertEquals("Initial channel count wrong", 0, channelCount);
+
+ long maxChannels = 10L;
+ _session.setMaximumNumberOfChannels(maxChannels);
+ assertEquals("Number of channels not correctly set.", new Long(maxChannels), _session.getMaximumNumberOfChannels());
+
+
+ try
+ {
+ for (long currentChannel = 0L; currentChannel < maxChannels; currentChannel++)
+ {
+ _session.addChannel(new AMQChannel(_session, (int) currentChannel, null));
+ }
+ }
+ catch (AMQException e)
+ {
+ assertEquals("Wrong exception recevied.", e.getErrorCode(), AMQConstant.NOT_ALLOWED);
+ }
+ assertEquals("Maximum number of channels not set.", new Long(maxChannels), new Long(_session.getChannels().size()));
+ }
+
+ @Override
+ public void setUp()
+ {
+ _appRegistry = ApplicationRegistry.getInstance(1);
+ }
+
+ @Override
+ public void tearDown()
+ {
+ try {
+ _session.closeSession();
+ } catch (AMQException e) {
+ // Yikes
+ fail(e.getMessage());
+ }
+ ApplicationRegistry.remove(1);
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/protocol/TestIoSession.java b/java/broker/src/test/java/org/apache/qpid/server/protocol/TestIoSession.java
new file mode 100644
index 0000000000..211f491867
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/protocol/TestIoSession.java
@@ -0,0 +1,328 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.protocol;
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.mina.common.CloseFuture;
+import org.apache.mina.common.IdleStatus;
+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.IoSession;
+import org.apache.mina.common.IoSessionConfig;
+import org.apache.mina.common.ThreadModel;
+import org.apache.mina.common.TrafficMask;
+import org.apache.mina.common.TransportType;
+import org.apache.mina.common.WriteFuture;
+import org.apache.mina.transport.socket.nio.SocketAcceptorConfig;
+import org.apache.qpid.pool.ReadWriteThreadModel;
+
+/**
+ * Test implementation of IoSession, which is required for some tests. Methods not being used are not implemented,
+ * so if this class is being used and some methods are to be used, then please update those.
+ */
+public class TestIoSession implements IoSession
+{
+ private final ConcurrentMap attributes = new ConcurrentHashMap();
+ private String _address = "127.0.0.1";
+ private int _port = 1;
+
+ public TestIoSession()
+ {
+ }
+
+ public IoService getService()
+ {
+ return null;
+ }
+
+ public IoServiceConfig getServiceConfig()
+ {
+ return new TestIoConfig();
+ }
+
+ public IoHandler getHandler()
+ {
+ return null;
+ }
+
+ public IoSessionConfig getConfig()
+ {
+ return null;
+ }
+
+ public IoFilterChain getFilterChain()
+ {
+ return null;
+ }
+
+ public WriteFuture write(Object message)
+ {
+ return null;
+ }
+
+ public CloseFuture close()
+ {
+ return null;
+ }
+
+ public Object getAttachment()
+ {
+ return getAttribute("");
+ }
+
+ public Object setAttachment(Object attachment)
+ {
+ return setAttribute("",attachment);
+ }
+
+ public Object getAttribute(String key)
+ {
+ return attributes.get(key);
+ }
+
+ public Object setAttribute(String key, Object value)
+ {
+ return attributes.put(key,value);
+ }
+
+ public Object setAttribute(String key)
+ {
+ return attributes.put(key, Boolean.TRUE);
+ }
+
+ public Object removeAttribute(String key)
+ {
+ return attributes.remove(key);
+ }
+
+ public boolean containsAttribute(String key)
+ {
+ return attributes.containsKey(key);
+ }
+
+ public Set getAttributeKeys()
+ {
+ return attributes.keySet();
+ }
+
+ public TransportType getTransportType()
+ {
+ return null;
+ }
+
+ public boolean isConnected()
+ {
+ return false;
+ }
+
+ public boolean isClosing()
+ {
+ return false;
+ }
+
+ public CloseFuture getCloseFuture()
+ {
+ return null;
+ }
+
+ public SocketAddress getRemoteAddress()
+ {
+ return new InetSocketAddress(getAddress(), getPort());
+ }
+
+ public SocketAddress getLocalAddress()
+ {
+ return null;
+ }
+
+ public SocketAddress getServiceAddress()
+ {
+ return null;
+ }
+
+ public int getIdleTime(IdleStatus status)
+ {
+ return 0;
+ }
+
+ public long getIdleTimeInMillis(IdleStatus status)
+ {
+ return 0;
+ }
+
+ public void setIdleTime(IdleStatus status, int idleTime)
+ {
+
+ }
+
+ public int getWriteTimeout()
+ {
+ return 0;
+ }
+
+ public long getWriteTimeoutInMillis()
+ {
+ return 0;
+ }
+
+ public void setWriteTimeout(int writeTimeout)
+ {
+
+ }
+
+ public TrafficMask getTrafficMask()
+ {
+ return null;
+ }
+
+ public void setTrafficMask(TrafficMask trafficMask)
+ {
+
+ }
+
+ public void suspendRead()
+ {
+
+ }
+
+ public void suspendWrite()
+ {
+
+ }
+
+ public void resumeRead()
+ {
+
+ }
+
+ public void resumeWrite()
+ {
+
+ }
+
+ public long getReadBytes()
+ {
+ return 0;
+ }
+
+ public long getWrittenBytes()
+ {
+ return 0;
+ }
+
+ public long getReadMessages()
+ {
+ return 0;
+ }
+
+ public long getWrittenMessages()
+ {
+ return 0;
+ }
+
+ public long getWrittenWriteRequests()
+ {
+ return 0;
+ }
+
+ public int getScheduledWriteRequests()
+ {
+ return 0;
+ }
+
+ public int getScheduledWriteBytes()
+ {
+ return 0;
+ }
+
+ public long getCreationTime()
+ {
+ return 0;
+ }
+
+ public long getLastIoTime()
+ {
+ return 0;
+ }
+
+ public long getLastReadTime()
+ {
+ return 0;
+ }
+
+ public long getLastWriteTime()
+ {
+ return 0;
+ }
+
+ public boolean isIdle(IdleStatus status)
+ {
+ return false;
+ }
+
+ public int getIdleCount(IdleStatus status)
+ {
+ return 0;
+ }
+
+ public long getLastIdleTime(IdleStatus status)
+ {
+ return 0;
+ }
+
+ public void setAddress(String string)
+ {
+ this._address = string;
+ }
+
+ public String getAddress()
+ {
+ return _address;
+ }
+
+ public void setPort(int _port)
+ {
+ this._port = _port;
+ }
+
+ public int getPort()
+ {
+ return _port;
+ }
+
+ /**
+ * Test implementation of IoServiceConfig
+ */
+ private class TestIoConfig extends SocketAcceptorConfig
+ {
+ public ThreadModel getThreadModel()
+ {
+ return ReadWriteThreadModel.getInstance();
+ }
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java
new file mode 100644
index 0000000000..aff7af6952
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java
@@ -0,0 +1,107 @@
+package org.apache.qpid.server.queue;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+import java.util.ArrayList;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.FieldTable;
+import junit.framework.AssertionFailedError;
+
+public class AMQPriorityQueueTest extends SimpleAMQQueueTest
+{
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ _arguments = new FieldTable();
+ _arguments.put(AMQQueueFactory.X_QPID_PRIORITIES, 3);
+ super.setUp();
+ }
+
+ public void testPriorityOrdering() throws AMQException, InterruptedException
+ {
+
+ // Enqueue messages in order
+ _queue.enqueue(null, createMessage(1L, (byte) 10));
+ _queue.enqueue(null, createMessage(2L, (byte) 4));
+ _queue.enqueue(null, createMessage(3L, (byte) 0));
+
+ // Enqueue messages in reverse order
+ _queue.enqueue(null, createMessage(4L, (byte) 0));
+ _queue.enqueue(null, createMessage(5L, (byte) 4));
+ _queue.enqueue(null, createMessage(6L, (byte) 10));
+
+ // Enqueue messages out of order
+ _queue.enqueue(null, createMessage(7L, (byte) 4));
+ _queue.enqueue(null, createMessage(8L, (byte) 10));
+ _queue.enqueue(null, createMessage(9L, (byte) 0));
+
+ // Register subscriber
+ _queue.registerSubscription(_subscription, false);
+ Thread.sleep(150);
+
+ ArrayList<QueueEntry> msgs = _subscription.getMessages();
+ try
+ {
+ assertEquals(new Long(1L), msgs.get(0).getMessage().getMessageId());
+ assertEquals(new Long(6L), msgs.get(1).getMessage().getMessageId());
+ assertEquals(new Long(8L), msgs.get(2).getMessage().getMessageId());
+
+ assertEquals(new Long(2L), msgs.get(3).getMessage().getMessageId());
+ assertEquals(new Long(5L), msgs.get(4).getMessage().getMessageId());
+ assertEquals(new Long(7L), msgs.get(5).getMessage().getMessageId());
+
+ assertEquals(new Long(3L), msgs.get(6).getMessage().getMessageId());
+ assertEquals(new Long(4L), msgs.get(7).getMessage().getMessageId());
+ assertEquals(new Long(9L), msgs.get(8).getMessage().getMessageId());
+ }
+ catch (AssertionFailedError afe)
+ {
+ // Show message order on failure.
+ int index = 1;
+ for (QueueEntry qe : msgs)
+ {
+ System.err.println(index + ":" + qe.getMessage().getMessageId());
+ index++;
+ }
+
+ throw afe;
+ }
+
+ }
+
+ protected AMQMessage createMessage(Long id, byte i) throws AMQException
+ {
+ AMQMessage msg = super.createMessage(id);
+ BasicContentHeaderProperties props = new BasicContentHeaderProperties();
+ props.setPriority(i);
+ msg.getContentHeaderBody().properties = props;
+ return msg;
+ }
+
+ protected AMQMessage createMessage(Long id) throws AMQException
+ {
+ return createMessage(id, (byte) 0);
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java
new file mode 100644
index 0000000000..6589f46c7b
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java
@@ -0,0 +1,354 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import junit.framework.TestCase;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.MemoryMessageStore;
+import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.txn.TransactionalContext;
+import org.apache.qpid.server.txn.NonTransactionalContext;
+import org.apache.qpid.server.RequiredDeliveryException;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.SubscriptionFactoryImpl;
+import org.apache.qpid.server.protocol.AMQMinaProtocolSession;
+import org.apache.qpid.server.protocol.InternalTestProtocolSession;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.framing.abstraction.ContentChunk;
+import org.apache.commons.configuration.CompositeConfiguration;
+import org.apache.mina.common.ByteBuffer;
+
+import javax.management.Notification;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.Collections;
+import java.util.Set;
+
+/** This class tests all the alerts an AMQQueue can throw based on threshold values of different parameters */
+public class AMQQueueAlertTest extends TestCase
+{
+ private final static long MAX_MESSAGE_COUNT = 50;
+ private final static long MAX_MESSAGE_AGE = 250; // 0.25 sec
+ private final static long MAX_MESSAGE_SIZE = 2000; // 2 KB
+ private final static long MAX_QUEUE_DEPTH = 10000; // 10 KB
+ private AMQQueue _queue;
+ private AMQQueueMBean _queueMBean;
+ private VirtualHost _virtualHost;
+ private AMQMinaProtocolSession _protocolSession;
+ private MessageStore _messageStore = new MemoryMessageStore();
+ private StoreContext _storeContext = new StoreContext();
+ private TransactionalContext _transactionalContext = new NonTransactionalContext(_messageStore, _storeContext,
+ null,
+ new LinkedList<RequiredDeliveryException>()
+ );
+ private static final SubscriptionFactoryImpl SUBSCRIPTION_FACTORY = SubscriptionFactoryImpl.INSTANCE;
+
+ /**
+ * Tests if the alert gets thrown when message count increases the threshold limit
+ *
+ * @throws Exception
+ */
+ public void testMessageCountAlert() throws Exception
+ {
+ _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue1"), false, new AMQShortString("AMQueueAlertTest"),
+ false, _virtualHost,
+ null);
+ _queueMBean = (AMQQueueMBean) _queue.getManagedObject();
+
+ _queueMBean.setMaximumMessageCount(MAX_MESSAGE_COUNT);
+
+ sendMessages(MAX_MESSAGE_COUNT, 256l);
+ assertTrue(_queueMBean.getMessageCount() == MAX_MESSAGE_COUNT);
+
+ Notification lastNotification = _queueMBean.getLastNotification();
+ assertNotNull(lastNotification);
+
+ String notificationMsg = lastNotification.getMessage();
+ assertTrue(notificationMsg.startsWith(NotificationCheck.MESSAGE_COUNT_ALERT.name()));
+ }
+
+ /**
+ * Tests if the Message Size alert gets thrown when message of higher than threshold limit is sent
+ *
+ * @throws Exception
+ */
+ public void testMessageSizeAlert() throws Exception
+ {
+ _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue2"), false, new AMQShortString("AMQueueAlertTest"),
+ false, _virtualHost,
+ null);
+ _queueMBean = (AMQQueueMBean) _queue.getManagedObject();
+ _queueMBean.setMaximumMessageCount(MAX_MESSAGE_COUNT);
+ _queueMBean.setMaximumMessageSize(MAX_MESSAGE_SIZE);
+
+ sendMessages(1, MAX_MESSAGE_SIZE * 2);
+ assertTrue(_queueMBean.getMessageCount() == 1);
+
+ Notification lastNotification = _queueMBean.getLastNotification();
+ assertNotNull(lastNotification);
+
+ String notificationMsg = lastNotification.getMessage();
+ assertTrue(notificationMsg.startsWith(NotificationCheck.MESSAGE_SIZE_ALERT.name()));
+ }
+
+ /**
+ * Tests if Queue Depth alert is thrown when queue depth reaches the threshold value
+ *
+ * Based on FT-402 subbmitted by client
+ *
+ * @throws Exception
+ */
+ public void testQueueDepthAlertNoSubscriber() throws Exception
+ {
+ _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue3"), false, new AMQShortString("AMQueueAlertTest"),
+ false, _virtualHost,
+ null);
+ _queueMBean = (AMQQueueMBean) _queue.getManagedObject();
+ _queueMBean.setMaximumMessageCount(MAX_MESSAGE_COUNT);
+ _queueMBean.setMaximumQueueDepth(MAX_QUEUE_DEPTH);
+
+ while (_queue.getQueueDepth() < MAX_QUEUE_DEPTH)
+ {
+ sendMessages(1, MAX_MESSAGE_SIZE);
+ }
+
+ Notification lastNotification = _queueMBean.getLastNotification();
+ assertNotNull(lastNotification);
+
+ String notificationMsg = lastNotification.getMessage();
+ assertTrue(notificationMsg.startsWith(NotificationCheck.QUEUE_DEPTH_ALERT.name()));
+ }
+
+ /**
+ * Tests if MESSAGE AGE alert is thrown, when a message is in the queue for time higher than threshold value of
+ * message age
+ *
+ * Alternative test to FT-401 provided by client
+ *
+ * @throws Exception
+ */
+ public void testMessageAgeAlert() throws Exception
+ {
+ _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue4"), false, new AMQShortString("AMQueueAlertTest"),
+ false, _virtualHost,
+ null);
+ _queueMBean = (AMQQueueMBean) _queue.getManagedObject();
+ _queueMBean.setMaximumMessageCount(MAX_MESSAGE_COUNT);
+ _queueMBean.setMaximumMessageAge(MAX_MESSAGE_AGE);
+
+ sendMessages(1, MAX_MESSAGE_SIZE);
+
+ // Ensure message sits on queue long enough to age.
+ Thread.sleep(MAX_MESSAGE_AGE * 2);
+
+ Notification lastNotification = _queueMBean.getLastNotification();
+ assertNotNull(lastNotification);
+
+ String notificationMsg = lastNotification.getMessage();
+ assertTrue(notificationMsg.startsWith(NotificationCheck.MESSAGE_AGE_ALERT.name()));
+ }
+
+ /*
+ This test sends some messages to the queue with subscribers needing message to be acknowledged.
+ The messages will not be acknowledged and will be required twice. Why we are checking this is because
+ the bug reported said that the queueDepth keeps increasing when messages are requeued.
+ // TODO - queue depth now includes unacknowledged messages so does not go down when messages are delivered
+
+ The QueueDepth should decrease when messages are delivered from the queue (QPID-408)
+ */
+ public void testQueueDepthAlertWithSubscribers() throws Exception
+ {
+ _protocolSession = new InternalTestProtocolSession();
+ AMQChannel channel = new AMQChannel(_protocolSession, 2, _messageStore);
+ _protocolSession.addChannel(channel);
+
+ // Create queue
+ _queue = getNewQueue();
+ Subscription subscription =
+ SUBSCRIPTION_FACTORY.createSubscription(channel.getChannelId(), _protocolSession, new AMQShortString("consumer_tag"), true, null, false, channel.getCreditManager());
+
+ _queue.registerSubscription(
+ subscription, false);
+
+ _queueMBean = (AMQQueueMBean) _queue.getManagedObject();
+ _queueMBean.setMaximumMessageCount(9999l); // Set a high value, because this is not being tested
+ _queueMBean.setMaximumQueueDepth(MAX_QUEUE_DEPTH);
+
+ // Send messages(no of message to be little more than what can cause a Queue_Depth alert)
+ int messageCount = Math.round(MAX_QUEUE_DEPTH / MAX_MESSAGE_SIZE) + 10;
+ long totalSize = (messageCount * MAX_MESSAGE_SIZE);
+ sendMessages(messageCount, MAX_MESSAGE_SIZE);
+
+ // Check queueDepth. There should be no messages on the queue and as the subscriber is listening
+ // so there should be no Queue_Deoth alert raised
+ assertEquals(new Long(totalSize), new Long(_queueMBean.getQueueDepth()));
+ Notification lastNotification = _queueMBean.getLastNotification();
+// assertNull(lastNotification);
+
+ // Kill the subscriber and check for the queue depth values.
+ // Messages are unacknowledged, so those should get requeued. All messages should be on the Queue
+ _queue.unregisterSubscription(subscription);
+ channel.requeue();
+
+ assertEquals(new Long(totalSize), new Long(_queueMBean.getQueueDepth()));
+
+ lastNotification = _queueMBean.getLastNotification();
+ assertNotNull(lastNotification);
+ String notificationMsg = lastNotification.getMessage();
+ assertTrue(notificationMsg.startsWith(NotificationCheck.QUEUE_DEPTH_ALERT.name()));
+
+ // Connect a consumer again and check QueueDepth values. The queue should get emptied.
+ // Messages will get delivered but still are unacknowledged.
+ Subscription subscription2 =
+ SUBSCRIPTION_FACTORY.createSubscription(channel.getChannelId(), _protocolSession, new AMQShortString("consumer_tag"), true, null, false, channel.getCreditManager());
+
+ _queue.registerSubscription(
+ subscription2, false);
+
+ while (_queue.getUndeliveredMessageCount()!= 0)
+ {
+ Thread.sleep(100);
+ }
+// assertEquals(new Long(0), new Long(_queueMBean.getQueueDepth()));
+
+ // Kill the subscriber again. Now those messages should get requeued again. Check if the queue depth
+ // value is correct.
+ _queue.unregisterSubscription(subscription2);
+ channel.requeue();
+
+ assertEquals(new Long(totalSize), new Long(_queueMBean.getQueueDepth()));
+ _protocolSession.closeSession();
+
+ // Check the clear queue
+ _queueMBean.clearQueue();
+ assertEquals(new Long(0), new Long(_queueMBean.getQueueDepth()));
+ }
+
+ protected IncomingMessage message(final boolean immediate, long size) throws AMQException
+ {
+ MessagePublishInfo publish = new MessagePublishInfo()
+ {
+
+ public AMQShortString getExchange()
+ {
+ return null;
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isImmediate()
+ {
+ return immediate;
+ }
+
+ public boolean isMandatory()
+ {
+ return false;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return null;
+ }
+ };
+
+ ContentHeaderBody contentHeaderBody = new ContentHeaderBody();
+ contentHeaderBody.bodySize = size; // in bytes
+ IncomingMessage message = new IncomingMessage(_messageStore.getNewMessageId(), publish, _transactionalContext, _protocolSession);
+ message.setContentHeaderBody(contentHeaderBody);
+
+ return message;
+ }
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ IApplicationRegistry applicationRegistry = ApplicationRegistry.getInstance(1);
+ _virtualHost = applicationRegistry.getVirtualHostRegistry().getVirtualHost("test");
+ _protocolSession = new InternalTestProtocolSession();
+
+ }
+
+ protected void tearDown()
+ {
+ ApplicationRegistry.remove(1);
+ }
+
+
+ private void sendMessages(long messageCount, final long size) throws AMQException
+ {
+ IncomingMessage[] messages = new IncomingMessage[(int) messageCount];
+ for (int i = 0; i < messages.length; i++)
+ {
+ messages[i] = message(false, size);
+ ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>();
+ qs.add(_queue);
+ messages[i].enqueue(qs);
+ messages[i].routingComplete(_messageStore, new MessageHandleFactory());
+
+ }
+
+ for (int i = 0; i < messageCount; i++)
+ {
+ messages[i].addContentBodyFrame(new ContentChunk(){
+
+ ByteBuffer _data = ByteBuffer.allocate((int)size);
+
+ public int getSize()
+ {
+ return (int) size;
+ }
+
+ public ByteBuffer getData()
+ {
+ return _data;
+ }
+
+ public void reduceToFit()
+ {
+
+ }
+ });
+ messages[i].deliverToQueues();
+ }
+ }
+
+ private AMQQueue getNewQueue() throws AMQException
+ {
+ return AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue" + Math.random()),
+ false,
+ new AMQShortString("AMQueueAlertTest"),
+ false,
+ _virtualHost, null);
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java
new file mode 100644
index 0000000000..520e49c56a
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueFactoryTest.java
@@ -0,0 +1,85 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import junit.framework.TestCase;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.AMQException;
+
+public class AMQQueueFactoryTest extends TestCase
+{
+ QueueRegistry _queueRegistry;
+ VirtualHost _virtualHost;
+
+ public void setUp()
+ {
+ ApplicationRegistry registry = (ApplicationRegistry) ApplicationRegistry.getInstance();
+
+ _virtualHost = registry.getVirtualHostRegistry().getVirtualHost("test");
+
+ _queueRegistry = _virtualHost.getQueueRegistry();
+
+ assertEquals("Queues registered on an empty virtualhost", 0, _queueRegistry.getQueues().size());
+ }
+
+ public void tearDown()
+ {
+ assertEquals("Queue was not registered in virtualhost", 1, _queueRegistry.getQueues().size());
+ ApplicationRegistry.remove(1);
+ }
+
+
+ public void testPriorityQueueRegistration()
+ {
+ FieldTable fieldTable = new FieldTable();
+ fieldTable.put(new AMQShortString(AMQQueueFactory.X_QPID_PRIORITIES), 5);
+
+ try
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testPriorityQueue"), false, new AMQShortString("owner"), false,
+ _virtualHost, fieldTable);
+
+ assertEquals("Queue not a priorty queue", AMQPriorityQueue.class, queue.getClass());
+ }
+ catch (AMQException e)
+ {
+ fail(e.getMessage());
+ }
+ }
+
+
+ public void testSimpleQueueRegistration()
+ {
+ try
+ {
+ AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue"), false, new AMQShortString("owner"), false,
+ _virtualHost, null);
+ assertEquals("Queue not a simple queue", SimpleAMQQueue.class, queue.getClass());
+ }
+ catch (AMQException e)
+ {
+ fail(e.getMessage());
+ }
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java
new file mode 100644
index 0000000000..ce986cf55b
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java
@@ -0,0 +1,349 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import junit.framework.TestCase;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.ContentBody;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.framing.abstraction.ContentChunk;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.RequiredDeliveryException;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.SubscriptionFactory;
+import org.apache.qpid.server.subscription.SubscriptionFactoryImpl;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.protocol.InternalTestProtocolSession;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.txn.TransactionalContext;
+import org.apache.qpid.server.txn.NonTransactionalContext;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.store.MemoryMessageStore;
+import org.apache.qpid.server.store.TestableMemoryMessageStore;
+import org.apache.mina.common.ByteBuffer;
+
+import javax.management.JMException;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.Collections;
+
+/**
+ * Test class to test AMQQueueMBean attribtues and operations
+ */
+public class AMQQueueMBeanTest extends TestCase
+{
+ private static long MESSAGE_SIZE = 1000;
+ private AMQQueue _queue;
+ private AMQQueueMBean _queueMBean;
+ private MessageStore _messageStore;
+ private StoreContext _storeContext = new StoreContext();
+ private TransactionalContext _transactionalContext;
+ private VirtualHost _virtualHost;
+ private AMQProtocolSession _protocolSession;
+ private static final SubscriptionFactoryImpl SUBSCRIPTION_FACTORY = SubscriptionFactoryImpl.INSTANCE;
+
+ public void testMessageCountTransient() throws Exception
+ {
+ int messageCount = 10;
+ sendMessages(messageCount, false);
+ assertTrue(_queueMBean.getMessageCount() == messageCount);
+ assertTrue(_queueMBean.getReceivedMessageCount() == messageCount);
+ long queueDepth = (messageCount * MESSAGE_SIZE);
+ assertTrue(_queueMBean.getQueueDepth() == queueDepth);
+
+ _queueMBean.deleteMessageFromTop();
+ assertTrue(_queueMBean.getMessageCount() == (messageCount - 1));
+ assertTrue(_queueMBean.getReceivedMessageCount() == messageCount);
+
+ _queueMBean.clearQueue();
+ assertEquals(0,(int)_queueMBean.getMessageCount());
+ assertTrue(_queueMBean.getReceivedMessageCount() == messageCount);
+
+ //Ensure that the data has been removed from the Store
+ verifyBrokerState();
+ }
+
+ public void testMessageCountPersistent() throws Exception
+ {
+ int messageCount = 10;
+ sendMessages(messageCount, true);
+ assertEquals("", messageCount, _queueMBean.getMessageCount().intValue());
+ assertTrue(_queueMBean.getReceivedMessageCount() == messageCount);
+ long queueDepth = (messageCount * MESSAGE_SIZE);
+ assertTrue(_queueMBean.getQueueDepth() == queueDepth);
+
+ _queueMBean.deleteMessageFromTop();
+ assertTrue(_queueMBean.getMessageCount() == (messageCount - 1));
+ assertTrue(_queueMBean.getReceivedMessageCount() == messageCount);
+
+ _queueMBean.clearQueue();
+ assertTrue(_queueMBean.getMessageCount() == 0);
+ assertTrue(_queueMBean.getReceivedMessageCount() == messageCount);
+
+ //Ensure that the data has been removed from the Store
+ verifyBrokerState();
+ }
+
+ // todo: collect to a general testing class -duplicated from Systest/MessageReturntest
+ private void verifyBrokerState()
+ {
+
+ TestableMemoryMessageStore store = new TestableMemoryMessageStore((MemoryMessageStore) _virtualHost.getMessageStore());
+
+ // Unlike MessageReturnTest there is no need for a delay as there this thread does the clean up.
+ assertNotNull("ContentBodyMap should not be null", store.getContentBodyMap());
+ assertEquals("Expected the store to have no content:" + store.getContentBodyMap(), 0, store.getContentBodyMap().size());
+ assertNotNull("MessageMetaDataMap should not be null", store.getMessageMetaDataMap());
+ assertEquals("Expected the store to have no metadata:" + store.getMessageMetaDataMap(), 0, store.getMessageMetaDataMap().size());
+ }
+
+ public void testConsumerCount() throws AMQException
+ {
+
+ assertTrue(_queue.getActiveConsumerCount() == 0);
+ assertTrue(_queueMBean.getActiveConsumerCount() == 0);
+
+
+ InternalTestProtocolSession protocolSession = new InternalTestProtocolSession();
+ AMQChannel channel = new AMQChannel(protocolSession, 1, _messageStore);
+ protocolSession.addChannel(channel);
+
+ Subscription subscription =
+ SUBSCRIPTION_FACTORY.createSubscription(channel.getChannelId(), protocolSession, new AMQShortString("test"), false, null, false, channel.getCreditManager());
+
+ _queue.registerSubscription(subscription, false);
+ assertEquals(1,(int)_queueMBean.getActiveConsumerCount());
+
+
+ SubscriptionFactory subscriptionFactory = SUBSCRIPTION_FACTORY;
+ Subscription s1 = subscriptionFactory.createSubscription(channel.getChannelId(),
+ protocolSession,
+ new AMQShortString("S1"),
+ false,
+ null,
+ true,
+ channel.getCreditManager());
+
+ Subscription s2 = subscriptionFactory.createSubscription(channel.getChannelId(),
+ protocolSession,
+ new AMQShortString("S2"),
+ false,
+ null,
+ true,
+ channel.getCreditManager());
+ _queue.registerSubscription(s1,false);
+ _queue.registerSubscription(s2,false);
+ assertTrue(_queueMBean.getActiveConsumerCount() == 3);
+ assertTrue(_queueMBean.getConsumerCount() == 3);
+
+ s1.close();
+ assertEquals(2, (int) _queueMBean.getActiveConsumerCount());
+ assertTrue(_queueMBean.getConsumerCount() == 3);
+ }
+
+ public void testGeneralProperties()
+ {
+ long maxQueueDepth = 1000; // in bytes
+ _queueMBean.setMaximumMessageCount(50000l);
+ _queueMBean.setMaximumMessageSize(2000l);
+ _queueMBean.setMaximumQueueDepth(maxQueueDepth);
+
+ assertTrue(_queueMBean.getMaximumMessageCount() == 50000);
+ assertTrue(_queueMBean.getMaximumMessageSize() == 2000);
+ assertTrue(_queueMBean.getMaximumQueueDepth() == (maxQueueDepth));
+
+ assertTrue(_queueMBean.getName().equals("testQueue"));
+ assertTrue(_queueMBean.getOwner().equals("AMQueueMBeanTest"));
+ assertFalse(_queueMBean.isAutoDelete());
+ assertFalse(_queueMBean.isDurable());
+ }
+
+ public void testExceptions() throws Exception
+ {
+ try
+ {
+ _queueMBean.viewMessages(0, 3);
+ fail();
+ }
+ catch (JMException ex)
+ {
+
+ }
+
+ try
+ {
+ _queueMBean.viewMessages(2, 1);
+ fail();
+ }
+ catch (JMException ex)
+ {
+
+ }
+
+ try
+ {
+ _queueMBean.viewMessages(-1, 1);
+ fail();
+ }
+ catch (JMException ex)
+ {
+
+ }
+
+ IncomingMessage msg = message(false, false);
+ long id = msg.getMessageId();
+ _queue.clearQueue(_storeContext);
+ ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>();
+ qs.add(_queue);
+ msg.enqueue(qs);
+ msg.routingComplete(_messageStore, new MessageHandleFactory());
+
+ msg.addContentBodyFrame(new ContentChunk()
+ {
+ ByteBuffer _data = ByteBuffer.allocate((int)MESSAGE_SIZE);
+
+ public int getSize()
+ {
+ return (int) MESSAGE_SIZE;
+ }
+
+ public ByteBuffer getData()
+ {
+ return _data;
+ }
+
+ public void reduceToFit()
+ {
+
+ }
+ });
+ msg.deliverToQueues();
+// _queue.process(_storeContext, new QueueEntry(_queue, msg), false);
+ _queueMBean.viewMessageContent(id);
+ try
+ {
+ _queueMBean.viewMessageContent(id + 1);
+ fail();
+ }
+ catch (JMException ex)
+ {
+
+ }
+ }
+
+ private IncomingMessage message(final boolean immediate, boolean persistent) throws AMQException
+ {
+ MessagePublishInfo publish = new MessagePublishInfo()
+ {
+
+ public AMQShortString getExchange()
+ {
+ return null;
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isImmediate()
+ {
+ return immediate;
+ }
+
+ public boolean isMandatory()
+ {
+ return false;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return null;
+ }
+ };
+
+ ContentHeaderBody contentHeaderBody = new ContentHeaderBody();
+ contentHeaderBody.bodySize = MESSAGE_SIZE; // in bytes
+ contentHeaderBody.properties = new BasicContentHeaderProperties();
+ ((BasicContentHeaderProperties) contentHeaderBody.properties).setDeliveryMode((byte) (persistent ? 2 : 1));
+ IncomingMessage msg = new IncomingMessage(_messageStore.getNewMessageId(), publish, _transactionalContext, _protocolSession);
+ msg.setContentHeaderBody(contentHeaderBody);
+ return msg;
+
+ }
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ IApplicationRegistry applicationRegistry = ApplicationRegistry.getInstance(1);
+ _virtualHost = applicationRegistry.getVirtualHostRegistry().getVirtualHost("test");
+ _messageStore = _virtualHost.getMessageStore();
+
+ _transactionalContext = new NonTransactionalContext(_messageStore, _storeContext,
+ null,
+ new LinkedList<RequiredDeliveryException>()
+ );
+
+ _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue"), false, new AMQShortString("AMQueueMBeanTest"), false, _virtualHost,
+ null);
+ _queueMBean = new AMQQueueMBean(_queue);
+
+ _protocolSession = new InternalTestProtocolSession();
+ }
+
+ public void tearDown()
+ {
+ ApplicationRegistry.remove(1);
+ }
+
+ private void sendMessages(int messageCount, boolean persistent) throws AMQException
+ {
+ for (int i = 0; i < messageCount; i++)
+ {
+ IncomingMessage currentMessage = message(false, persistent);
+ ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>();
+ qs.add(_queue);
+ currentMessage.enqueue(qs);
+
+ // route header
+ currentMessage.routingComplete(_messageStore, new MessageHandleFactory());
+
+ // Add the body so we have somthing to test later
+ currentMessage.addContentBodyFrame(
+ _protocolSession.getMethodRegistry()
+ .getProtocolVersionMethodConverter()
+ .convertToContentChunk(
+ new ContentBody(ByteBuffer.allocate((int) MESSAGE_SIZE),
+ MESSAGE_SIZE)));
+ currentMessage.deliverToQueues();
+
+
+ }
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/AckTest.java b/java/broker/src/test/java/org/apache/qpid/server/queue/AckTest.java
new file mode 100644
index 0000000000..9c2932c5e2
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/AckTest.java
@@ -0,0 +1,420 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import junit.framework.TestCase;
+import org.apache.log4j.Logger;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.RequiredDeliveryException;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.SubscriptionFactoryImpl;
+import org.apache.qpid.server.flow.LimitlessCreditManager;
+import org.apache.qpid.server.flow.Pre0_10CreditManager;
+import org.apache.qpid.server.ack.UnacknowledgedMessageMap;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.store.TestMemoryMessageStore;
+import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.txn.NonTransactionalContext;
+import org.apache.qpid.server.txn.TransactionalContext;
+import org.apache.qpid.server.util.NullApplicationRegistry;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.Set;
+import java.util.Collections;
+
+/**
+ * Tests that acknowledgements are handled correctly.
+ */
+public class AckTest extends TestCase
+{
+ private static final Logger _log = Logger.getLogger(AckTest.class);
+
+ private Subscription _subscription;
+
+ private MockProtocolSession _protocolSession;
+
+ private TestMemoryMessageStore _messageStore;
+
+ private StoreContext _storeContext = new StoreContext();
+
+ private AMQChannel _channel;
+
+ private AMQQueue _queue;
+
+ private static final AMQShortString DEFAULT_CONSUMER_TAG = new AMQShortString("conTag");
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ ApplicationRegistry.initialise(new NullApplicationRegistry(), 1);
+
+ _messageStore = new TestMemoryMessageStore();
+ _protocolSession = new MockProtocolSession(_messageStore);
+ _channel = new AMQChannel(_protocolSession,5, _messageStore /*dont need exchange registry*/);
+
+ _protocolSession.addChannel(_channel);
+
+ _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("myQ"), false, new AMQShortString("guest"), true, ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test"),
+ null);
+ }
+
+ protected void tearDown()
+ {
+ ApplicationRegistry.remove(1);
+ }
+
+ private void publishMessages(int count) throws AMQException
+ {
+ publishMessages(count, false);
+ }
+
+ private void publishMessages(int count, boolean persistent) throws AMQException
+ {
+ TransactionalContext txnContext = new NonTransactionalContext(_messageStore, _storeContext, null,
+ new LinkedList<RequiredDeliveryException>()
+ );
+ _queue.registerSubscription(_subscription,false);
+ MessageHandleFactory factory = new MessageHandleFactory();
+ for (int i = 1; i <= count; i++)
+ {
+ // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0)
+ // TODO: Establish some way to determine the version for the test.
+ MessagePublishInfo publishBody = new MessagePublishInfo()
+ {
+
+ public AMQShortString getExchange()
+ {
+ return new AMQShortString("someExchange");
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isImmediate()
+ {
+ return false;
+ }
+
+ public boolean isMandatory()
+ {
+ return false;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return new AMQShortString("rk");
+ }
+ };
+ IncomingMessage msg = new IncomingMessage(_messageStore.getNewMessageId(), publishBody, txnContext,_protocolSession);
+ //IncomingMessage msg2 = null;
+ if (persistent)
+ {
+ BasicContentHeaderProperties b = new BasicContentHeaderProperties();
+ //This is DeliveryMode.PERSISTENT
+ b.setDeliveryMode((byte) 2);
+ ContentHeaderBody cb = new ContentHeaderBody();
+ cb.properties = b;
+ msg.setContentHeaderBody(cb);
+ }
+ else
+ {
+ msg.setContentHeaderBody(new ContentHeaderBody());
+ }
+ // we increment the reference here since we are not delivering the messaging to any queues, which is where
+ // the reference is normally incremented. The test is easier to construct if we have direct access to the
+ // subscription
+ ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>();
+ qs.add(_queue);
+ msg.enqueue(qs);
+ msg.routingComplete(_messageStore, factory);
+ if(msg.allContentReceived())
+ {
+ msg.deliverToQueues();
+ }
+ // we manually send the message to the subscription
+ //_subscription.send(new QueueEntry(_queue,msg), _queue);
+ }
+ }
+
+ /**
+ * Tests that the acknowledgements are correctly associated with a channel and
+ * order is preserved when acks are enabled
+ */
+ public void testAckChannelAssociationTest() throws AMQException
+ {
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true, null, false, new LimitlessCreditManager());
+ final int msgCount = 10;
+ publishMessages(msgCount, true);
+
+ UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
+ assertTrue(map.size() == msgCount);
+ assertTrue(_messageStore.getMessageMetaDataMap().size() == msgCount);
+
+ Set<Long> deliveryTagSet = map.getDeliveryTags();
+ int i = 1;
+ for (long deliveryTag : deliveryTagSet)
+ {
+ assertTrue(deliveryTag == i);
+ i++;
+ QueueEntry unackedMsg = map.get(deliveryTag);
+ assertTrue(unackedMsg.getQueue() == _queue);
+ }
+
+ assertTrue(map.size() == msgCount);
+ assertTrue(_messageStore.getMessageMetaDataMap().size() == msgCount);
+ }
+
+ /**
+ * Tests that in no-ack mode no messages are retained
+ */
+ public void testNoAckMode() throws AMQException
+ {
+ // false arg means no acks expected
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, false, null, false, new LimitlessCreditManager());
+ final int msgCount = 10;
+ publishMessages(msgCount);
+
+ UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
+ assertTrue(map.size() == 0);
+ assertTrue(_messageStore.getMessageMetaDataMap().size() == 0);
+ assertTrue(_messageStore.getContentBodyMap().size() == 0);
+
+ }
+
+ /**
+ * Tests that in no-ack mode no messages are retained
+ */
+ public void testPersistentNoAckMode() throws AMQException
+ {
+ // false arg means no acks expected
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, false,null,false, new LimitlessCreditManager());
+ final int msgCount = 10;
+ publishMessages(msgCount, true);
+
+ UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
+ assertTrue(map.size() == 0);
+ assertTrue(_messageStore.getMessageMetaDataMap().size() == 0);
+ assertTrue(_messageStore.getContentBodyMap().size() == 0);
+
+ }
+
+ /**
+ * Tests that a single acknowledgement is handled correctly (i.e multiple flag not
+ * set case)
+ */
+ public void testSingleAckReceivedTest() throws AMQException
+ {
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
+ final int msgCount = 10;
+ publishMessages(msgCount);
+
+ _channel.acknowledgeMessage(5, false);
+ UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
+ assertTrue(map.size() == msgCount - 1);
+
+ Set<Long> deliveryTagSet = map.getDeliveryTags();
+ int i = 1;
+ for (long deliveryTag : deliveryTagSet)
+ {
+ assertTrue(deliveryTag == i);
+ QueueEntry unackedMsg = map.get(deliveryTag);
+ assertTrue(unackedMsg.getQueue() == _queue);
+ // 5 is the delivery tag of the message that *should* be removed
+ if (++i == 5)
+ {
+ ++i;
+ }
+ }
+ }
+
+ /**
+ * Tests that a single acknowledgement is handled correctly (i.e multiple flag not
+ * set case)
+ */
+ public void testMultiAckReceivedTest() throws AMQException
+ {
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
+ final int msgCount = 10;
+ publishMessages(msgCount);
+
+ _channel.acknowledgeMessage(5, true);
+ UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
+ assertTrue(map.size() == 5);
+
+ Set<Long> deliveryTagSet = map.getDeliveryTags();
+ int i = 1;
+ for (long deliveryTag : deliveryTagSet)
+ {
+ assertTrue(deliveryTag == i + 5);
+ QueueEntry unackedMsg = map.get(deliveryTag);
+ assertTrue(unackedMsg.getQueue() == _queue);
+ ++i;
+ }
+ }
+
+ /**
+ * Tests that a multiple acknowledgement is handled correctly. When ack'ing all pending msgs.
+ */
+ public void testMultiAckAllReceivedTest() throws AMQException
+ {
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
+ final int msgCount = 10;
+ publishMessages(msgCount);
+
+ _channel.acknowledgeMessage(0, true);
+ UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
+ assertTrue(map.size() == 0);
+
+ Set<Long> deliveryTagSet = map.getDeliveryTags();
+ int i = 1;
+ for (long deliveryTag : deliveryTagSet)
+ {
+ assertTrue(deliveryTag == i + 5);
+ QueueEntry unackedMsg = map.get(deliveryTag);
+ assertTrue(unackedMsg.getQueue() == _queue);
+ ++i;
+ }
+ }
+
+ /**
+ * A regression fixing QPID-1136 showed this up
+ *
+ * @throws Exception
+ */
+ public void testMessageDequeueRestoresCreditTest() throws Exception
+ {
+ // Send 10 messages
+ Pre0_10CreditManager creditManager = new Pre0_10CreditManager(0l, 1);
+
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession,
+ DEFAULT_CONSUMER_TAG, true, null, false, creditManager);
+ final int msgCount = 1;
+ publishMessages(msgCount);
+
+ _queue.deliverAsync(_subscription);
+
+ _channel.acknowledgeMessage(1, false);
+
+ // Check credit available
+ assertTrue("No credit available", creditManager.hasCredit());
+
+ }
+
+
+/*
+ public void testPrefetchHighLow() throws AMQException
+ {
+ int lowMark = 5;
+ int highMark = 10;
+
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
+ _channel.setPrefetchLowMarkCount(lowMark);
+ _channel.setPrefetchHighMarkCount(highMark);
+
+ assertTrue(_channel.getPrefetchLowMarkCount() == lowMark);
+ assertTrue(_channel.getPrefetchHighMarkCount() == highMark);
+
+ publishMessages(highMark);
+
+ // at this point we should have sent out only highMark messages
+ // which have not bee received so will be queued up in the channel
+ // which should be suspended
+ assertTrue(_subscription.isSuspended());
+ UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
+ assertTrue(map.size() == highMark);
+
+ //acknowledge messages so we are just above lowMark
+ _channel.acknowledgeMessage(lowMark - 1, true);
+
+ //we should still be suspended
+ assertTrue(_subscription.isSuspended());
+ assertTrue(map.size() == lowMark + 1);
+
+ //acknowledge one more message
+ _channel.acknowledgeMessage(lowMark, true);
+
+ //and suspension should be lifted
+ assertTrue(!_subscription.isSuspended());
+
+ //pubilsh more msgs so we are just below the limit
+ publishMessages(lowMark - 1);
+
+ //we should not be suspended
+ assertTrue(!_subscription.isSuspended());
+
+ //acknowledge all messages
+ _channel.acknowledgeMessage(0, true);
+ try
+ {
+ Thread.sleep(3000);
+ }
+ catch (InterruptedException e)
+ {
+ _log.error("Error: " + e, e);
+ }
+ //map will be empty
+ assertTrue(map.size() == 0);
+ }
+
+*/
+/*
+ public void testPrefetch() throws AMQException
+ {
+ _subscription = SubscriptionFactoryImpl.INSTANCE.createSubscription(5, _protocolSession, DEFAULT_CONSUMER_TAG, true,null,false, new LimitlessCreditManager());
+ _channel.setMessageCredit(5);
+
+ assertTrue(_channel.getPrefetchCount() == 5);
+
+ final int msgCount = 5;
+ publishMessages(msgCount);
+
+ // at this point we should have sent out only 5 messages with a further 5 queued
+ // up in the channel which should now be suspended
+ assertTrue(_subscription.isSuspended());
+ UnacknowledgedMessageMap map = _channel.getUnacknowledgedMessageMap();
+ assertTrue(map.size() == 5);
+ _channel.acknowledgeMessage(5, true);
+ assertTrue(!_subscription.isSuspended());
+ try
+ {
+ Thread.sleep(3000);
+ }
+ catch (InterruptedException e)
+ {
+ _log.error("Error: " + e, e);
+ }
+ assertTrue(map.size() == 0);
+ }
+
+*/
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(AckTest.class);
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessage.java b/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessage.java
new file mode 100644
index 0000000000..355ba6a362
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessage.java
@@ -0,0 +1,49 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+
+public class MockAMQMessage extends AMQMessage
+{
+ public MockAMQMessage(long messageId)
+ throws AMQException
+ {
+ super(new MockAMQMessageHandle(messageId) ,
+ (StoreContext)null,
+ (MessagePublishInfo)new MockMessagePublishInfo());
+ }
+
+ protected MockAMQMessage(AMQMessage msg)
+ throws AMQException
+ {
+ super(msg);
+ }
+
+
+ @Override
+ public long getSize()
+ {
+ return 0l;
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessageHandle.java b/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessageHandle.java
new file mode 100644
index 0000000000..bdb0707c27
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQMessageHandle.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.server.store.StoreContext;
+
+public class MockAMQMessageHandle extends InMemoryMessageHandle
+{
+ public MockAMQMessageHandle(final Long messageId)
+ {
+ super(messageId);
+ }
+
+ @Override
+ public long getBodySize(StoreContext store)
+ {
+ return 0l;
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java b/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java
new file mode 100644
index 0000000000..20503bf15c
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.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.server.queue;
+
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.server.configuration.QueueConfiguration;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.management.ManagedObject;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.AMQException;
+import org.apache.commons.configuration.Configuration;
+
+import java.util.List;
+import java.util.Set;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.LinkedList;
+
+public class MockAMQQueue implements AMQQueue
+{
+ private boolean _deleted = false;
+ private AMQShortString _name;
+
+ public MockAMQQueue(String name)
+ {
+ _name = new AMQShortString(name);
+ }
+
+ public MockAMQQueue()
+ {
+
+ }
+
+ public AMQShortString getName()
+ {
+ return _name;
+ }
+
+ public boolean isDurable()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isAutoDelete()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public AMQShortString getOwner()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public VirtualHost getVirtualHost()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void bind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void unBind(Exchange exchange, AMQShortString routingKey, FieldTable arguments) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public List<ExchangeBinding> getExchangeBindings()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void registerSubscription(Subscription subscription, boolean exclusive) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void unregisterSubscription(Subscription subscription) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getConsumerCount()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getActiveConsumerCount()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isUnused()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isEmpty()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getMessageCount()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getUndeliveredMessageCount()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getQueueDepth()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getReceivedMessageCount()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getOldestMessageArrivalTime()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isDeleted()
+ {
+ return _deleted;
+ }
+
+ public int delete() throws AMQException
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public QueueEntry enqueue(StoreContext storeContext, AMQMessage message) throws AMQException
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void requeue(StoreContext storeContext, QueueEntry entry) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void dequeue(StoreContext storeContext, QueueEntry entry) throws FailedDequeueException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean resend(QueueEntry entry, Subscription subscription) throws AMQException
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void addQueueDeleteTask(Task task)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public List<QueueEntry> getMessagesOnTheQueue()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public List<QueueEntry> getMessagesOnTheQueue(long fromMessageId, long toMessageId)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public List<Long> getMessagesOnTheQueue(int num)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public List<Long> getMessagesOnTheQueue(int num, int offest)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public QueueEntry getMessageOnTheQueue(long messageId)
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, StoreContext storeContext)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, StoreContext storeContext)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void removeMessagesFromQueue(long fromMessageId, long toMessageId, StoreContext storeContext)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getMaximumMessageSize()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setMaximumMessageSize(long value)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getMaximumMessageCount()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setMaximumMessageCount(long value)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getMaximumQueueDepth()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setMaximumQueueDepth(long value)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getMaximumMessageAge()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setMaximumMessageAge(long maximumMessageAge)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long getMinimumAlertRepeatGap()
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void deleteMessageFromTop(StoreContext storeContext) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public long clearQueue(StoreContext storeContext) throws AMQException
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void checkMessageStatus() throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Set<NotificationCheck> getNotificationChecks()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void flushSubscription(Subscription sub) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void deliverAsync(Subscription sub)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void deliverAsync()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void stop()
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public ManagedObject getManagedObject()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int compareTo(AMQQueue o)
+ {
+ return 0; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void setMinimumAlertRepeatGap(long value)
+ {
+
+ }
+
+ public void configure(QueueConfiguration config)
+ {
+
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/MockMessagePublishInfo.java b/java/broker/src/test/java/org/apache/qpid/server/queue/MockMessagePublishInfo.java
new file mode 100644
index 0000000000..5a5ffaa14d
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/MockMessagePublishInfo.java
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.framing.AMQShortString;
+
+public class MockMessagePublishInfo implements MessagePublishInfo
+{
+ public AMQShortString getExchange()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isImmediate()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isMandatory()
+ {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/MockProtocolSession.java b/java/broker/src/test/java/org/apache/qpid/server/queue/MockProtocolSession.java
new file mode 100644
index 0000000000..99c88fac3e
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/MockProtocolSession.java
@@ -0,0 +1,262 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQConnectionException;
+import org.apache.qpid.framing.*;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.output.ProtocolOutputConverter;
+import org.apache.qpid.server.output.ProtocolOutputConverterRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.transport.Sender;
+
+import javax.security.sasl.SaslServer;
+import java.util.HashMap;
+import java.util.Map;
+import java.security.Principal;
+
+/**
+ * A protocol session that can be used for testing purposes.
+ */
+public class MockProtocolSession implements AMQProtocolSession
+{
+ private MessageStore _messageStore;
+
+ private Map<Integer, AMQChannel> _channelMap = new HashMap<Integer, AMQChannel>();
+
+ public MockProtocolSession(MessageStore messageStore)
+ {
+ _messageStore = messageStore;
+ }
+
+ public void dataBlockReceived(AMQDataBlock message) throws Exception
+ {
+ }
+
+ public void writeFrame(AMQDataBlock frame)
+ {
+ }
+
+ public AMQShortString getContextKey()
+ {
+ return null;
+ }
+
+ public void setContextKey(AMQShortString contextKey)
+ {
+ }
+
+ public AMQChannel getChannel(int channelId)
+ {
+ AMQChannel channel = _channelMap.get(channelId);
+ if (channel == null)
+ {
+ throw new IllegalArgumentException("Invalid channel id: " + channelId);
+ }
+ else
+ {
+ return channel;
+ }
+ }
+
+ public void addChannel(AMQChannel channel)
+ {
+ if (channel == null)
+ {
+ throw new IllegalArgumentException("Channel must not be null");
+ }
+ else
+ {
+ _channelMap.put(channel.getChannelId(), channel);
+ }
+ }
+
+ public void closeChannel(int channelId) throws AMQException
+ {
+ }
+
+ public void closeChannelOk(int channelId)
+ {
+
+ }
+
+ public boolean channelAwaitingClosure(int channelId)
+ {
+ return false;
+ }
+
+ public void removeChannel(int channelId)
+ {
+ _channelMap.remove(channelId);
+ }
+
+ public void initHeartbeats(int delay)
+ {
+ }
+
+ public void closeSession() throws AMQException
+ {
+ }
+
+ public void closeConnection(int channelId, AMQConnectionException e, boolean closeIoSession) throws AMQException
+ {
+ }
+
+ public Object getKey()
+ {
+ return null;
+ }
+
+ public String getLocalFQDN()
+ {
+ return null;
+ }
+
+ public SaslServer getSaslServer()
+ {
+ return null;
+ }
+
+ public void setSaslServer(SaslServer saslServer)
+ {
+ }
+
+ public FieldTable getClientProperties()
+ {
+ return null;
+ }
+
+ public void setClientProperties(FieldTable clientProperties)
+ {
+ }
+
+ public Object getClientIdentifier()
+ {
+ return null;
+ }
+
+ public VirtualHost getVirtualHost()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setVirtualHost(VirtualHost virtualHost)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void addSessionCloseTask(Task task)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void removeSessionCloseTask(Task task)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public ProtocolOutputConverter getProtocolOutputConverter()
+ {
+ return ProtocolOutputConverterRegistry.getConverter(this);
+ }
+
+ public void setAuthorizedID(Principal authorizedID)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public Principal getAuthorizedID()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public MethodRegistry getMethodRegistry()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void methodFrameReceived(int channelId, AMQMethodBody body)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void contentHeaderReceived(int channelId, ContentHeaderBody body)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void contentBodyReceived(int channelId, ContentBody body)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void heartbeatBodyReceived(int channelId, HeartbeatBody body)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public MethodDispatcher getMethodDispatcher()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public ProtocolSessionIdentifier getSessionIdentifier()
+ {
+ return null;
+ }
+
+ public byte getProtocolMajorVersion()
+ {
+ return getProtocolVersion().getMajorVersion();
+ }
+
+ public byte getProtocolMinorVersion()
+ {
+ return getProtocolVersion().getMinorVersion();
+ }
+
+
+ public ProtocolVersion getProtocolVersion()
+ {
+ return ProtocolVersion.getLatestSupportedVersion(); //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+
+ public VersionSpecificRegistry getRegistry()
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void setSender(Sender<java.nio.ByteBuffer> sender)
+ {
+ // FIXME AS TODO
+
+ }
+
+ public void init()
+ {
+ // TODO Auto-generated method stub
+
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java b/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java
new file mode 100644
index 0000000000..37f91e7464
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/MockQueueEntry.java
@@ -0,0 +1,197 @@
+/*
+*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.subscription.Subscription;
+
+public class MockQueueEntry implements QueueEntry
+{
+
+ private AMQMessage _message;
+
+ public boolean acquire()
+ {
+ return false;
+ }
+
+ public boolean acquire(Subscription sub)
+ {
+ return false;
+ }
+
+ public boolean acquiredBySubscription()
+ {
+ return false;
+ }
+
+ public void addStateChangeListener(StateChangeListener listener)
+ {
+
+ }
+
+ public String debugIdentity()
+ {
+ return null;
+ }
+
+ public boolean delete()
+ {
+ return false;
+ }
+
+ public void dequeue(StoreContext storeContext) throws FailedDequeueException
+ {
+
+ }
+
+ public void discard(StoreContext storeContext) throws FailedDequeueException, MessageCleanupException
+ {
+
+ }
+
+ public void dispose(StoreContext storeContext) throws MessageCleanupException
+ {
+
+ }
+
+ public boolean expired() throws AMQException
+ {
+ return false;
+ }
+
+ public Subscription getDeliveredSubscription()
+ {
+ return null;
+ }
+
+ public boolean getDeliveredToConsumer()
+ {
+ return false;
+ }
+
+ public AMQMessage getMessage()
+ {
+ return _message;
+ }
+
+ public AMQQueue getQueue()
+ {
+ return null;
+ }
+
+ public long getSize()
+ {
+ return 0;
+ }
+
+ public boolean immediateAndNotDelivered()
+ {
+ return false;
+ }
+
+ public boolean isAcquired()
+ {
+ return false;
+ }
+
+ public boolean isDeleted()
+ {
+ return false;
+ }
+
+
+ public boolean isQueueDeleted()
+ {
+
+ return false;
+ }
+
+
+ public boolean isRejectedBy(Subscription subscription)
+ {
+
+ return false;
+ }
+
+
+ public void reject()
+ {
+
+
+ }
+
+
+ public void reject(Subscription subscription)
+ {
+
+
+ }
+
+
+ public void release()
+ {
+
+
+ }
+
+
+ public boolean removeStateChangeListener(StateChangeListener listener)
+ {
+
+ return false;
+ }
+
+
+ public void requeue(StoreContext storeContext) throws AMQException
+ {
+
+
+ }
+
+
+ public void setDeliveredToSubscription()
+ {
+
+
+ }
+
+
+ public void setRedelivered(boolean b)
+ {
+
+
+ }
+
+
+ public int compareTo(QueueEntry o)
+ {
+
+ return 0;
+ }
+
+ public void setMessage(AMQMessage msg)
+ {
+ _message = msg;
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java b/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java
new file mode 100644
index 0000000000..3084dc7fa1
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java
@@ -0,0 +1,435 @@
+package org.apache.qpid.server.queue;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.ContentHeaderProperties;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
+import org.apache.qpid.server.exchange.DirectExchange;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.store.TestableMemoryMessageStore;
+import org.apache.qpid.server.subscription.MockSubscription;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.SubscriptionImpl;
+import org.apache.qpid.server.txn.NonTransactionalContext;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+public class SimpleAMQQueueTest extends TestCase
+{
+
+ protected SimpleAMQQueue _queue;
+ protected VirtualHost _virtualHost;
+ protected TestableMemoryMessageStore _store = new TestableMemoryMessageStore();
+ protected AMQShortString _qname = new AMQShortString("qname");
+ protected AMQShortString _owner = new AMQShortString("owner");
+ protected AMQShortString _routingKey = new AMQShortString("routing key");
+ protected DirectExchange _exchange = new DirectExchange();
+ protected MockSubscription _subscription = new MockSubscription();
+ protected FieldTable _arguments = null;
+
+ MessagePublishInfo info = new MessagePublishInfo()
+ {
+
+ public AMQShortString getExchange()
+ {
+ return null;
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isImmediate()
+ {
+ return false;
+ }
+
+ public boolean isMandatory()
+ {
+ return false;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return null;
+ }
+ };
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ //Create Application Registry for test
+ ApplicationRegistry applicationRegistry = (ApplicationRegistry)ApplicationRegistry.getInstance(1);
+
+ PropertiesConfiguration env = new PropertiesConfiguration();
+ _virtualHost = new VirtualHost(new VirtualHostConfiguration(getClass().getName(), env), _store);
+ applicationRegistry.getVirtualHostRegistry().registerVirtualHost(_virtualHost);
+
+ _queue = (SimpleAMQQueue) AMQQueueFactory.createAMQQueueImpl(_qname, false, _owner, false, _virtualHost, _arguments);
+ }
+
+ @Override
+ protected void tearDown()
+ {
+ _queue.stop();
+ ApplicationRegistry.remove(1);
+ }
+
+ public void testCreateQueue() throws AMQException
+ {
+ _queue.stop();
+ try {
+ _queue = (SimpleAMQQueue) AMQQueueFactory.createAMQQueueImpl(null, false, _owner, false, _virtualHost, _arguments );
+ assertNull("Queue was created", _queue);
+ }
+ catch (IllegalArgumentException e)
+ {
+ assertTrue("Exception was not about missing name",
+ e.getMessage().contains("name"));
+ }
+
+ try {
+ _queue = new SimpleAMQQueue(_qname, false, _owner, false, null);
+ assertNull("Queue was created", _queue);
+ }
+ catch (IllegalArgumentException e)
+ {
+ assertTrue("Exception was not about missing vhost",
+ e.getMessage().contains("Host"));
+ }
+
+ _queue = (SimpleAMQQueue) AMQQueueFactory.createAMQQueueImpl(_qname, false, _owner, false,
+ _virtualHost, _arguments);
+ assertNotNull("Queue was not created", _queue);
+ }
+
+ public void testGetVirtualHost()
+ {
+ assertEquals("Virtual host was wrong", _virtualHost, _queue.getVirtualHost());
+ }
+
+ public void testBinding()
+ {
+ try
+ {
+ _queue.bind(_exchange, _routingKey, null);
+ assertTrue("Routing key was not bound",
+ _exchange.getBindings().containsKey(_routingKey));
+ assertEquals("Queue was not bound to key",
+ _exchange.getBindings().get(_routingKey).get(0),
+ _queue);
+ assertEquals("Exchange binding count", 1,
+ _queue.getExchangeBindings().size());
+ assertEquals("Wrong exchange bound", _routingKey,
+ _queue.getExchangeBindings().get(0).getRoutingKey());
+ assertEquals("Wrong exchange bound", _exchange,
+ _queue.getExchangeBindings().get(0).getExchange());
+
+ _queue.unBind(_exchange, _routingKey, null);
+ assertFalse("Routing key was still bound",
+ _exchange.getBindings().containsKey(_routingKey));
+ assertNull("Routing key was not empty",
+ _exchange.getBindings().get(_routingKey));
+ }
+ catch (AMQException e)
+ {
+ assertNull("Unexpected exception", e);
+ }
+ }
+
+ public void testSubscription() throws AMQException
+ {
+ // Check adding a subscription adds it to the queue
+ _queue.registerSubscription(_subscription, false);
+ assertEquals("Subscription did not get queue", _queue,
+ _subscription.getQueue());
+ assertEquals("Queue does not have consumer", 1,
+ _queue.getConsumerCount());
+ assertEquals("Queue does not have active consumer", 1,
+ _queue.getActiveConsumerCount());
+
+ // Check sending a message ends up with the subscriber
+ AMQMessage messageA = createMessage(new Long(24));
+ _queue.enqueue(null, messageA);
+ assertEquals(messageA, _subscription.getLastSeenEntry().getMessage());
+
+ // Check removing the subscription removes it's information from the queue
+ _queue.unregisterSubscription(_subscription);
+ assertTrue("Subscription still had queue", _subscription.isClosed());
+ assertFalse("Queue still has consumer", 1 == _queue.getConsumerCount());
+ assertFalse("Queue still has active consumer",
+ 1 == _queue.getActiveConsumerCount());
+
+ AMQMessage messageB = createMessage(new Long (25));
+ _queue.enqueue(null, messageB);
+ QueueEntry entry = _subscription.getLastSeenEntry();
+ assertNull(entry);
+ }
+
+ public void testQueueNoSubscriber() throws AMQException, InterruptedException
+ {
+ AMQMessage messageA = createMessage(new Long(24));
+ _queue.enqueue(null, messageA);
+ _queue.registerSubscription(_subscription, false);
+ Thread.sleep(150);
+ assertEquals(messageA, _subscription.getLastSeenEntry().getMessage());
+ }
+
+ public void testExclusiveConsumer() throws AMQException
+ {
+ // Check adding an exclusive subscription adds it to the queue
+ _queue.registerSubscription(_subscription, true);
+ assertEquals("Subscription did not get queue", _queue,
+ _subscription.getQueue());
+ assertEquals("Queue does not have consumer", 1,
+ _queue.getConsumerCount());
+ assertEquals("Queue does not have active consumer", 1,
+ _queue.getActiveConsumerCount());
+
+ // Check sending a message ends up with the subscriber
+ AMQMessage messageA = createMessage(new Long(24));
+ _queue.enqueue(null, messageA);
+ assertEquals(messageA, _subscription.getLastSeenEntry().getMessage());
+
+ // Check we cannot add a second subscriber to the queue
+ Subscription subB = new MockSubscription();
+ Exception ex = null;
+ try
+ {
+ _queue.registerSubscription(subB, false);
+ }
+ catch (AMQException e)
+ {
+ ex = e;
+ }
+ assertNotNull(ex);
+ assertTrue(ex instanceof AMQException);
+
+ // Check we cannot add an exclusive subscriber to a queue with an
+ // existing subscription
+ _queue.unregisterSubscription(_subscription);
+ _queue.registerSubscription(_subscription, false);
+ try
+ {
+ _queue.registerSubscription(subB, true);
+ }
+ catch (AMQException e)
+ {
+ ex = e;
+ }
+ assertNotNull(ex);
+ }
+
+ public void testAutoDeleteQueue() throws Exception
+ {
+ _queue.stop();
+ _queue = new SimpleAMQQueue(_qname, false, _owner, true, _virtualHost);
+ _queue.registerSubscription(_subscription, false);
+ AMQMessage message = createMessage(new Long(25));
+ _queue.enqueue(null, message);
+ _queue.unregisterSubscription(_subscription);
+ assertTrue("Queue was not deleted when subscription was removed",
+ _queue.isDeleted());
+ }
+
+ public void testResend() throws Exception
+ {
+ _queue.registerSubscription(_subscription, false);
+ Long id = new Long(26);
+ AMQMessage message = createMessage(id);
+ _queue.enqueue(null, message);
+ QueueEntry entry = _subscription.getLastSeenEntry();
+ entry.setRedelivered(true);
+ _queue.resend(entry, _subscription);
+
+ }
+
+ public void testGetFirstMessageId() throws Exception
+ {
+ // Create message
+ Long messageId = new Long(23);
+ AMQMessage message = createMessage(messageId);
+
+ // Put message on queue
+ _queue.enqueue(null, message);
+ // Get message id
+ Long testmsgid = _queue.getMessagesOnTheQueue(1).get(0);
+
+ // Check message id
+ assertEquals("Message ID was wrong", messageId, testmsgid);
+ }
+
+ public void testGetFirstFiveMessageIds() throws Exception
+ {
+ for (int i = 0 ; i < 5; i++)
+ {
+ // Create message
+ Long messageId = new Long(i);
+ AMQMessage message = createMessage(messageId);
+ // Put message on queue
+ _queue.enqueue(null, message);
+ }
+ // Get message ids
+ List<Long> msgids = _queue.getMessagesOnTheQueue(5);
+
+ // Check message id
+ for (int i = 0; i < 5; i++)
+ {
+ Long messageId = new Long(i);
+ assertEquals("Message ID was wrong", messageId, msgids.get(i));
+ }
+ }
+
+ public void testGetLastFiveMessageIds() throws Exception
+ {
+ for (int i = 0 ; i < 10; i++)
+ {
+ // Create message
+ Long messageId = new Long(i);
+ AMQMessage message = createMessage(messageId);
+ // Put message on queue
+ _queue.enqueue(null, message);
+ }
+ // Get message ids
+ List<Long> msgids = _queue.getMessagesOnTheQueue(5, 5);
+
+ // Check message id
+ for (int i = 0; i < 5; i++)
+ {
+ Long messageId = new Long(i+5);
+ assertEquals("Message ID was wrong", messageId, msgids.get(i));
+ }
+ }
+
+ public void testEnqueueDequeueOfPersistentMessageToNonDurableQueue() throws AMQException
+ {
+ // Create IncomingMessage and nondurable queue
+ NonTransactionalContext txnContext = new NonTransactionalContext(_store, null, null, null);
+ IncomingMessage msg = new IncomingMessage(1L, info, txnContext, null);
+ ContentHeaderBody contentHeaderBody = new ContentHeaderBody();
+ contentHeaderBody.properties = new BasicContentHeaderProperties();
+ ((BasicContentHeaderProperties) contentHeaderBody.properties).setDeliveryMode((byte) 2);
+ msg.setContentHeaderBody(contentHeaderBody);
+ ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>();
+
+ // Send persistent message
+ qs.add(_queue);
+ msg.enqueue(qs);
+ msg.routingComplete(_store, new MessageHandleFactory());
+ _store.storeMessageMetaData(null, new Long(1L), new MessageMetaData(info, contentHeaderBody, 1));
+
+ // Check that it is enqueued
+ AMQQueue data = _store.getMessages().get(1L);
+ assertNotNull(data);
+
+ // Dequeue message
+ MockQueueEntry entry = new MockQueueEntry();
+ AMQMessage amqmsg = new AMQMessage(1L, _store, new MessageHandleFactory(), txnContext);
+
+ entry.setMessage(amqmsg);
+ _queue.dequeue(null, entry);
+
+ // Check that it is dequeued
+ data = _store.getMessages().get(1L);
+ assertNull(data);
+ }
+
+
+ // FIXME: move this to somewhere useful
+ private static AMQMessageHandle createMessageHandle(final long messageId, final MessagePublishInfo publishBody)
+ {
+ final AMQMessageHandle amqMessageHandle = (new MessageHandleFactory()).createMessageHandle(messageId,
+ null,
+ false);
+ try
+ {
+ amqMessageHandle.setPublishAndContentHeaderBody(new StoreContext(),
+ publishBody,
+ new ContentHeaderBody()
+ {
+ public int getSize()
+ {
+ return 1;
+ }
+ });
+ }
+ catch (AMQException e)
+ {
+ // won't happen
+ }
+
+
+ return amqMessageHandle;
+ }
+
+ public class TestMessage extends AMQMessage
+ {
+ private final long _tag;
+ private int _count;
+
+ TestMessage(long tag, long messageId, MessagePublishInfo publishBody, StoreContext storeContext)
+ throws AMQException
+ {
+ super(createMessageHandle(messageId, publishBody), storeContext, publishBody);
+ _tag = tag;
+ }
+
+
+ public boolean incrementReference()
+ {
+ _count++;
+ return true;
+ }
+
+ public void decrementReference(StoreContext context)
+ {
+ _count--;
+ }
+
+ void assertCountEquals(int expected)
+ {
+ assertEquals("Wrong count for message with tag " + _tag, expected, _count);
+ }
+ }
+
+ protected AMQMessage createMessage(Long id) throws AMQException
+ {
+ AMQMessage messageA = new TestMessage(id, id, info, new StoreContext());
+ return messageA;
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueThreadPoolTest.java b/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueThreadPoolTest.java
new file mode 100644
index 0000000000..832df80004
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueThreadPoolTest.java
@@ -0,0 +1,60 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.queue;
+
+import junit.framework.TestCase;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.pool.ReferenceCountingExecutorService;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.AMQException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SimpleAMQQueueThreadPoolTest extends TestCase
+{
+
+ public void test() throws AMQException
+ {
+ int initialCount = ReferenceCountingExecutorService.getInstance().getReferenceCount();
+ VirtualHost test = ApplicationRegistry.getInstance(1).getVirtualHostRegistry().getVirtualHost("test");
+
+ try
+ {
+ SimpleAMQQueue queue = (SimpleAMQQueue) AMQQueueFactory.createAMQQueueImpl(new AMQShortString("test"), false,
+ new AMQShortString("owner"),
+ false, test, null);
+
+ assertFalse("Creation did not start Pool.", ReferenceCountingExecutorService.getInstance().getPool().isShutdown());
+
+ assertEquals("References not increased", initialCount + 1, ReferenceCountingExecutorService.getInstance().getReferenceCount());
+
+ queue.stop();
+
+ assertEquals("References not decreased", initialCount , ReferenceCountingExecutorService.getInstance().getReferenceCount());
+ }
+ finally
+ {
+ ApplicationRegistry.remove(1);
+ }
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryShutdownTest.java b/java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryShutdownTest.java
new file mode 100644
index 0000000000..939e3436a5
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/registry/ApplicationRegistryShutdownTest.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.server.registry;
+
+import junit.framework.TestCase;
+import org.apache.qpid.server.util.TestApplicationRegistry;
+
+import java.security.Security;
+import java.security.Provider;
+import java.util.List;
+import java.util.LinkedList;
+
+/**
+ * QPID-1390 : Test to validate that the AuthenticationManger succesfully unregisters any new SASL providers when
+ * The ApplicationRegistry is closed.
+ *
+ * This should be expanded as QPID-1399 is implemented.
+ */
+public class ApplicationRegistryShutdownTest extends TestCase
+{
+
+ ApplicationRegistry _registry;
+
+ public void setUp() throws Exception
+ {
+ _registry = new TestApplicationRegistry();
+ }
+
+ /**
+ * QPID-1399 : Ensure that the Authentiction manager unregisters any SASL providers created during
+ * ApplicationRegistry initialisation.
+ *
+ */
+ public void testAuthenticationMangerCleansUp()
+ {
+ // Get default providers
+ Provider[] defaultProviders = Security.getProviders();
+
+ // Register new providers
+ try
+ {
+ _registry.initialise();
+ }
+ catch (Exception e)
+ {
+ fail(e.getMessage());
+ }
+
+ // Get the providers after initialisation
+ Provider[] providersAfterInitialisation = Security.getProviders();
+
+ // Find the additions
+ List additions = new LinkedList();
+ for (Provider afterInit : providersAfterInitialisation)
+ {
+ boolean found = false;
+ for (Provider defaultProvider : defaultProviders)
+ {
+ if (defaultProvider == afterInit)
+ {
+ found=true;
+ break;
+ }
+ }
+
+ // Record added registies
+ if (!found)
+ {
+ additions.add(afterInit);
+ }
+ }
+
+ // Not using isEmpty as that is not in Java 5
+ assertTrue("No new SASL mechanisms added by initialisation.", additions.size() != 0 );
+
+ //Close the registry which will perform the close the AuthenticationManager
+ try
+ {
+ _registry.close();
+ }
+ catch (Exception e)
+ {
+ fail(e.getMessage());
+ }
+
+ //Validate that the SASL plugins have been removed.
+ Provider[] providersAfterClose = Security.getProviders();
+
+ assertTrue("No providers unregistered", providersAfterInitialisation.length > providersAfterClose.length);
+
+ //Ensure that the additions are not still present after close().
+ for (Provider afterClose : providersAfterClose)
+ {
+ assertFalse("Added provider not unregistered", additions.contains(afterClose));
+ }
+ }
+
+
+
+
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/access/ACLManagerTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/access/ACLManagerTest.java
new file mode 100644
index 0000000000..6c6835ccca
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/access/ACLManagerTest.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.security.access;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.qpid.server.configuration.SecurityConfiguration;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.plugins.MockPluginManager;
+import org.apache.qpid.server.plugins.PluginManager;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.MockAMQQueue;
+import org.apache.qpid.server.queue.MockProtocolSession;
+import org.apache.qpid.server.store.TestableMemoryMessageStore;
+
+public class ACLManagerTest extends TestCase
+{
+
+ private ACLManager _authzManager;
+ private AMQProtocolSession _session;
+ private SecurityConfiguration _conf;
+ private PluginManager _pluginManager;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ File tmpFile = File.createTempFile(getClass().getName(), "testconfig");
+ tmpFile.deleteOnExit();
+ BufferedWriter out = new BufferedWriter(new FileWriter(tmpFile));
+ out.write("<security><queueDenier>notyet</queueDenier><exchangeDenier>yes</exchangeDenier></security>");
+ out.close();
+
+ _conf = new SecurityConfiguration(new XMLConfiguration(tmpFile));
+
+ // Create ACLManager
+
+ _pluginManager = new MockPluginManager("");
+ _authzManager = new ACLManager(_conf, _pluginManager);
+
+ _session = new MockProtocolSession(new TestableMemoryMessageStore());
+ }
+
+ public void testACLManagerConfigurationPluginManager() throws Exception
+ {
+ AMQQueue queue = new MockAMQQueue("notyet");
+ AMQQueue otherQueue = new MockAMQQueue("other");
+
+ assertFalse(_authzManager.authoriseDelete(_session, queue));
+
+ // This should only be denied if the config hasn't been correctly passed in
+ assertTrue(_authzManager.authoriseDelete(_session, otherQueue));
+ assertTrue(_authzManager.authorisePurge(_session, queue));
+ }
+
+ public void testACLManagerConfigurationPluginManagerACLPlugin() throws ConfigurationException
+ {
+ _authzManager = new ACLManager(_conf, _pluginManager, ExchangeDenier.FACTORY);
+
+ Exchange exchange = null;
+ assertFalse(_authzManager.authoriseDelete(_session, exchange));
+ }
+
+ public void testConfigurePlugins() throws ConfigurationException
+ {
+ Configuration hostConfig = new PropertiesConfiguration();
+ hostConfig.setProperty("queueDenier", "thisoneneither");
+ _authzManager.configureHostPlugins(new SecurityConfiguration(hostConfig));
+ AMQQueue queue = new MockAMQQueue("thisoneneither");
+ assertFalse(_authzManager.authoriseDelete(_session, queue));
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java b/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.java
new file mode 100644
index 0000000000..f62b0c6241
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/access/ExchangeDenier.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.server.security.access;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.security.access.plugins.AllowAll;
+
+public class ExchangeDenier extends AllowAll
+{
+
+ public static final ACLPluginFactory FACTORY = new ACLPluginFactory()
+ {
+ public boolean supportsTag(String name)
+ {
+ return name.startsWith("exchangeDenier");
+ }
+
+ public ACLPlugin newInstance(Configuration config)
+ {
+ return new ExchangeDenier();
+ }
+ };
+
+ @Override
+ public AuthzResult authoriseDelete(AMQProtocolSession session, Exchange exchange)
+ {
+ return AuthzResult.DENIED;
+ }
+
+ @Override
+ public String getPluginName()
+ {
+ return getClass().getSimpleName();
+ }
+
+ @Override
+ public boolean supportsTag(String name)
+ {
+ return name.equals("exchangeDenier");
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java
new file mode 100644
index 0000000000..e1e93ae9cb
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/access/PrincipalPermissionsTest.java
@@ -0,0 +1,156 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.security.access;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.amqp_0_9.ExchangeDeclareBodyImpl;
+import org.apache.qpid.framing.amqp_0_9.QueueDeclareBodyImpl;
+import org.apache.qpid.framing.amqp_8_0.QueueBindBodyImpl;
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
+import org.apache.qpid.server.exchange.DirectExchange;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult;
+import org.apache.qpid.server.store.SkeletonMessageStore;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+
+public class PrincipalPermissionsTest extends TestCase
+{
+
+ private String _user = "user";
+ private PrincipalPermissions _perms;
+
+ // Common things that are passed to frame constructors
+ private AMQShortString _queueName = new AMQShortString(this.getClass().getName()+"queue");
+ private AMQShortString _exchangeName = new AMQShortString("amq.direct");
+ private AMQShortString _routingKey = new AMQShortString(this.getClass().getName()+"route");
+ private int _ticket = 1;
+ private FieldTable _arguments = null;
+ private boolean _nowait = false;
+ private boolean _passive = false;
+ private boolean _durable = false;
+ private boolean _autoDelete = false;
+ private AMQShortString _exchangeType = new AMQShortString("direct");
+ private boolean _internal = false;
+
+ private DirectExchange _exchange;
+ private VirtualHost _virtualHost;
+ private AMQShortString _owner = new AMQShortString(this.getClass().getName()+"owner");
+ private AMQQueue _queue;
+ private Boolean _temporary = false;
+
+ @Override
+ public void setUp()
+ {
+ _perms = new PrincipalPermissions(_user);
+ try
+ {
+ PropertiesConfiguration env = new PropertiesConfiguration();
+ _virtualHost = new VirtualHost(new VirtualHostConfiguration("test", env));
+ _exchange = DirectExchange.TYPE.newInstance(_virtualHost, _exchangeName, _durable, _ticket, _autoDelete);
+ _queue = AMQQueueFactory.createAMQQueueImpl(_queueName, false, _owner , false, _virtualHost, _arguments);
+ }
+ catch (Exception e)
+ {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testPrincipalPermissions()
+ {
+ assertNotNull(_perms);
+ assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.ACCESS, (Object[]) null));
+ }
+
+ // FIXME: test has been disabled since the permissions assume that the user has tried to create
+ // the queue first. QPID-1597
+ public void disableTestBind() throws Exception
+ {
+ QueueBindBodyImpl bind = new QueueBindBodyImpl(_ticket, _queueName, _exchangeName, _routingKey, _nowait, _arguments);
+ Object[] args = new Object[]{bind, _exchange, _queue, _routingKey};
+
+ assertEquals(AuthzResult.DENIED, _perms.authorise(Permission.BIND, args));
+ _perms.grant(Permission.BIND, (Object[]) null);
+ assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.BIND, args));
+ }
+
+ public void testQueueCreate()
+ {
+ Object[] grantArgs = new Object[]{_temporary , _queueName, _exchangeName, _routingKey};
+ Object[] authArgs = new Object[]{_autoDelete, _queueName};
+
+ assertEquals(AuthzResult.DENIED, _perms.authorise(Permission.CREATEQUEUE, authArgs));
+ _perms.grant(Permission.CREATEQUEUE, grantArgs);
+ assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.CREATEQUEUE, authArgs));
+ }
+
+ public void testQueueCreateWithNullRoutingKey()
+ {
+ Object[] grantArgs = new Object[]{_temporary , _queueName, _exchangeName, null};
+ Object[] authArgs = new Object[]{_autoDelete, _queueName};
+
+ assertEquals(AuthzResult.DENIED, _perms.authorise(Permission.CREATEQUEUE, authArgs));
+ _perms.grant(Permission.CREATEQUEUE, grantArgs);
+ assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.CREATEQUEUE, authArgs));
+ }
+
+ // FIXME disabled, this fails due to grant putting the grant into the wrong map QPID-1598
+ public void disableTestExchangeCreate()
+ {
+ ExchangeDeclareBodyImpl exchangeDeclare =
+ new ExchangeDeclareBodyImpl(_ticket, _exchangeName, _exchangeType, _passive, _durable,
+ _autoDelete, _internal, _nowait, _arguments);
+ Object[] authArgs = new Object[]{exchangeDeclare};
+ Object[] grantArgs = new Object[]{_exchangeName, _exchangeType};
+
+ assertEquals(AuthzResult.DENIED, _perms.authorise(Permission.CREATEEXCHANGE, authArgs));
+ _perms.grant(Permission.CREATEEXCHANGE, grantArgs);
+ assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.CREATEEXCHANGE, authArgs));
+ }
+
+ public void testConsume()
+ {
+ Object[] authArgs = new Object[]{_queue};
+ Object[] grantArgs = new Object[]{_queueName, _temporary, _temporary};
+
+ /* FIXME: This throws a null pointer exception QPID-1599
+ * assertFalse(_perms.authorise(Permission.CONSUME, authArgs));
+ */
+ _perms.grant(Permission.CONSUME, grantArgs);
+ assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.CONSUME, authArgs));
+ }
+
+ public void testPublish()
+ {
+ Object[] authArgs = new Object[]{_exchange, _routingKey};
+ Object[] grantArgs = new Object[]{_exchange.getName(), _routingKey};
+
+ assertEquals(AuthzResult.DENIED, _perms.authorise(Permission.PUBLISH, authArgs));
+ _perms.grant(Permission.PUBLISH, grantArgs);
+ assertEquals(AuthzResult.ALLOWED, _perms.authorise(Permission.PUBLISH, authArgs));
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java b/java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java
new file mode 100644
index 0000000000..5497f0ae44
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/access/QueueDenier.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *
+ */
+package org.apache.qpid.server.security.access;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult;
+import org.apache.qpid.server.security.access.plugins.AllowAll;
+
+public class QueueDenier extends AllowAll
+{
+
+ public static final ACLPluginFactory FACTORY = new ACLPluginFactory()
+ {
+ public boolean supportsTag(String name)
+ {
+ return name.equals("queueDenier");
+ }
+
+ public ACLPlugin newInstance(Configuration config)
+ {
+ QueueDenier plugin = new QueueDenier();
+ plugin.setConfiguration(config);
+ return plugin;
+ }
+ };
+
+ private String _queueName = "";
+
+
+ @Override
+ public AuthzResult authoriseDelete(AMQProtocolSession session, AMQQueue queue)
+ {
+ if (!(queue.getName().toString().equals(_queueName)))
+ {
+ return AuthzResult.ALLOWED;
+ }
+ else
+ {
+ return AuthzResult.DENIED;
+ }
+ }
+
+ @Override
+ public void setConfiguration(Configuration config)
+ {
+ _queueName = config.getString("queueDenier");
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBeanTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBeanTest.java
new file mode 100644
index 0000000000..958ee35476
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/access/management/AMQUserManagementMBeanTest.java
@@ -0,0 +1,271 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.security.access.management;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.server.management.MBeanInvocationHandlerImpl;
+import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase;
+
+import junit.framework.TestCase;
+
+/* Note: The main purpose is to test the jmx access rights file manipulation
+ * within AMQUserManagementMBean. The Principal Databases are tested by their own tests,
+ * this test just exercises their usage in AMQUserManagementMBean.
+ */
+public class AMQUserManagementMBeanTest extends TestCase
+{
+ private PlainPasswordFilePrincipalDatabase _database;
+ private AMQUserManagementMBean _amqumMBean;
+
+ private File _passwordFile;
+ private File _accessFile;
+
+ private static final String TEST_USERNAME = "testuser";
+ private static final String TEST_PASSWORD = "password";
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ _database = new PlainPasswordFilePrincipalDatabase();
+ _amqumMBean = new AMQUserManagementMBean();
+ loadFreshTestPasswordFile();
+ loadFreshTestAccessFile();
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ _passwordFile.delete();
+ _accessFile.delete();
+ }
+
+ public void testDeleteUser()
+ {
+ loadFreshTestPasswordFile();
+ loadFreshTestAccessFile();
+
+ //try deleting a non existant user
+ assertFalse(_amqumMBean.deleteUser("made.up.username"));
+
+ assertTrue(_amqumMBean.deleteUser(TEST_USERNAME));
+ }
+
+ public void testDeleteUserIsSavedToAccessFile()
+ {
+ loadFreshTestPasswordFile();
+ loadFreshTestAccessFile();
+
+ assertTrue(_amqumMBean.deleteUser(TEST_USERNAME));
+
+ //check the access rights were actually deleted from the file
+ try{
+ BufferedReader reader = new BufferedReader(new FileReader(_accessFile));
+
+ //check the 'generated by' comment line is present
+ assertTrue("File has no content", reader.ready());
+ assertTrue("'Generated by' comment line was missing",reader.readLine().contains("Generated by " +
+ "AMQUserManagementMBean Console : Last edited by user:"));
+
+ //there should also be a modified date/time comment line
+ assertTrue("File has no modified date/time comment line", reader.ready());
+ assertTrue("Modification date/time comment line was missing",reader.readLine().startsWith("#"));
+
+ //the access file should not contain any further data now as we just deleted the only user
+ assertFalse("User access data was present when it should have been deleted", reader.ready());
+ }
+ catch (IOException e)
+ {
+ fail("Unable to valdate file contents due to:" + e.getMessage());
+ }
+
+ }
+
+ public void testSetRights()
+ {
+ loadFreshTestPasswordFile();
+ loadFreshTestAccessFile();
+
+ assertFalse(_amqumMBean.setRights("made.up.username", true, false, false));
+
+ assertTrue(_amqumMBean.setRights(TEST_USERNAME, true, false, false));
+ assertTrue(_amqumMBean.setRights(TEST_USERNAME, false, true, false));
+ assertTrue(_amqumMBean.setRights(TEST_USERNAME, false, false, true));
+ }
+
+ public void testSetRightsIsSavedToAccessFile()
+ {
+ loadFreshTestPasswordFile();
+ loadFreshTestAccessFile();
+
+ assertTrue(_amqumMBean.setRights(TEST_USERNAME, false, false, true));
+
+ //check the access rights were actually updated in the file
+ try{
+ BufferedReader reader = new BufferedReader(new FileReader(_accessFile));
+
+ //check the 'generated by' comment line is present
+ assertTrue("File has no content", reader.ready());
+ assertTrue("'Generated by' comment line was missing",reader.readLine().contains("Generated by " +
+ "AMQUserManagementMBean Console : Last edited by user:"));
+
+ //there should also be a modified date/time comment line
+ assertTrue("File has no modified date/time comment line", reader.ready());
+ assertTrue("Modification date/time comment line was missing",reader.readLine().startsWith("#"));
+
+ //the access file should not contain any further data now as we just deleted the only user
+ assertTrue("User access data was not updated in the access file",
+ reader.readLine().equals(TEST_USERNAME + "=" + MBeanInvocationHandlerImpl.ADMIN));
+
+ //the access file should not contain any further data now as we just deleted the only user
+ assertFalse("Additional user access data was present when there should be no more", reader.ready());
+ }
+ catch (IOException e)
+ {
+ fail("Unable to valdate file contents due to:" + e.getMessage());
+ }
+ }
+
+ public void testMBeanVersion()
+ {
+ try
+ {
+ ObjectName name = _amqumMBean.getObjectName();
+ assertEquals(AMQUserManagementMBean.VERSION, Integer.parseInt(name.getKeyProperty("version")));
+ }
+ catch (MalformedObjectNameException e)
+ {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testSetAccessFileWithMissingFile()
+ {
+ try
+ {
+ _amqumMBean.setAccessFile("made.up.filename");
+ }
+ catch (IOException e)
+ {
+ fail("Should not have been an IOE." + e.getMessage());
+ }
+ catch (ConfigurationException e)
+ {
+ assertTrue(e.getMessage(), e.getMessage().endsWith("does not exist"));
+ }
+ }
+
+ public void testSetAccessFileWithReadOnlyFile()
+ {
+ File testFile = null;
+ try
+ {
+ testFile = File.createTempFile(this.getClass().getName(),".access.readonly");
+ BufferedWriter passwordWriter = new BufferedWriter(new FileWriter(testFile, false));
+ passwordWriter.write(TEST_USERNAME + ":" + TEST_PASSWORD);
+ passwordWriter.newLine();
+ passwordWriter.flush();
+ passwordWriter.close();
+
+ testFile.setReadOnly();
+ _amqumMBean.setAccessFile(testFile.getPath());
+ }
+ catch (IOException e)
+ {
+ fail("Access file was not created." + e.getMessage());
+ }
+ catch (ConfigurationException e)
+ {
+ fail("There should not have been a configuration exception." + e.getMessage());
+ }
+
+ testFile.delete();
+ }
+
+ // ============================ Utility methods =========================
+
+ private void loadFreshTestPasswordFile()
+ {
+ try
+ {
+ if(_passwordFile == null)
+ {
+ _passwordFile = File.createTempFile(this.getClass().getName(),".password");
+ }
+
+ BufferedWriter passwordWriter = new BufferedWriter(new FileWriter(_passwordFile, false));
+ passwordWriter.write(TEST_USERNAME + ":" + TEST_PASSWORD);
+ passwordWriter.newLine();
+ passwordWriter.flush();
+ passwordWriter.close();
+ _database.setPasswordFile(_passwordFile.toString());
+ _amqumMBean.setPrincipalDatabase(_database);
+ }
+ catch (IOException e)
+ {
+ fail("Unable to create test password file: " + e.getMessage());
+ }
+ }
+
+ private void loadFreshTestAccessFile()
+ {
+ try
+ {
+ if(_accessFile == null)
+ {
+ _accessFile = File.createTempFile(this.getClass().getName(),".access");
+ }
+
+ BufferedWriter accessWriter = new BufferedWriter(new FileWriter(_accessFile,false));
+ accessWriter.write("#Last Updated By comment");
+ accessWriter.newLine();
+ accessWriter.write("#Date/time comment");
+ accessWriter.newLine();
+ accessWriter.write(TEST_USERNAME + "=" + MBeanInvocationHandlerImpl.READONLY);
+ accessWriter.newLine();
+ accessWriter.flush();
+ accessWriter.close();
+ }
+ catch (IOException e)
+ {
+ fail("Unable to create test access file: " + e.getMessage());
+ }
+
+ try{
+ _amqumMBean.setAccessFile(_accessFile.toString());
+ }
+ catch (Exception e)
+ {
+ fail("Unable to set access file: " + e.getMessage());
+ }
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/access/plugins/network/FirewallPluginTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/access/plugins/network/FirewallPluginTest.java
new file mode 100644
index 0000000000..ff1fb8c97d
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/access/plugins/network/FirewallPluginTest.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.server.security.access.plugins.network;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.qpid.codec.AMQCodecFactory;
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
+import org.apache.qpid.server.protocol.AMQMinaProtocolSession;
+import org.apache.qpid.server.protocol.TestIoSession;
+import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult;
+import org.apache.qpid.server.store.TestableMemoryMessageStore;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
+
+public class FirewallPluginTest extends TestCase
+{
+
+ public class RuleInfo
+ {
+ private String _access;
+ private String _network;
+ private String _hostname;
+
+ public void setAccess(String _access)
+ {
+ this._access = _access;
+ }
+
+ public String getAccess()
+ {
+ return _access;
+ }
+
+ public void setNetwork(String _network)
+ {
+ this._network = _network;
+ }
+
+ public String getNetwork()
+ {
+ return _network;
+ }
+
+ public void setHostname(String _hostname)
+ {
+ this._hostname = _hostname;
+ }
+
+ public String getHostname()
+ {
+ return _hostname;
+ }
+ }
+
+ private TestableMemoryMessageStore _store;
+ private VirtualHost _virtualHost;
+ private AMQMinaProtocolSession _session;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _store = new TestableMemoryMessageStore();
+ PropertiesConfiguration env = new PropertiesConfiguration();
+ _virtualHost = new VirtualHost(new VirtualHostConfiguration("test", env));
+ TestIoSession iosession = new TestIoSession();
+ iosession.setAddress("127.0.0.1");
+ VirtualHostRegistry virtualHostRegistry = null;
+ AMQCodecFactory codecFactory = new AMQCodecFactory(true);
+ _session = new AMQMinaProtocolSession(iosession, virtualHostRegistry, codecFactory);
+ }
+
+ private FirewallPlugin initialisePlugin(String defaultAction, RuleInfo[] rules) throws IOException, ConfigurationException
+ {
+ // Create sample config file
+ File confFile = File.createTempFile(getClass().getSimpleName()+"conffile", null);
+ confFile.deleteOnExit();
+ BufferedWriter buf = new BufferedWriter(new FileWriter(confFile));
+ buf.write("<firewall default-action=\""+defaultAction+"\">\n");
+ if (rules != null)
+ {
+ for (RuleInfo rule : rules)
+ {
+ buf.write("<rule");
+ buf.write(" access=\""+rule.getAccess()+"\"");
+ if (rule.getHostname() != null)
+ {
+ buf.write(" hostname=\""+rule.getHostname()+"\"");
+ }
+ if (rule.getNetwork() != null)
+ {
+ buf.write(" network=\""+rule.getNetwork()+"\"");
+ }
+ buf.write("/>\n");
+ }
+ }
+ buf.write("</firewall>");
+ buf.close();
+
+ // Configure plugin
+ FirewallPlugin plugin = new FirewallPlugin();
+ plugin.setConfiguration(new XMLConfiguration(confFile));
+ return plugin;
+ }
+
+ private FirewallPlugin initialisePlugin(String string) throws ConfigurationException, IOException
+ {
+ return initialisePlugin(string, null);
+ }
+
+ public void testDefaultAction() throws Exception
+ {
+ // Test simple deny
+ FirewallPlugin plugin = initialisePlugin("deny");
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Test simple allow
+ plugin = initialisePlugin("allow");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+
+ public void testSingleIPRule() throws Exception
+ {
+ RuleInfo rule = new RuleInfo();
+ rule.setAccess("allow");
+ rule.setNetwork("192.168.23.23");
+
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{rule});
+
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Set session IP so that we're connected from the right address
+ ((TestIoSession) _session.getIOSession()).setAddress("192.168.23.23");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testSingleNetworkRule() throws Exception
+ {
+ RuleInfo rule = new RuleInfo();
+ rule.setAccess("allow");
+ rule.setNetwork("192.168.23.0/24");
+
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{rule});
+
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Set session IP so that we're connected from the right address
+ ((TestIoSession) _session.getIOSession()).setAddress("192.168.23.23");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testSingleHostRule() throws Exception
+ {
+ RuleInfo rule = new RuleInfo();
+ rule.setAccess("allow");
+ rule.setHostname(new InetSocketAddress("127.0.0.1", 5672).getHostName());
+
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{rule});
+
+ // Set session IP so that we're connected from the right address
+ ((TestIoSession) _session.getIOSession()).setAddress("127.0.0.1");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testSingleHostWilcardRule() throws Exception
+ {
+ RuleInfo rule = new RuleInfo();
+ rule.setAccess("allow");
+ rule.setHostname(".*ocal.*");
+
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{rule});
+
+ // Set session IP so that we're connected from the right address
+ ((TestIoSession) _session.getIOSession()).setAddress("127.0.0.1");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testSeveralFirstAllowsAccess() throws Exception
+ {
+ RuleInfo firstRule = new RuleInfo();
+ firstRule.setAccess("allow");
+ firstRule.setNetwork("192.168.23.23");
+
+ RuleInfo secondRule = new RuleInfo();
+ secondRule.setAccess("deny");
+ secondRule.setNetwork("192.168.42.42");
+
+ RuleInfo thirdRule = new RuleInfo();
+ thirdRule.setAccess("deny");
+ thirdRule.setHostname("localhost");
+
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{firstRule, secondRule, thirdRule});
+
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Set session IP so that we're connected from the right address
+ ((TestIoSession) _session.getIOSession()).setAddress("192.168.23.23");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testSeveralLastAllowsAccess() throws Exception
+ {
+ RuleInfo firstRule = new RuleInfo();
+ firstRule.setAccess("deny");
+ firstRule.setHostname("localhost");
+
+ RuleInfo secondRule = new RuleInfo();
+ secondRule.setAccess("deny");
+ secondRule.setNetwork("192.168.42.42");
+
+ RuleInfo thirdRule = new RuleInfo();
+ thirdRule.setAccess("allow");
+ thirdRule.setNetwork("192.168.23.23");
+
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{firstRule, secondRule, thirdRule});
+
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Set session IP so that we're connected from the right address
+ ((TestIoSession) _session.getIOSession()).setAddress("192.168.23.23");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testNetmask() throws Exception
+ {
+ RuleInfo firstRule = new RuleInfo();
+ firstRule.setAccess("allow");
+ firstRule.setNetwork("192.168.23.0/24");
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{firstRule});
+
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Set session IP so that we're connected from the right address
+ ((TestIoSession) _session.getIOSession()).setAddress("192.168.23.23");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testCommaSeperatedNetmask() throws Exception
+ {
+ RuleInfo firstRule = new RuleInfo();
+ firstRule.setAccess("allow");
+ firstRule.setNetwork("10.1.1.1/8, 192.168.23.0/24");
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{firstRule});
+
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Set session IP so that we're connected from the right address
+ ((TestIoSession) _session.getIOSession()).setAddress("192.168.23.23");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+ public void testCommaSeperatedHostnames() throws Exception
+ {
+ RuleInfo firstRule = new RuleInfo();
+ firstRule.setAccess("allow");
+ firstRule.setHostname("foo, bar, "+new InetSocketAddress("127.0.0.1", 5672).getHostName());
+ FirewallPlugin plugin = initialisePlugin("deny", new RuleInfo[]{firstRule});
+ ((TestIoSession) _session.getIOSession()).setAddress("10.0.0.1");
+ assertEquals(AuthzResult.DENIED, plugin.authoriseConnect(_session, _virtualHost));
+
+ // Set session IP so that we're connected from the right address
+ ((TestIoSession) _session.getIOSession()).setAddress("127.0.0.1");
+ assertEquals(AuthzResult.ALLOWED, plugin.authoriseConnect(_session, _virtualHost));
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabaseTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabaseTest.java
new file mode 100644
index 0000000000..413b974986
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabaseTest.java
@@ -0,0 +1,447 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.auth.database;
+
+import junit.framework.TestCase;
+
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.login.AccountNotFoundException;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class Base64MD5PasswordFilePrincipalDatabaseTest extends TestCase
+{
+
+ private static final String TEST_COMMENT = "# Test Comment";
+
+ private static final String USERNAME = "testUser";
+ private static final String PASSWORD = "guest";
+ private static final String PASSWORD_B64MD5HASHED = "CE4DQ6BIb/BVMN9scFyLtA==";
+ private static char[] PASSWORD_MD5_CHARS;
+ private static final String PRINCIPAL_USERNAME = "testUserPrincipal";
+ private static final Principal PRINCIPAL = new UsernamePrincipal(PRINCIPAL_USERNAME);
+ private Base64MD5PasswordFilePrincipalDatabase _database;
+ private File _pwdFile;
+
+ static
+ {
+ try
+ {
+ Base64 b64 = new Base64();
+ byte[] md5passBytes = PASSWORD_B64MD5HASHED.getBytes(Base64MD5PasswordFilePrincipalDatabase.DEFAULT_ENCODING);
+ byte[] decoded = b64.decode(md5passBytes);
+
+ PASSWORD_MD5_CHARS = new char[decoded.length];
+
+ int index = 0;
+ for (byte c : decoded)
+ {
+ PASSWORD_MD5_CHARS[index++] = (char) c;
+ }
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ fail("Unable to perform B64 decode to get the md5 char[] password");
+ }
+ }
+
+
+ public void setUp() throws Exception
+ {
+ _database = new Base64MD5PasswordFilePrincipalDatabase();
+ _pwdFile = File.createTempFile(this.getClass().getName(), "pwd");
+ _pwdFile.deleteOnExit();
+ _database.setPasswordFile(_pwdFile.getAbsolutePath());
+ }
+
+ private File createPasswordFile(int commentLines, int users)
+ {
+ try
+ {
+ File testFile = File.createTempFile("Base64MD5PDPDTest","tmp");
+ testFile.deleteOnExit();
+
+ BufferedWriter writer = new BufferedWriter(new FileWriter(testFile));
+
+ for (int i = 0; i < commentLines; i++)
+ {
+ writer.write(TEST_COMMENT);
+ writer.newLine();
+ }
+
+ for (int i = 0; i < users; i++)
+ {
+ writer.write(USERNAME + i + ":Password");
+ writer.newLine();
+ }
+
+ writer.flush();
+ writer.close();
+
+ return testFile;
+
+ }
+ catch (IOException e)
+ {
+ fail("Unable to create test password file." + e.getMessage());
+ }
+
+ return null;
+ }
+
+ private void loadPasswordFile(File file)
+ {
+ try
+ {
+ _database.setPasswordFile(file.toString());
+ }
+ catch (IOException e)
+ {
+ fail("Password File was not created." + e.getMessage());
+ }
+ }
+
+ /** **** Test Methods ************** */
+
+ public void testCreatePrincipal()
+ {
+ File testFile = createPasswordFile(1, 0);
+
+ loadPasswordFile(testFile);
+
+
+ Principal principal = new Principal()
+ {
+ public String getName()
+ {
+ return USERNAME;
+ }
+ };
+
+ assertTrue("New user not created.", _database.createPrincipal(principal, PASSWORD.toCharArray()));
+
+ PasswordCallback callback = new PasswordCallback("prompt",false);
+ try
+ {
+ _database.setPassword(principal, callback);
+ }
+ catch (AccountNotFoundException e)
+ {
+ fail("user account did not exist");
+ }
+ assertTrue("Password returned was incorrect.", Arrays.equals(PASSWORD_MD5_CHARS, callback.getPassword()));
+
+ loadPasswordFile(testFile);
+
+ try
+ {
+ _database.setPassword(principal, callback);
+ }
+ catch (AccountNotFoundException e)
+ {
+ fail("user account did not exist");
+ }
+ assertTrue("Password returned was incorrect.", Arrays.equals(PASSWORD_MD5_CHARS, callback.getPassword()));
+
+ assertNotNull("Created User was not saved", _database.getUser(USERNAME));
+
+ assertFalse("Duplicate user created.", _database.createPrincipal(principal, PASSWORD.toCharArray()));
+
+ testFile.delete();
+ }
+
+ public void testCreatePrincipalIsSavedToFile()
+ {
+
+ File testFile = createPasswordFile(1, 0);
+
+ loadPasswordFile(testFile);
+
+ final String CREATED_PASSWORD = "guest";
+ final String CREATED_B64MD5HASHED_PASSWORD = "CE4DQ6BIb/BVMN9scFyLtA==";
+ final String CREATED_USERNAME = "createdUser";
+
+ Principal principal = new Principal()
+ {
+ public String getName()
+ {
+ return CREATED_USERNAME;
+ }
+ };
+
+ _database.createPrincipal(principal, CREATED_PASSWORD.toCharArray());
+
+ try
+ {
+ BufferedReader reader = new BufferedReader(new FileReader(testFile));
+
+ assertTrue("File has no content", reader.ready());
+
+ assertEquals("Comment line has been corrupted.", TEST_COMMENT, reader.readLine());
+
+ assertTrue("File is missing user data.", reader.ready());
+
+ String userLine = reader.readLine();
+
+ String[] result = Pattern.compile(":").split(userLine);
+
+ assertEquals("User line not complete '" + userLine + "'", 2, result.length);
+
+ assertEquals("Username not correct,", CREATED_USERNAME, result[0]);
+ assertEquals("Password not correct,", CREATED_B64MD5HASHED_PASSWORD, result[1]);
+
+ assertFalse("File has more content", reader.ready());
+
+ }
+ catch (IOException e)
+ {
+ fail("Unable to valdate file contents due to:" + e.getMessage());
+ }
+ testFile.delete();
+ }
+
+
+ public void testDeletePrincipal()
+ {
+ File testFile = createPasswordFile(1, 1);
+
+ loadPasswordFile(testFile);
+
+ Principal user = _database.getUser(USERNAME + "0");
+ assertNotNull("Generated user not present.", user);
+
+ try
+ {
+ _database.deletePrincipal(user);
+ }
+ catch (AccountNotFoundException e)
+ {
+ fail("User should be present" + e.getMessage());
+ }
+
+ try
+ {
+ _database.deletePrincipal(user);
+ fail("User should not be present");
+ }
+ catch (AccountNotFoundException e)
+ {
+ //pass
+ }
+
+ loadPasswordFile(testFile);
+
+ try
+ {
+ _database.deletePrincipal(user);
+ fail("User should not be present");
+ }
+ catch (AccountNotFoundException e)
+ {
+ //pass
+ }
+
+ assertNull("Deleted user still present.", _database.getUser(USERNAME + "0"));
+
+ testFile.delete();
+ }
+
+ public void testGetUsers()
+ {
+ int USER_COUNT = 10;
+ File testFile = createPasswordFile(1, USER_COUNT);
+
+ loadPasswordFile(testFile);
+
+ Principal user = _database.getUser("MISSING_USERNAME");
+ assertNull("Missing user present.", user);
+
+ List<Principal> users = _database.getUsers();
+
+ assertNotNull("Users list is null.", users);
+
+ assertEquals(USER_COUNT, users.size());
+
+ boolean[] verify = new boolean[USER_COUNT];
+ for (int i = 0; i < USER_COUNT; i++)
+ {
+ Principal principal = users.get(i);
+
+ assertNotNull("Generated user not present.", principal);
+
+ String name = principal.getName();
+
+ int id = Integer.parseInt(name.substring(USERNAME.length()));
+
+ assertFalse("Duplicated username retrieve", verify[id]);
+ verify[id] = true;
+ }
+
+ for (int i = 0; i < USER_COUNT; i++)
+ {
+ assertTrue("User " + i + " missing", verify[i]);
+ }
+
+ testFile.delete();
+ }
+
+ public void testUpdatePasswordIsSavedToFile()
+ {
+
+ File testFile = createPasswordFile(1, 1);
+
+ loadPasswordFile(testFile);
+
+ Principal testUser = _database.getUser(USERNAME + "0");
+
+ assertNotNull(testUser);
+
+ String NEW_PASSWORD = "guest";
+ String NEW_PASSWORD_HASH = "CE4DQ6BIb/BVMN9scFyLtA==";
+ try
+ {
+ _database.updatePassword(testUser, NEW_PASSWORD.toCharArray());
+ }
+ catch (AccountNotFoundException e)
+ {
+ fail(e.toString());
+ }
+
+ try
+ {
+ BufferedReader reader = new BufferedReader(new FileReader(testFile));
+
+ assertTrue("File has no content", reader.ready());
+
+ assertEquals("Comment line has been corrupted.", TEST_COMMENT, reader.readLine());
+
+ assertTrue("File is missing user data.", reader.ready());
+
+ String userLine = reader.readLine();
+
+ String[] result = Pattern.compile(":").split(userLine);
+
+ assertEquals("User line not complete '" + userLine + "'", 2, result.length);
+
+ assertEquals("Username not correct,", USERNAME + "0", result[0]);
+ assertEquals("New Password not correct,", NEW_PASSWORD_HASH, result[1]);
+
+ assertFalse("File has more content", reader.ready());
+
+ }
+ catch (IOException e)
+ {
+ fail("Unable to valdate file contents due to:" + e.getMessage());
+ }
+ testFile.delete();
+ }
+
+ public void testSetPasswordFileWithMissingFile()
+ {
+ try
+ {
+ _database.setPasswordFile("DoesntExist");
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ assertTrue(fnfe.getMessage(), fnfe.getMessage().startsWith("Cannot find password file"));
+ }
+ catch (IOException e)
+ {
+ fail("Password File was not created." + e.getMessage());
+ }
+
+ }
+
+ public void testSetPasswordFileWithReadOnlyFile()
+ {
+
+ File testFile = createPasswordFile(0, 0);
+
+ testFile.setReadOnly();
+
+ try
+ {
+ _database.setPasswordFile(testFile.toString());
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ assertTrue(fnfe.getMessage().startsWith("Cannot read password file "));
+ }
+ catch (IOException e)
+ {
+ fail("Password File was not created." + e.getMessage());
+ }
+
+ testFile.delete();
+ }
+
+ public void testCreateUserPrincipal() throws IOException
+ {
+ _database.createPrincipal(PRINCIPAL, PASSWORD.toCharArray());
+ Principal newPrincipal = _database.getUser(PRINCIPAL_USERNAME);
+ assertNotNull(newPrincipal);
+ assertEquals(PRINCIPAL.getName(), newPrincipal.getName());
+ }
+
+ public void testVerifyPassword() throws IOException, AccountNotFoundException
+ {
+ testCreateUserPrincipal();
+ //assertFalse(_pwdDB.verifyPassword(_username, null));
+ assertFalse(_database.verifyPassword(PRINCIPAL_USERNAME, new char[]{}));
+ assertFalse(_database.verifyPassword(PRINCIPAL_USERNAME, (PASSWORD+"z").toCharArray()));
+ assertTrue(_database.verifyPassword(PRINCIPAL_USERNAME, PASSWORD.toCharArray()));
+
+ try
+ {
+ _database.verifyPassword("made.up.username", PASSWORD.toCharArray());
+ fail("Should not have been able to verify this non-existant users password.");
+ }
+ catch (AccountNotFoundException e)
+ {
+ // pass
+ }
+ }
+
+ public void testUpdatePassword() throws IOException, AccountNotFoundException
+ {
+ testCreateUserPrincipal();
+ char[] newPwd = "newpassword".toCharArray();
+ _database.updatePassword(PRINCIPAL, newPwd);
+ assertFalse(_database.verifyPassword(PRINCIPAL_USERNAME, PASSWORD.toCharArray()));
+ assertTrue(_database.verifyPassword(PRINCIPAL_USERNAME, newPwd));
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/HashedUserTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/HashedUserTest.java
new file mode 100644
index 0000000000..aa85cac758
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/HashedUserTest.java
@@ -0,0 +1,95 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.auth.database;
+
+import junit.framework.TestCase;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+
+import java.io.UnsupportedEncodingException;
+
+/*
+ Note User is mainly tested by Base64MD5PFPDTest this is just to catch the extra methods
+ */
+public class HashedUserTest extends TestCase
+{
+
+ String USERNAME = "username";
+ String PASSWORD = "password";
+ String B64_ENCODED_PASSWORD = "cGFzc3dvcmQ=";
+
+ public void testToLongArrayConstructor()
+ {
+ try
+ {
+ HashedUser user = new HashedUser(new String[]{USERNAME, PASSWORD, USERNAME});
+ fail("Error expected");
+ }
+ catch (IllegalArgumentException e)
+ {
+ assertEquals("User Data should be length 2, username, password", e.getMessage());
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testArrayConstructor()
+ {
+ try
+ {
+ HashedUser user = new HashedUser(new String[]{USERNAME, B64_ENCODED_PASSWORD});
+ assertEquals("Username incorrect", USERNAME, user.getName());
+ int index = 0;
+
+ char[] hash = B64_ENCODED_PASSWORD.toCharArray();
+
+ try
+ {
+ for (byte c : user.getEncodedPassword())
+ {
+ assertEquals("Password incorrect", hash[index], (char) c);
+ index++;
+ }
+ }
+ catch (Exception e)
+ {
+ fail(e.getMessage());
+ }
+
+ hash = PASSWORD.toCharArray();
+
+ index=0;
+ for (char c : user.getPassword())
+ {
+ assertEquals("Password incorrect", hash[index], c);
+ index++;
+ }
+
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ fail(e.getMessage());
+ }
+ }
+}
+
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabaseTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabaseTest.java
new file mode 100644
index 0000000000..20b8d0a7b4
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabaseTest.java
@@ -0,0 +1,396 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.auth.database;
+
+import junit.framework.TestCase;
+
+import javax.security.auth.login.AccountNotFoundException;
+
+import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.security.Principal;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class PlainPasswordFilePrincipalDatabaseTest extends TestCase
+{
+
+ private static final String TEST_COMMENT = "# Test Comment";
+ private static final String TEST_PASSWORD = "testPassword";
+ private static final char[] TEST_PASSWORD_CHARS = TEST_PASSWORD.toCharArray();
+ private static final String TEST_USERNAME = "testUser";
+
+ private Principal _principal = new UsernamePrincipal(TEST_USERNAME);
+ private PlainPasswordFilePrincipalDatabase _database;
+
+ public void setUp() throws Exception
+ {
+ _database = new PlainPasswordFilePrincipalDatabase();
+ }
+
+ // ******* Test Methods ********** //
+
+ public void testCreatePrincipal()
+ {
+ File testFile = createPasswordFile(1, 0);
+
+ loadPasswordFile(testFile);
+
+ final String CREATED_PASSWORD = "guest";
+ final String CREATED_USERNAME = "createdUser";
+
+ Principal principal = new Principal()
+ {
+ public String getName()
+ {
+ return CREATED_USERNAME;
+ }
+ };
+
+ assertTrue("New user not created.", _database.createPrincipal(principal, CREATED_PASSWORD.toCharArray()));
+
+ loadPasswordFile(testFile);
+
+ assertNotNull("Created User was not saved", _database.getUser(CREATED_USERNAME));
+
+ assertFalse("Duplicate user created.", _database.createPrincipal(principal, CREATED_PASSWORD.toCharArray()));
+
+ testFile.delete();
+ }
+
+ public void testCreatePrincipalIsSavedToFile()
+ {
+
+ File testFile = createPasswordFile(1, 0);
+
+ loadPasswordFile(testFile);
+
+ Principal principal = new Principal()
+ {
+ public String getName()
+ {
+ return TEST_USERNAME;
+ }
+ };
+
+ _database.createPrincipal(principal, TEST_PASSWORD_CHARS);
+
+ try
+ {
+ BufferedReader reader = new BufferedReader(new FileReader(testFile));
+
+ assertTrue("File has no content", reader.ready());
+
+ assertEquals("Comment line has been corrupted.", TEST_COMMENT, reader.readLine());
+
+ assertTrue("File is missing user data.", reader.ready());
+
+ String userLine = reader.readLine();
+
+ String[] result = Pattern.compile(":").split(userLine);
+
+ assertEquals("User line not complete '" + userLine + "'", 2, result.length);
+
+ assertEquals("Username not correct,", TEST_USERNAME, result[0]);
+ assertEquals("Password not correct,", TEST_PASSWORD, result[1]);
+
+ assertFalse("File has more content", reader.ready());
+
+ }
+ catch (IOException e)
+ {
+ fail("Unable to valdate file contents due to:" + e.getMessage());
+ }
+ testFile.delete();
+ }
+
+ public void testDeletePrincipal()
+ {
+ File testFile = createPasswordFile(1, 1);
+
+ loadPasswordFile(testFile);
+
+ Principal user = _database.getUser(TEST_USERNAME + "0");
+ assertNotNull("Generated user not present.", user);
+
+ try
+ {
+ _database.deletePrincipal(user);
+ }
+ catch (AccountNotFoundException e)
+ {
+ fail("User should be present" + e.getMessage());
+ }
+
+ try
+ {
+ _database.deletePrincipal(user);
+ fail("User should not be present");
+ }
+ catch (AccountNotFoundException e)
+ {
+ //pass
+ }
+
+ loadPasswordFile(testFile);
+
+ try
+ {
+ _database.deletePrincipal(user);
+ fail("User should not be present");
+ }
+ catch (AccountNotFoundException e)
+ {
+ //pass
+ }
+
+ assertNull("Deleted user still present.", _database.getUser(TEST_USERNAME + "0"));
+
+ testFile.delete();
+ }
+
+ public void testGetUsers()
+ {
+ int USER_COUNT = 10;
+ File testFile = createPasswordFile(1, USER_COUNT);
+
+ loadPasswordFile(testFile);
+
+ Principal user = _database.getUser("MISSING_USERNAME");
+ assertNull("Missing user present.", user);
+
+ List<Principal> users = _database.getUsers();
+
+ assertNotNull("Users list is null.", users);
+
+ assertEquals(USER_COUNT, users.size());
+
+ boolean[] verify = new boolean[USER_COUNT];
+ for (int i = 0; i < USER_COUNT; i++)
+ {
+ Principal principal = users.get(i);
+
+ assertNotNull("Generated user not present.", principal);
+
+ String name = principal.getName();
+
+ int id = Integer.parseInt(name.substring(TEST_USERNAME.length()));
+
+ assertFalse("Duplicated username retrieve", verify[id]);
+ verify[id] = true;
+ }
+
+ for (int i = 0; i < USER_COUNT; i++)
+ {
+ assertTrue("User " + i + " missing", verify[i]);
+ }
+
+ testFile.delete();
+ }
+
+ public void testUpdatePasswordIsSavedToFile()
+ {
+
+ File testFile = createPasswordFile(1, 1);
+
+ loadPasswordFile(testFile);
+
+ Principal testUser = _database.getUser(TEST_USERNAME + "0");
+
+ assertNotNull(testUser);
+
+ String NEW_PASSWORD = "NewPassword";
+ try
+ {
+ _database.updatePassword(testUser, NEW_PASSWORD.toCharArray());
+ }
+ catch (AccountNotFoundException e)
+ {
+ fail(e.toString());
+ }
+
+ try
+ {
+ BufferedReader reader = new BufferedReader(new FileReader(testFile));
+
+ assertTrue("File has no content", reader.ready());
+
+ assertEquals("Comment line has been corrupted.", TEST_COMMENT, reader.readLine());
+
+ assertTrue("File is missing user data.", reader.ready());
+
+ String userLine = reader.readLine();
+
+ String[] result = Pattern.compile(":").split(userLine);
+
+ assertEquals("User line not complete '" + userLine + "'", 2, result.length);
+
+ assertEquals("Username not correct,", TEST_USERNAME + "0", result[0]);
+ assertEquals("New Password not correct,", NEW_PASSWORD, result[1]);
+
+ assertFalse("File has more content", reader.ready());
+
+ }
+ catch (IOException e)
+ {
+ fail("Unable to valdate file contents due to:" + e.getMessage());
+ }
+ testFile.delete();
+ }
+
+ public void testSetPasswordFileWithMissingFile()
+ {
+ try
+ {
+ _database.setPasswordFile("DoesntExist");
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ assertTrue(fnfe.getMessage(), fnfe.getMessage().startsWith("Cannot find password file"));
+ }
+ catch (IOException e)
+ {
+ fail("Password File was not created." + e.getMessage());
+ }
+
+ }
+
+ public void testSetPasswordFileWithReadOnlyFile()
+ {
+
+ File testFile = createPasswordFile(0, 0);
+
+ testFile.setReadOnly();
+
+ try
+ {
+ _database.setPasswordFile(testFile.toString());
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ assertTrue(fnfe.getMessage().startsWith("Cannot read password file "));
+ }
+ catch (IOException e)
+ {
+ fail("Password File was not created." + e.getMessage());
+ }
+
+ testFile.delete();
+ }
+
+ private void createUserPrincipal() throws IOException
+ {
+ File testFile = createPasswordFile(0, 0);
+ loadPasswordFile(testFile);
+
+ _database.createPrincipal(_principal, TEST_PASSWORD_CHARS);
+ Principal newPrincipal = _database.getUser(TEST_USERNAME);
+ assertNotNull(newPrincipal);
+ assertEquals(_principal.getName(), newPrincipal.getName());
+ }
+
+ public void testVerifyPassword() throws IOException, AccountNotFoundException
+ {
+ createUserPrincipal();
+ assertFalse(_database.verifyPassword(TEST_USERNAME, new char[]{}));
+ assertFalse(_database.verifyPassword(TEST_USERNAME, "massword".toCharArray()));
+ assertTrue(_database.verifyPassword(TEST_USERNAME, TEST_PASSWORD_CHARS));
+
+ try
+ {
+ _database.verifyPassword("made.up.username", TEST_PASSWORD_CHARS);
+ fail("Should not have been able to verify this non-existant users password.");
+ }
+ catch (AccountNotFoundException e)
+ {
+ // pass
+ }
+ }
+
+ public void testUpdatePassword() throws IOException, AccountNotFoundException
+ {
+ createUserPrincipal();
+ char[] newPwd = "newpassword".toCharArray();
+ _database.updatePassword(_principal, newPwd);
+ assertFalse(_database.verifyPassword(TEST_USERNAME, TEST_PASSWORD_CHARS));
+ assertTrue(_database.verifyPassword(TEST_USERNAME, newPwd));
+ }
+
+
+
+ // *********** Utility Methods ******** //
+
+ private File createPasswordFile(int commentLines, int users)
+ {
+ try
+ {
+ File testFile = File.createTempFile(this.getClass().getName(),"tmp");
+ testFile.deleteOnExit();
+
+ BufferedWriter writer = new BufferedWriter(new FileWriter(testFile));
+
+ for (int i = 0; i < commentLines; i++)
+ {
+ writer.write(TEST_COMMENT);
+ writer.newLine();
+ }
+
+ for (int i = 0; i < users; i++)
+ {
+ writer.write(TEST_USERNAME + i + ":" + TEST_PASSWORD);
+ writer.newLine();
+ }
+
+ writer.flush();
+ writer.close();
+
+ return testFile;
+
+ }
+ catch (IOException e)
+ {
+ fail("Unable to create test password file." + e.getMessage());
+ }
+
+ return null;
+ }
+
+ private void loadPasswordFile(File file)
+ {
+ try
+ {
+ _database.setPasswordFile(file.toString());
+ }
+ catch (IOException e)
+ {
+ fail("Password File was not created." + e.getMessage());
+ }
+ }
+
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainUserTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainUserTest.java
new file mode 100644
index 0000000000..7f0843d46e
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainUserTest.java
@@ -0,0 +1,78 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.security.auth.database;
+
+import junit.framework.TestCase;
+
+/*
+ Note PlainUser is mainly tested by PlainPFPDTest, this is just to catch the extra methods
+ */
+public class PlainUserTest extends TestCase
+{
+
+ String USERNAME = "username";
+ String PASSWORD = "password";
+
+ public void testTooLongArrayConstructor()
+ {
+ try
+ {
+ PlainUser user = new PlainUser(new String[]{USERNAME, PASSWORD, USERNAME});
+ fail("Error expected");
+ }
+ catch (IllegalArgumentException e)
+ {
+ assertEquals("User Data should be length 2, username, password", e.getMessage());
+ }
+ }
+
+ public void testStringArrayConstructor()
+ {
+ PlainUser user = new PlainUser(new String[]{USERNAME, PASSWORD});
+ assertEquals("Username incorrect", USERNAME, user.getName());
+ int index = 0;
+
+ char[] password = PASSWORD.toCharArray();
+
+ try
+ {
+ for (byte c : user.getPasswordBytes())
+ {
+ assertEquals("Password incorrect", password[index], (char) c);
+ index++;
+ }
+ }
+ catch (Exception e)
+ {
+ fail(e.getMessage());
+ }
+
+ password = PASSWORD.toCharArray();
+
+ index=0;
+ for (char c : user.getPassword())
+ {
+ assertEquals("Password incorrect", password[index], c);
+ index++;
+ }
+ }
+}
+
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java
new file mode 100644
index 0000000000..e8c24da68d
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.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.server.security.auth.rmi;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Collections;
+
+import javax.management.remote.JMXPrincipal;
+import javax.security.auth.Subject;
+
+import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrincipalDatabase;
+import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase;
+
+import junit.framework.TestCase;
+
+public class RMIPasswordAuthenticatorTest extends TestCase
+{
+ private final String USERNAME = "guest";
+ private final String PASSWORD = "guest";
+ private final String B64_MD5HASHED_PASSWORD = "CE4DQ6BIb/BVMN9scFyLtA==";
+ private RMIPasswordAuthenticator _rmipa;
+
+ private Base64MD5PasswordFilePrincipalDatabase _md5Pd;
+ private File _md5PwdFile;
+
+ private PlainPasswordFilePrincipalDatabase _plainPd;
+ private File _plainPwdFile;
+
+ private Subject testSubject;
+
+ protected void setUp() throws Exception
+ {
+ _rmipa = new RMIPasswordAuthenticator();
+
+ _md5Pd = new Base64MD5PasswordFilePrincipalDatabase();
+ _md5PwdFile = createTempPasswordFile(this.getClass().getName()+"md5pwd", USERNAME, B64_MD5HASHED_PASSWORD);
+ _md5Pd.setPasswordFile(_md5PwdFile.getAbsolutePath());
+
+ _plainPd = new PlainPasswordFilePrincipalDatabase();
+ _plainPwdFile = createTempPasswordFile(this.getClass().getName()+"plainpwd", USERNAME, PASSWORD);
+ _plainPd.setPasswordFile(_plainPwdFile.getAbsolutePath());
+
+ testSubject = new Subject(true,
+ Collections.singleton(new JMXPrincipal(USERNAME)),
+ Collections.EMPTY_SET,
+ Collections.EMPTY_SET);
+ }
+
+ private File createTempPasswordFile(String filenamePrefix, String user, String password)
+ {
+ try
+ {
+ File testFile = File.createTempFile(filenamePrefix,"tmp");
+ testFile.deleteOnExit();
+
+ BufferedWriter writer = new BufferedWriter(new FileWriter(testFile));
+
+ writer.write(user + ":" + password);
+ writer.newLine();
+
+ writer.flush();
+ writer.close();
+
+ return testFile;
+ }
+ catch (IOException e)
+ {
+ fail("Unable to create temporary test password file." + e.getMessage());
+ }
+
+ return null;
+ }
+
+
+ //********** Test Methods *********//
+
+
+ public void testAuthenticate()
+ {
+ String[] credentials;
+ Subject newSubject;
+
+ // Test when no PD has been set
+ try
+ {
+ credentials = new String[]{USERNAME, PASSWORD};
+ newSubject = _rmipa.authenticate(credentials);
+ fail("SecurityException expected due to lack of principal database");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.UNABLE_TO_LOOKUP, se.getMessage());
+ }
+
+ //The PrincipalDatabase's are tested primarily by their own tests, but
+ //minimal tests are done here to exercise their usage in this area.
+
+ // Test correct passwords are verified with an MD5 PD
+ try
+ {
+ _rmipa.setPrincipalDatabase(_md5Pd);
+ credentials = new String[]{USERNAME, PASSWORD};
+ newSubject = _rmipa.authenticate(credentials);
+ assertTrue("Returned subject does not equal expected value",
+ newSubject.equals(testSubject));
+ }
+ catch (Exception e)
+ {
+ fail("Unexpected Exception:" + e.getMessage());
+ }
+
+ // Test incorrect passwords are not verified with an MD5 PD
+ try
+ {
+ credentials = new String[]{USERNAME, PASSWORD+"incorrect"};
+ newSubject = _rmipa.authenticate(credentials);
+ fail("SecurityException expected due to incorrect password");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.INVALID_CREDENTIALS, se.getMessage());
+ }
+
+ // Test non-existent accounts are not verified with an MD5 PD
+ try
+ {
+ credentials = new String[]{USERNAME+"invalid", PASSWORD};
+ newSubject = _rmipa.authenticate(credentials);
+ fail("SecurityException expected due to non-existant account");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.INVALID_CREDENTIALS, se.getMessage());
+ }
+
+ // Test correct passwords are verified with a Plain PD
+ try
+ {
+ _rmipa.setPrincipalDatabase(_plainPd);
+ credentials = new String[]{USERNAME, PASSWORD};
+ newSubject = _rmipa.authenticate(credentials);
+ assertTrue("Returned subject does not equal expected value",
+ newSubject.equals(testSubject));
+ }
+ catch (Exception e)
+ {
+ fail("Unexpected Exception");
+ }
+
+ // Test incorrect passwords are not verified with a Plain PD
+ try
+ {
+ credentials = new String[]{USERNAME, PASSWORD+"incorrect"};
+ newSubject = _rmipa.authenticate(credentials);
+ fail("SecurityException expected due to incorrect password");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.INVALID_CREDENTIALS, se.getMessage());
+ }
+
+ // Test non-existent accounts are not verified with an Plain PD
+ try
+ {
+ credentials = new String[]{USERNAME+"invalid", PASSWORD};
+ newSubject = _rmipa.authenticate(credentials);
+ fail("SecurityException expected due to non existant account");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.INVALID_CREDENTIALS, se.getMessage());
+ }
+
+ // Test handling of non-string credential's
+ try
+ {
+ Object[] objCredentials = new Object[]{USERNAME, PASSWORD};
+ newSubject = _rmipa.authenticate(objCredentials);
+ fail("SecurityException expected due to non string[] credentials");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.SHOULD_BE_STRING_ARRAY, se.getMessage());
+ }
+
+ // Test handling of incorrect number of credential's
+ try
+ {
+ credentials = new String[]{USERNAME, PASSWORD, PASSWORD};
+ newSubject = _rmipa.authenticate(credentials);
+ fail("SecurityException expected due to supplying wrong number of credentials");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.SHOULD_HAVE_2_ELEMENTS, se.getMessage());
+ }
+
+ // Test handling of null credential's
+ try
+ {
+ //send a null array
+ credentials = null;
+ newSubject = _rmipa.authenticate(credentials);
+ fail("SecurityException expected due to not supplying an array of credentials");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.CREDENTIALS_REQUIRED, se.getMessage());
+ }
+
+ try
+ {
+ //send a null password
+ credentials = new String[]{USERNAME, null};
+ newSubject = _rmipa.authenticate(credentials);
+ fail("SecurityException expected due to sending a null password");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.SHOULD_BE_NON_NULL, se.getMessage());
+ }
+
+ try
+ {
+ //send a null username
+ credentials = new String[]{null, PASSWORD};
+ newSubject = _rmipa.authenticate(credentials);
+ fail("SecurityException expected due to sending a null username");
+ }
+ catch (SecurityException se)
+ {
+ assertEquals("Unexpected exception message",
+ RMIPasswordAuthenticator.SHOULD_BE_NON_NULL, se.getMessage());
+ }
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/SaslServerTestCase.java b/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/SaslServerTestCase.java
new file mode 100644
index 0000000000..f80413d4f8
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/SaslServerTestCase.java
@@ -0,0 +1,66 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.security.auth.sasl;
+
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+
+import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
+
+import junit.framework.TestCase;
+
+public abstract class SaslServerTestCase extends TestCase
+{
+ protected SaslServer server;
+ protected String username = "u";
+ protected String password = "p";
+ protected String notpassword = "a";
+ protected PrincipalDatabase db = new TestPrincipalDatabase();
+
+ protected byte[] correctresponse;
+ protected byte[] wrongresponse;
+
+ public void testSucessfulAuth() throws SaslException
+ {
+ byte[] resp = this.server.evaluateResponse(correctresponse);
+ assertNull(resp);
+ }
+
+ public void testFailAuth()
+ {
+ boolean exceptionCaught = false;
+ try
+ {
+ byte[] resp = this.server.evaluateResponse(wrongresponse);
+ }
+ catch (SaslException e)
+ {
+ assertEquals("Authentication failed", e.getCause().getMessage());
+ exceptionCaught = true;
+ }
+ if (!exceptionCaught)
+ {
+ fail("Should have thrown SaslException");
+ }
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/TestPrincipalDatabase.java b/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/TestPrincipalDatabase.java
new file mode 100644
index 0000000000..8507e49e17
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/TestPrincipalDatabase.java
@@ -0,0 +1,91 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.security.auth.sasl;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.List;
+import java.util.Map;
+
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.login.AccountNotFoundException;
+
+import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
+import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser;
+
+public class TestPrincipalDatabase implements PrincipalDatabase
+{
+
+ public boolean createPrincipal(Principal principal, char[] password)
+ {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean deletePrincipal(Principal principal) throws AccountNotFoundException
+ {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public Map<String, AuthenticationProviderInitialiser> getMechanisms()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Principal getUser(String username)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public List<Principal> getUsers()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void setPassword(Principal principal, PasswordCallback callback) throws IOException,
+ AccountNotFoundException
+ {
+ callback.setPassword("p".toCharArray());
+ }
+
+ public boolean updatePassword(Principal principal, char[] password) throws AccountNotFoundException
+ {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean verifyPassword(String principal, char[] password) throws AccountNotFoundException
+ {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void reload() throws IOException
+ {
+ // TODO Auto-generated method stub
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/amqplain/AMQPlainSaslServerTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/amqplain/AMQPlainSaslServerTest.java
new file mode 100644
index 0000000000..6245064bf7
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/amqplain/AMQPlainSaslServerTest.java
@@ -0,0 +1,43 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.security.auth.sasl.amqplain;
+
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.FieldTableFactory;
+import org.apache.qpid.server.security.auth.sasl.SaslServerTestCase;
+import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser;
+
+public class AMQPlainSaslServerTest extends SaslServerTestCase
+{
+ protected void setUp() throws Exception
+ {
+ UsernamePasswordInitialiser handler = new AmqPlainInitialiser();
+ handler.initialise(db);
+ this.server = new AmqPlainSaslServer(handler.getCallbackHandler());
+ FieldTable table = FieldTableFactory.newFieldTable();
+ table.setString("LOGIN", username);
+ table.setString("PASSWORD", password);
+ correctresponse = table.getDataAsBytes();
+ table.setString("PASSWORD", notpassword);
+ wrongresponse = table.getDataAsBytes();
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerTest.java b/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerTest.java
new file mode 100644
index 0000000000..5dd51250dc
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerTest.java
@@ -0,0 +1,39 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.security.auth.sasl.plain;
+
+import org.apache.qpid.server.security.auth.sasl.SaslServerTestCase;
+import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser;
+
+public class PlainSaslServerTest extends SaslServerTestCase
+{
+
+ protected void setUp() throws Exception
+ {
+ UsernamePasswordInitialiser handler = new PlainInitialiser();
+ handler.initialise(db);
+ this.server = new PlainSaslServer(handler.getCallbackHandler());
+ correctresponse = new byte[]{0x0, (byte) username.charAt(0), 0x0, (byte) password.charAt(0)};
+ wrongresponse = new byte[]{0x0,(byte) username.charAt(0), 0x0, (byte) notpassword.charAt(0)};
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreShutdownTest.java b/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreShutdownTest.java
new file mode 100644
index 0000000000..a695a67eea
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreShutdownTest.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.server.store;
+
+import org.apache.qpid.server.util.InternalBrokerBaseCase;
+import org.apache.qpid.server.protocol.InternalTestProtocolSession;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+
+import java.util.List;
+
+public class MessageStoreShutdownTest extends InternalBrokerBaseCase
+{
+
+ public void test()
+ {
+ subscribe(_session, _channel, _queue);
+
+ try
+ {
+ publishMessages(_session, _channel, 1);
+ }
+ catch (AMQException e)
+ {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ fail(e.getMessage());
+ }
+
+ try
+ {
+ _registry.close();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ fail(e.getMessage());
+ }
+
+ assertTrue("Session should now be closed", _session.isClosed());
+
+
+ //Test attempting to modify the broker state after session has been closed.
+
+ //The Message should have been removed from the unacked list.
+
+ //Ack Messages
+ List<InternalTestProtocolSession.DeliveryPair> list = _session.getDelivers(_channel.getChannelId(), new AMQShortString("sgen_1"), 1);
+
+ InternalTestProtocolSession.DeliveryPair pair = list.get(0);
+
+ try
+ {
+ // The message should now be requeued and so unable to ack it.
+ _channel.acknowledgeMessage(pair.getDeliveryTag(), false);
+ }
+ catch (AMQException e)
+ {
+ assertEquals("Incorrect exception thrown", "Single ack on delivery tag 1 not known for channel:1", e.getMessage());
+ }
+
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java b/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java
new file mode 100644
index 0000000000..4317a501ed
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java
@@ -0,0 +1,646 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.store;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
+import org.apache.qpid.server.exchange.DirectExchange;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.exchange.ExchangeType;
+import org.apache.qpid.server.exchange.TopicExchange;
+import org.apache.qpid.server.exchange.ExchangeRegistry;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.apache.qpid.server.queue.IncomingMessage;
+import org.apache.qpid.server.queue.MessageHandleFactory;
+import org.apache.qpid.server.queue.QueueRegistry;
+import org.apache.qpid.server.queue.AMQPriorityQueue;
+import org.apache.qpid.server.queue.SimpleAMQQueue;
+import org.apache.qpid.server.queue.ExchangeBinding;
+import org.apache.qpid.server.txn.NonTransactionalContext;
+import org.apache.qpid.server.protocol.InternalTestProtocolSession;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.amqp_8_0.BasicConsumeBodyImpl;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.common.AMQPFilterTypes;
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * This tests the MessageStores by using the available interfaces.
+ *
+ * This test validates that Exchanges, Queues, Bindings and Messages are persisted correctly.
+ */
+public class MessageStoreTest extends TestCase
+{
+
+ private static final int DEFAULT_PRIORTY_LEVEL = 5;
+ private static final Logger _logger = LoggerFactory.getLogger(MessageStoreTest.class);
+
+ public void testMemoryMessageStore()
+ {
+
+ PropertiesConfiguration config = new PropertiesConfiguration();
+
+ config.addProperty("store.class", "org.apache.qpid.server.store.MemoryMessageStore");
+
+ runTestWithStore(config);
+ }
+
+ public void DISABLE_testDerbyMessageStore()
+ {
+ PropertiesConfiguration config = new PropertiesConfiguration();
+
+ config.addProperty("store.environment-path", "derbyDB_MST");
+ config.addProperty("store.class", "org.apache.qpid.server.store.DerbyMessageStore");
+
+ runTestWithStore(config);
+ }
+
+ private void reload(Configuration configuration)
+ {
+ if (_virtualHost != null)
+ {
+ try
+ {
+ _virtualHost.close();
+ }
+ catch (Exception e)
+ {
+ fail(e.getMessage());
+ }
+ }
+
+ try
+ {
+ _virtualHost = new VirtualHost(new VirtualHostConfiguration(getClass().getName(), configuration));
+ ApplicationRegistry.getInstance().getVirtualHostRegistry().registerVirtualHost(_virtualHost);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+
+ VirtualHost _virtualHost = null;
+ String virtualHostName = "MessageStoreTest";
+
+ AMQShortString nonDurableExchangeName = new AMQShortString("MST-NonDurableDirectExchange");
+ AMQShortString directExchangeName = new AMQShortString("MST-DirectExchange");
+ AMQShortString topicExchangeName = new AMQShortString("MST-TopicExchange");
+ AMQShortString queueOwner = new AMQShortString("MST");
+
+ AMQShortString durablePriorityTopicQueueName = new AMQShortString("MST-PriorityTopicQueue-Durable");
+ AMQShortString durableTopicQueueName = new AMQShortString("MST-TopicQueue-Durable");
+ AMQShortString priorityTopicQueueName = new AMQShortString("MST-PriorityTopicQueue");
+ AMQShortString topicQueueName = new AMQShortString("MST-TopicQueue");
+
+ AMQShortString durablePriorityQueueName = new AMQShortString("MST-PriorityQueue-Durable");
+ AMQShortString durableQueueName = new AMQShortString("MST-Queue-Durable");
+ AMQShortString priorityQueueName = new AMQShortString("MST-PriorityQueue");
+ AMQShortString queueName = new AMQShortString("MST-Queue");
+
+ AMQShortString directRouting = new AMQShortString("MST-direct");
+ AMQShortString topicRouting = new AMQShortString("MST-topic");
+
+ protected void setUp()
+ {
+ ApplicationRegistry.getInstance(1);
+ }
+
+ protected void tearDown()
+ {
+ ApplicationRegistry.remove(1);
+ }
+
+ protected void runTestWithStore(Configuration configuration)
+ {
+ //Ensure Environment Path is empty
+ cleanup(configuration);
+
+ //Load the Virtualhost with the required MessageStore
+ reload(configuration);
+
+ MessageStore messageStore = _virtualHost.getMessageStore();
+
+ createAllQueues();
+ createAllTopicQueues();
+
+ //Register Non-Durable DirectExchange
+ Exchange nonDurableExchange = createExchange(DirectExchange.TYPE, nonDurableExchangeName, false);
+ bindAllQueuesToExchange(nonDurableExchange, directRouting);
+
+ //Register DirectExchange
+ Exchange directExchange = createExchange(DirectExchange.TYPE, directExchangeName, true);
+ bindAllQueuesToExchange(directExchange, directRouting);
+
+ //Register TopicExchange
+ Exchange topicExchange = createExchange(TopicExchange.TYPE, topicExchangeName, true);
+ bindAllTopicQueuesToExchange(topicExchange, topicRouting);
+
+ //Send Message To NonDurable direct Exchange = persistent
+ sendMessageOnExchange(nonDurableExchange, directRouting, true);
+ // and non-persistent
+ sendMessageOnExchange(nonDurableExchange, directRouting, false);
+
+ //Send Message To direct Exchange = persistent
+ sendMessageOnExchange(directExchange, directRouting, true);
+ // and non-persistent
+ sendMessageOnExchange(directExchange, directRouting, false);
+
+ //Send Message To topic Exchange = persistent
+ sendMessageOnExchange(topicExchange, topicRouting, true);
+ // and non-persistent
+ sendMessageOnExchange(topicExchange, topicRouting, false);
+
+ //Ensure all the Queues have four messages (one transient, one persistent) x 2 exchange routings
+ validateMessageOnQueues(4, true);
+ //Ensure all the topics have two messages (one transient, one persistent)
+ validateMessageOnTopics(2, true);
+
+ assertEquals("Not all queues correctly registered", 8, _virtualHost.getQueueRegistry().getQueues().size());
+
+ if (!messageStore.isPersistent())
+ {
+ _logger.warn("Unable to test Persistent capabilities of messages store(" + messageStore.getClass() + ") as it is not capable of peristence.");
+ return;
+ }
+
+ //Reload the Virtualhost to test persistence
+ _logger.info("Reloading Virtualhost");
+
+ VirtualHost original = _virtualHost;
+
+ reload(configuration);
+
+ assertTrue("Virtualhost has not been reloaded", original != _virtualHost);
+
+ validateExchanges();
+
+ //Validate Durable Queues still have the persistentn message
+ validateMessageOnQueues(2, false);
+ //Validate Durable Queues still have the persistentn message
+ validateMessageOnTopics(1, false);
+
+ //Validate Properties of Binding
+ validateBindingProperties();
+
+ //Validate Properties of Queues
+ validateQueueProperties();
+
+ //Validate Non-Durable Queues are gone.
+ assertNull("Non-Durable queue still registered:" + priorityQueueName, _virtualHost.getQueueRegistry().getQueue(priorityQueueName));
+ assertNull("Non-Durable queue still registered:" + queueName, _virtualHost.getQueueRegistry().getQueue(queueName));
+ assertNull("Non-Durable queue still registered:" + priorityTopicQueueName, _virtualHost.getQueueRegistry().getQueue(priorityTopicQueueName));
+ assertNull("Non-Durable queue still registered:" + topicQueueName, _virtualHost.getQueueRegistry().getQueue(topicQueueName));
+
+ assertEquals("Not all queues correctly registered", 4, _virtualHost.getQueueRegistry().getQueues().size());
+ }
+
+ private void validateExchanges()
+ {
+ ExchangeRegistry registry = _virtualHost.getExchangeRegistry();
+
+ assertTrue(directExchangeName + " exchange NOT reloaded after failover",
+ registry.getExchangeNames().contains(directExchangeName));
+ assertTrue(topicExchangeName + " exchange NOT reloaded after failover",
+ registry.getExchangeNames().contains(topicExchangeName));
+ assertTrue(nonDurableExchangeName + " exchange reloaded after failover",
+ !registry.getExchangeNames().contains(nonDurableExchangeName));
+
+ // There are 5 required exchanges + our 2 durable queues
+ assertEquals("Incorrect number of exchanges available", 5 + 2, registry.getExchangeNames().size());
+ }
+
+ /** Validates that the Durable queues */
+ private void validateBindingProperties()
+ {
+ QueueRegistry queueRegistry = _virtualHost.getQueueRegistry();
+
+ validateBindingProperties(queueRegistry.getQueue(durablePriorityQueueName).getExchangeBindings(), false);
+ validateBindingProperties(queueRegistry.getQueue(durablePriorityTopicQueueName).getExchangeBindings(), true);
+ validateBindingProperties(queueRegistry.getQueue(durableQueueName).getExchangeBindings(), false);
+ validateBindingProperties(queueRegistry.getQueue(durableTopicQueueName).getExchangeBindings(), true);
+ }
+
+ /**
+ * Validate that each queue is bound once.
+ *
+ * @param bindings the set of bindings to validate
+ * @param useSelectors if set validate that the binding has a JMS_SELECTOR argument
+ */
+ private void validateBindingProperties(List<ExchangeBinding> bindings, boolean useSelectors)
+ {
+ assertEquals("Each queue should only be bound once.", 1, bindings.size());
+
+ ExchangeBinding binding = bindings.get(0);
+
+ if (useSelectors)
+ {
+ assertTrue("Binding does not contain a Selector argument.",
+ binding.getArguments().containsKey(AMQPFilterTypes.JMS_SELECTOR.getValue()));
+ }
+ }
+
+ private void validateQueueProperties()
+ {
+ QueueRegistry queueRegistry = _virtualHost.getQueueRegistry();
+
+ validateQueueProperties(queueRegistry.getQueue(durablePriorityQueueName), true);
+ validateQueueProperties(queueRegistry.getQueue(durablePriorityTopicQueueName), true);
+ validateQueueProperties(queueRegistry.getQueue(durableQueueName), false);
+ validateQueueProperties(queueRegistry.getQueue(durableTopicQueueName), false);
+
+ }
+
+ private void validateQueueProperties(AMQQueue queue, boolean usePriority)
+ {
+ if (usePriority)
+ {
+ assertEquals("Queue is no longer a Priority Queue", AMQPriorityQueue.class, queue.getClass());
+ assertEquals("Priority Queue does not have set priorities", DEFAULT_PRIORTY_LEVEL, ((AMQPriorityQueue) queue).getPriorities());
+ }
+ else
+ {
+ assertEquals("Queue is no longer a Priority Queue", SimpleAMQQueue.class, queue.getClass());
+ }
+ }
+
+ /**
+ * Delete the Store Environment path
+ *
+ * @param configuration The configuration that contains the store environment path.
+ */
+ private void cleanup(Configuration configuration)
+ {
+
+ String environment = configuration.getString("store.environment-path");
+
+ if (environment != null)
+ {
+ File environmentPath = new File(environment);
+
+ if (environmentPath.exists())
+ {
+ deleteDirectory(environmentPath);
+ }
+ }
+ }
+
+ private void deleteDirectory(File path)
+ {
+ if (path.isDirectory())
+ {
+ for (File file : path.listFiles())
+ {
+ deleteDirectory(file);
+ }
+ }
+ else
+ {
+ path.delete();
+ }
+ }
+
+ private void sendMessageOnExchange(Exchange directExchange, AMQShortString routingKey, boolean deliveryMode)
+ {
+ //Set MessagePersustebce
+ BasicContentHeaderProperties properties = new BasicContentHeaderProperties();
+ properties.setDeliveryMode(deliveryMode ? Integer.valueOf(2).byteValue() : Integer.valueOf(1).byteValue());
+ FieldTable headers = properties.getHeaders();
+ headers.setString("Test", "MST");
+ properties.setHeaders(headers);
+
+ MessagePublishInfo messageInfo = new TestMessagePublishInfo(directExchange, false, false, routingKey);
+
+ IncomingMessage currentMessage = null;
+
+ try
+ {
+ currentMessage = new IncomingMessage(_virtualHost.getMessageStore().getNewMessageId(),
+ messageInfo,
+ new NonTransactionalContext(_virtualHost.getMessageStore(),
+ new StoreContext(), null, null),
+ new InternalTestProtocolSession());
+ }
+ catch (AMQException e)
+ {
+ fail(e.getMessage());
+ }
+
+ currentMessage.setMessageStore(_virtualHost.getMessageStore());
+ currentMessage.setExchange(directExchange);
+
+ ContentHeaderBody headerBody = new ContentHeaderBody();
+ headerBody.classId = BasicConsumeBodyImpl.CLASS_ID;
+ headerBody.bodySize = 0;
+
+ headerBody.properties = properties;
+
+ try
+ {
+ currentMessage.setContentHeaderBody(headerBody);
+ }
+ catch (AMQException e)
+ {
+ fail(e.getMessage());
+ }
+
+ currentMessage.setExpiration();
+
+ try
+ {
+ currentMessage.route();
+ }
+ catch (AMQException e)
+ {
+ fail(e.getMessage());
+ }
+
+ try
+ {
+ currentMessage.routingComplete(_virtualHost.getMessageStore(), new MessageHandleFactory());
+ }
+ catch (AMQException e)
+ {
+ fail(e.getMessage());
+ }
+
+ // check and deliver if header says body length is zero
+ if (currentMessage.allContentReceived())
+ {
+ try
+ {
+ currentMessage.deliverToQueues();
+ }
+ catch (AMQException e)
+ {
+ fail(e.getMessage());
+ }
+ }
+ }
+
+ private void createAllQueues()
+ {
+ //Register Durable Priority Queue
+ createQueue(durablePriorityQueueName, true, true);
+
+ //Register Durable Simple Queue
+ createQueue(durableQueueName, false, true);
+
+ //Register NON-Durable Priority Queue
+ createQueue(priorityQueueName, true, false);
+
+ //Register NON-Durable Simple Queue
+ createQueue(queueName, false, false);
+ }
+
+ private void createAllTopicQueues()
+ {
+ //Register Durable Priority Queue
+ createQueue(durablePriorityTopicQueueName, true, true);
+
+ //Register Durable Simple Queue
+ createQueue(durableTopicQueueName, false, true);
+
+ //Register NON-Durable Priority Queue
+ createQueue(priorityTopicQueueName, true, false);
+
+ //Register NON-Durable Simple Queue
+ createQueue(topicQueueName, false, false);
+ }
+
+ private Exchange createExchange(ExchangeType type, AMQShortString name, boolean durable)
+ {
+ Exchange exchange = null;
+
+ try
+ {
+ exchange = type.newInstance(_virtualHost, name, durable, 0, false);
+ }
+ catch (AMQException e)
+ {
+ fail(e.getMessage());
+ }
+
+ try
+ {
+ _virtualHost.getExchangeRegistry().registerExchange(exchange);
+ }
+ catch (AMQException e)
+ {
+ fail(e.getMessage());
+ }
+ return exchange;
+ }
+
+ private void createQueue(AMQShortString queueName, boolean usePriority, boolean durable)
+ {
+
+ FieldTable queueArguments = null;
+
+ if (usePriority)
+ {
+ queueArguments = new FieldTable();
+ queueArguments.put(AMQQueueFactory.X_QPID_PRIORITIES, DEFAULT_PRIORTY_LEVEL);
+ }
+
+ AMQQueue queue = null;
+
+ //Ideally we would be able to use the QueueDeclareHandler here.
+ try
+ {
+ queue = AMQQueueFactory.createAMQQueueImpl(queueName, durable, queueOwner, false, _virtualHost,
+ queueArguments);
+
+ validateQueueProperties(queue, usePriority);
+
+ if (queue.isDurable() && !queue.isAutoDelete())
+ {
+ _virtualHost.getMessageStore().createQueue(queue, queueArguments);
+ }
+ }
+ catch (AMQException e)
+ {
+ fail(e.getMessage());
+ }
+
+ try
+ {
+ _virtualHost.getQueueRegistry().registerQueue(queue);
+ }
+ catch (AMQException e)
+ {
+ fail(e.getMessage());
+ }
+
+ }
+
+ private void bindAllQueuesToExchange(Exchange exchange, AMQShortString routingKey)
+ {
+ FieldTable queueArguments = new FieldTable();
+ queueArguments.put(AMQQueueFactory.X_QPID_PRIORITIES, DEFAULT_PRIORTY_LEVEL);
+
+ QueueRegistry queueRegistry = _virtualHost.getQueueRegistry();
+
+ bindQueueToExchange(exchange, routingKey, queueRegistry.getQueue(durablePriorityQueueName), false, queueArguments);
+ bindQueueToExchange(exchange, routingKey, queueRegistry.getQueue(durableQueueName), false, null);
+ bindQueueToExchange(exchange, routingKey, queueRegistry.getQueue(priorityQueueName), false, queueArguments);
+ bindQueueToExchange(exchange, routingKey, queueRegistry.getQueue(queueName), false, null);
+ }
+
+ private void bindAllTopicQueuesToExchange(Exchange exchange, AMQShortString routingKey)
+ {
+ FieldTable queueArguments = new FieldTable();
+ queueArguments.put(AMQQueueFactory.X_QPID_PRIORITIES, DEFAULT_PRIORTY_LEVEL);
+
+ QueueRegistry queueRegistry = _virtualHost.getQueueRegistry();
+
+ bindQueueToExchange(exchange, routingKey, queueRegistry.getQueue(durablePriorityTopicQueueName), true, queueArguments);
+ bindQueueToExchange(exchange, routingKey, queueRegistry.getQueue(durableTopicQueueName), true, null);
+ bindQueueToExchange(exchange, routingKey, queueRegistry.getQueue(priorityTopicQueueName), true, queueArguments);
+ bindQueueToExchange(exchange, routingKey, queueRegistry.getQueue(topicQueueName), true, null);
+ }
+
+
+ protected void bindQueueToExchange(Exchange exchange, AMQShortString routingKey, AMQQueue queue, boolean useSelector, FieldTable queueArguments)
+ {
+ try
+ {
+ exchange.registerQueue(queueName, queue, queueArguments);
+ }
+ catch (AMQException e)
+ {
+ fail(e.getMessage());
+ }
+
+ FieldTable bindArguments = null;
+
+ if (useSelector)
+ {
+ bindArguments = new FieldTable();
+ bindArguments.put(AMQPFilterTypes.JMS_SELECTOR.getValue(), "Test = 'MST'");
+ }
+
+ try
+ {
+ queue.bind(exchange, routingKey, bindArguments);
+ }
+ catch (AMQException e)
+ {
+ fail(e.getMessage());
+ }
+ }
+
+ private void validateMessage(long messageCount, boolean allQueues)
+ {
+ validateMessageOnTopics(messageCount, allQueues);
+ validateMessageOnQueues(messageCount, allQueues);
+ }
+
+ private void validateMessageOnTopics(long messageCount, boolean allQueues)
+ {
+ validateMessageOnQueue(durablePriorityTopicQueueName, messageCount);
+ validateMessageOnQueue(durableTopicQueueName, messageCount);
+
+ if (allQueues)
+ {
+ validateMessageOnQueue(priorityTopicQueueName, messageCount);
+ validateMessageOnQueue(topicQueueName, messageCount);
+ }
+ }
+
+ private void validateMessageOnQueues(long messageCount, boolean allQueues)
+ {
+ validateMessageOnQueue(durablePriorityQueueName, messageCount);
+ validateMessageOnQueue(durableQueueName, messageCount);
+
+ if (allQueues)
+ {
+ validateMessageOnQueue(priorityQueueName, messageCount);
+ validateMessageOnQueue(queueName, messageCount);
+ }
+ }
+
+ private void validateMessageOnQueue(AMQShortString queueName, long messageCount)
+ {
+ AMQQueue queue = _virtualHost.getQueueRegistry().getQueue(queueName);
+
+ assertNotNull("Queue(" + queueName + ") not correctly registered:", queue);
+
+ assertEquals("Incorrect Message count on queue:" + queueName, messageCount, queue.getMessageCount());
+ }
+
+ private class TestMessagePublishInfo implements MessagePublishInfo
+ {
+
+ Exchange _exchange;
+ boolean _immediate;
+ boolean _mandatory;
+ AMQShortString _routingKey;
+
+ TestMessagePublishInfo(Exchange exchange, boolean immediate, boolean mandatory, AMQShortString routingKey)
+ {
+ _exchange = exchange;
+ _immediate = immediate;
+ _mandatory = mandatory;
+ _routingKey = routingKey;
+ }
+
+ public AMQShortString getExchange()
+ {
+ return _exchange.getName();
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+ //no-op
+ }
+
+ public boolean isImmediate()
+ {
+ return _immediate;
+ }
+
+ public boolean isMandatory()
+ {
+ return _mandatory;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return _routingKey;
+ }
+ }
+} \ No newline at end of file
diff --git a/java/broker/src/test/java/org/apache/qpid/server/store/SkeletonMessageStore.java b/java/broker/src/test/java/org/apache/qpid/server/store/SkeletonMessageStore.java
new file mode 100644
index 0000000000..fd6789f5ce
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/store/SkeletonMessageStore.java
@@ -0,0 +1,156 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.store;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.abstraction.ContentChunk;
+import org.apache.qpid.server.queue.MessageMetaData;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
+import org.apache.qpid.server.exchange.Exchange;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * A message store that does nothing. Designed to be used in tests that do not want to use any message store
+ * functionality.
+ */
+public class SkeletonMessageStore implements MessageStore
+{
+ private final AtomicLong _messageId = new AtomicLong(1);
+
+ public void configure(String base, Configuration config) throws Exception
+ {
+ }
+
+ public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void close() throws Exception
+ {
+ }
+
+ public void removeMessage(StoreContext s, Long messageId)
+ {
+ }
+
+ public void createExchange(Exchange exchange) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void removeExchange(Exchange exchange) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQException
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public void createQueue(AMQQueue queue) throws AMQException
+ {
+ }
+
+ public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQException
+ {
+ }
+
+ public void beginTran(StoreContext s) throws AMQException
+ {
+ }
+
+ public boolean inTran(StoreContext sc)
+ {
+ return false;
+ }
+
+ public void commitTran(StoreContext storeContext) throws AMQException
+ {
+ }
+
+ public void abortTran(StoreContext storeContext) throws AMQException
+ {
+ }
+
+ public List<AMQQueue> createQueues() throws AMQException
+ {
+ return null;
+ }
+
+ public Long getNewMessageId()
+ {
+ return _messageId.getAndIncrement();
+ }
+
+ public void storeContentBodyChunk(StoreContext sc, Long messageId, int index, ContentChunk contentBody, boolean lastContentBody) throws AMQException
+ {
+
+ }
+
+ public void storeMessageMetaData(StoreContext sc, Long messageId, MessageMetaData messageMetaData) throws AMQException
+ {
+
+ }
+
+ public MessageMetaData getMessageMetaData(StoreContext s,Long messageId) throws AMQException
+ {
+ return null;
+ }
+
+ public ContentChunk getContentBodyChunk(StoreContext s,Long messageId, int index) throws AMQException
+ {
+ return null;
+ }
+
+ public boolean isPersistent()
+ {
+ return false;
+ }
+
+ public void removeQueue(final AMQQueue queue) throws AMQException
+ {
+
+ }
+
+ public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException
+ {
+
+ }
+
+ public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException
+ {
+
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/store/TestMemoryMessageStore.java b/java/broker/src/test/java/org/apache/qpid/server/store/TestMemoryMessageStore.java
new file mode 100644
index 0000000000..4e48435962
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/store/TestMemoryMessageStore.java
@@ -0,0 +1,51 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.store;
+
+import org.apache.qpid.server.queue.MessageMetaData;
+import org.apache.qpid.framing.ContentBody;
+import org.apache.qpid.framing.abstraction.ContentChunk;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.List;
+
+/**
+ * Adds some extra methods to the memory message store for testing purposes.
+ */
+public class TestMemoryMessageStore extends MemoryMessageStore
+{
+ public TestMemoryMessageStore()
+ {
+ _metaDataMap = new ConcurrentHashMap<Long, MessageMetaData>();
+ _contentBodyMap = new ConcurrentHashMap<Long, List<ContentChunk>>();
+ }
+
+ public ConcurrentMap<Long, MessageMetaData> getMessageMetaDataMap()
+ {
+ return _metaDataMap;
+ }
+
+ public ConcurrentMap<Long, List<ContentChunk>> getContentBodyMap()
+ {
+ return _contentBodyMap;
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/store/TestReferenceCounting.java b/java/broker/src/test/java/org/apache/qpid/server/store/TestReferenceCounting.java
new file mode 100644
index 0000000000..2346660d25
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/store/TestReferenceCounting.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.server.store;
+
+import junit.framework.TestCase;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.MessageHandleFactory;
+import org.apache.qpid.server.queue.AMQMessageHandle;
+
+/**
+ * Tests that reference counting works correctly with AMQMessage and the message store
+ */
+public class TestReferenceCounting extends TestCase
+{
+ private TestMemoryMessageStore _store;
+
+ private StoreContext _storeContext = new StoreContext();
+
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _store = new TestMemoryMessageStore();
+ }
+
+ /**
+ * Check that when the reference count is decremented the message removes itself from the store
+ */
+ public void testMessageGetsRemoved() throws AMQException
+ {
+ ContentHeaderBody chb = createPersistentContentHeader();
+
+ MessagePublishInfo info = new MessagePublishInfo()
+ {
+
+ public AMQShortString getExchange()
+ {
+ return null;
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isImmediate()
+ {
+ return false;
+ }
+
+ public boolean isMandatory()
+ {
+ return false;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return null;
+ }
+ };
+
+
+ final long messageId = _store.getNewMessageId();
+ AMQMessageHandle messageHandle = (new MessageHandleFactory()).createMessageHandle(messageId, _store, true);
+ messageHandle.setPublishAndContentHeaderBody(_storeContext,info, chb);
+ AMQMessage message = new AMQMessage(messageHandle,
+ _storeContext,info);
+
+ message = message.takeReference();
+
+ // we call routing complete to set up the handle
+ // message.routingComplete(_store, _storeContext, new MessageHandleFactory());
+
+
+ assertEquals(1, _store.getMessageMetaDataMap().size());
+ message.decrementReference(_storeContext);
+ assertEquals(1, _store.getMessageMetaDataMap().size());
+ }
+
+ private ContentHeaderBody createPersistentContentHeader()
+ {
+ ContentHeaderBody chb = new ContentHeaderBody();
+ BasicContentHeaderProperties bchp = new BasicContentHeaderProperties();
+ bchp.setDeliveryMode((byte)2);
+ chb.properties = bchp;
+ return chb;
+ }
+
+ public void testMessageRemains() throws AMQException
+ {
+
+ MessagePublishInfo info = new MessagePublishInfo()
+ {
+
+ public AMQShortString getExchange()
+ {
+ return null;
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public boolean isImmediate()
+ {
+ return false;
+ }
+
+ public boolean isMandatory()
+ {
+ return false;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return null;
+ }
+ };
+
+ final Long messageId = _store.getNewMessageId();
+ final ContentHeaderBody chb = createPersistentContentHeader();
+ AMQMessageHandle messageHandle = (new MessageHandleFactory()).createMessageHandle(messageId, _store, true);
+ messageHandle.setPublishAndContentHeaderBody(_storeContext,info,chb);
+ AMQMessage message = new AMQMessage(messageHandle,
+ _storeContext,
+ info);
+
+
+ message = message.takeReference();
+ // we call routing complete to set up the handle
+ // message.routingComplete(_store, _storeContext, new MessageHandleFactory());
+
+
+
+ assertEquals(1, _store.getMessageMetaDataMap().size());
+ message = message.takeReference();
+ message.decrementReference(_storeContext);
+ assertEquals(1, _store.getMessageMetaDataMap().size());
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(TestReferenceCounting.class);
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java b/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java
new file mode 100644
index 0000000000..9146fe88ae
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java
@@ -0,0 +1,92 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.store;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.MessageMetaData;
+import org.apache.qpid.framing.ContentBody;
+import org.apache.qpid.framing.abstraction.ContentChunk;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Adds some extra methods to the memory message store for testing purposes.
+ */
+public class TestableMemoryMessageStore extends MemoryMessageStore
+{
+
+ MemoryMessageStore _mms = null;
+ private HashMap<Long, AMQQueue> _messages = new HashMap<Long, AMQQueue>();
+
+ public TestableMemoryMessageStore(MemoryMessageStore mms)
+ {
+ _mms = mms;
+ }
+
+ public TestableMemoryMessageStore()
+ {
+ _metaDataMap = new ConcurrentHashMap<Long, MessageMetaData>();
+ _contentBodyMap = new ConcurrentHashMap<Long, List<ContentChunk>>();
+ }
+
+ public ConcurrentMap<Long, MessageMetaData> getMessageMetaDataMap()
+ {
+ if (_mms != null)
+ {
+ return _mms._metaDataMap;
+ }
+ else
+ {
+ return _metaDataMap;
+ }
+ }
+
+ public ConcurrentMap<Long, List<ContentChunk>> getContentBodyMap()
+ {
+ if (_mms != null)
+ {
+ return _mms._contentBodyMap;
+ }
+ else
+ {
+ return _contentBodyMap;
+ }
+ }
+
+ public void enqueueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException
+ {
+ getMessages().put(messageId, queue);
+ }
+
+ public void dequeueMessage(StoreContext context, final AMQQueue queue, Long messageId) throws AMQException
+ {
+ getMessages().remove(messageId);
+ }
+
+ public HashMap<Long, AMQQueue> getMessages()
+ {
+ return _messages;
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java b/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java
new file mode 100644
index 0000000000..33fd669d5c
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java
@@ -0,0 +1,180 @@
+package org.apache.qpid.server.subscription;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+import java.util.ArrayList;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.queue.QueueEntry.SubscriptionAcquiredState;
+
+public class MockSubscription implements Subscription
+{
+
+ private boolean _closed = false;
+ private AMQShortString tag = new AMQShortString("mocktag");
+ private AMQQueue queue = null;
+ private StateListener _listener = null;
+ private QueueEntry lastSeen = null;
+ private State _state = State.ACTIVE;
+ private ArrayList<QueueEntry> messages = new ArrayList<QueueEntry>();
+ private final Lock _stateChangeLock = new ReentrantLock();
+
+ public void close()
+ {
+ _closed = true;
+ if (_listener != null)
+ {
+ _listener.stateChange(this, _state, State.CLOSED);
+ }
+ _state = State.CLOSED;
+ }
+
+ public boolean filtersMessages()
+ {
+ return false;
+ }
+
+ public AMQChannel getChannel()
+ {
+ return null;
+ }
+
+ public AMQShortString getConsumerTag()
+ {
+ return tag ;
+ }
+
+ public QueueEntry getLastSeenEntry()
+ {
+ return lastSeen;
+ }
+
+ public SubscriptionAcquiredState getOwningState()
+ {
+ return new QueueEntry.SubscriptionAcquiredState(this);
+ }
+
+ public AMQQueue getQueue()
+ {
+ return queue;
+ }
+
+ public void getSendLock()
+ {
+ _stateChangeLock.lock();
+ }
+
+ public boolean hasInterest(QueueEntry msg)
+ {
+ return true;
+ }
+
+ public boolean isActive()
+ {
+ return true;
+ }
+
+ public boolean isAutoClose()
+ {
+ return false;
+ }
+
+ public boolean isBrowser()
+ {
+ return false;
+ }
+
+ public boolean isClosed()
+ {
+ return _closed;
+ }
+
+ public boolean isSuspended()
+ {
+ return false;
+ }
+
+ public void queueDeleted(AMQQueue queue)
+ {
+ }
+
+ public void releaseSendLock()
+ {
+ _stateChangeLock.unlock();
+ }
+
+ public void resend(QueueEntry entry) throws AMQException
+ {
+ }
+
+ public void restoreCredit(QueueEntry queueEntry)
+ {
+ }
+
+ public void send(QueueEntry msg) throws AMQException
+ {
+ lastSeen = msg;
+ messages.add(msg);
+ }
+
+ public boolean setLastSeenEntry(QueueEntry expected, QueueEntry newValue)
+ {
+ boolean result = false;
+ if (expected != null)
+ {
+ result = (expected.equals(lastSeen));
+ }
+ lastSeen = newValue;
+ return result;
+ }
+
+ public void setQueue(AMQQueue queue)
+ {
+ this.queue = queue;
+ }
+
+ public void setStateListener(StateListener listener)
+ {
+ this._listener = listener;
+ }
+
+ public State getState()
+ {
+ return _state;
+ }
+
+ public boolean wouldSuspend(QueueEntry msg)
+ {
+ return false;
+ }
+
+ public ArrayList<QueueEntry> getMessages()
+ {
+ return messages;
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/subscription/QueueBrowserUsesNoAckTest.java b/java/broker/src/test/java/org/apache/qpid/server/subscription/QueueBrowserUsesNoAckTest.java
new file mode 100644
index 0000000000..d0db4ebd38
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/subscription/QueueBrowserUsesNoAckTest.java
@@ -0,0 +1,77 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.subscription;
+
+import org.apache.qpid.server.util.InternalBrokerBaseCase;
+import org.apache.qpid.server.protocol.InternalTestProtocolSession;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.AMQException;
+
+import java.util.List;
+
+public class QueueBrowserUsesNoAckTest extends InternalBrokerBaseCase
+{
+
+ public void testQueueBrowserUsesNoAck() throws AMQException
+ {
+ int sendMessageCount = 2;
+ int prefetch = 1;
+
+ //Check store is empty
+ checkStoreContents(0);
+
+ //Send required messsages to the queue
+ publishMessages(_session, _channel, sendMessageCount);
+
+ //Ensure they are stored
+ checkStoreContents(sendMessageCount);
+
+ //Check that there are no unacked messages
+ assertEquals("Channel should have no unacked msgs ", 0,
+ _channel.getUnacknowledgedMessageMap().size());
+
+ //Set the prefetch on the session to be less than the sent messages
+ _channel.setCredit(0, prefetch);
+
+ //browse the queue
+ AMQShortString browser = browse(_channel, _queue);
+
+ _queue.deliverAsync();
+
+ //Wait for messages to fill the prefetch
+ _session.awaitDelivery(prefetch);
+
+ //Get those messages
+ List<InternalTestProtocolSession.DeliveryPair> messages =
+ _session.getDelivers(_channel.getChannelId(), browser,
+ prefetch);
+
+ //Ensure we recevied the prefetched messages
+ assertEquals(prefetch, messages.size());
+
+ //Check the process didn't suspend the subscription as this would
+ // indicate we are using the prefetch credit. i.e. using acks not No-Ack
+ assertTrue("The subscription has been suspended",
+ !_channel.getSubscription(browser).getState()
+ .equals(Subscription.State.SUSPENDED));
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/txn/TxnBufferTest.java b/java/broker/src/test/java/org/apache/qpid/server/txn/TxnBufferTest.java
new file mode 100644
index 0000000000..84d3d313d1
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/txn/TxnBufferTest.java
@@ -0,0 +1,306 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.txn;
+
+import junit.framework.TestCase;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.TestMemoryMessageStore;
+import org.apache.qpid.server.store.StoreContext;
+
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+
+public class TxnBufferTest extends TestCase
+{
+ private final LinkedList<MockOp> ops = new LinkedList<MockOp>();
+
+ public void testCommit() throws AMQException
+ {
+ MockStore store = new MockStore();
+
+ TxnBuffer buffer = new TxnBuffer();
+ buffer.enlist(new MockOp().expectPrepare().expectCommit());
+ //check relative ordering
+ MockOp op = new MockOp().expectPrepare().expectPrepare().expectCommit().expectCommit();
+ buffer.enlist(op);
+ buffer.enlist(op);
+ buffer.enlist(new MockOp().expectPrepare().expectCommit());
+
+ buffer.commit(null);
+
+ validateOps();
+ store.validate();
+ }
+
+ public void testRollback() throws AMQException
+ {
+ MockStore store = new MockStore();
+
+ TxnBuffer buffer = new TxnBuffer();
+ buffer.enlist(new MockOp().expectRollback());
+ buffer.enlist(new MockOp().expectRollback());
+ buffer.enlist(new MockOp().expectRollback());
+
+ buffer.rollback(null);
+
+ validateOps();
+ store.validate();
+ }
+
+ public void testCommitWithFailureDuringPrepare() throws AMQException
+ {
+ MockStore store = new MockStore();
+ store.beginTran(null);
+
+ TxnBuffer buffer = new TxnBuffer();
+ buffer.enlist(new StoreMessageOperation(store));
+ buffer.enlist(new MockOp().expectPrepare().expectUndoPrepare());
+ buffer.enlist(new TxnTester(store));
+ buffer.enlist(new MockOp().expectPrepare().expectUndoPrepare());
+ buffer.enlist(new FailedPrepare());
+ buffer.enlist(new MockOp());
+
+ try
+ {
+ buffer.commit(null);
+ }
+ catch (NoSuchElementException e)
+ {
+
+ }
+
+ validateOps();
+ store.validate();
+ }
+
+ public void testCommitWithPersistance() throws AMQException
+ {
+ MockStore store = new MockStore();
+ store.beginTran(null);
+ store.expectCommit();
+
+ TxnBuffer buffer = new TxnBuffer();
+ buffer.enlist(new MockOp().expectPrepare().expectCommit());
+ buffer.enlist(new MockOp().expectPrepare().expectCommit());
+ buffer.enlist(new MockOp().expectPrepare().expectCommit());
+ buffer.enlist(new StoreMessageOperation(store));
+ buffer.enlist(new TxnTester(store));
+
+ buffer.commit(null);
+ validateOps();
+ store.validate();
+ }
+
+ private void validateOps()
+ {
+ for (MockOp op : ops)
+ {
+ op.validate();
+ }
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(TxnBufferTest.class);
+ }
+
+ class MockOp implements TxnOp
+ {
+ final Object PREPARE = "PREPARE";
+ final Object COMMIT = "COMMIT";
+ final Object UNDO_PREPARE = "UNDO_PREPARE";
+ final Object ROLLBACK = "ROLLBACK";
+
+ private final LinkedList expected = new LinkedList();
+
+ MockOp()
+ {
+ ops.add(this);
+ }
+
+ public void prepare(StoreContext context)
+ {
+ assertEquals(expected.removeLast(), PREPARE);
+ }
+
+ public void commit(StoreContext context)
+ {
+ assertEquals(expected.removeLast(), COMMIT);
+ }
+
+ public void undoPrepare()
+ {
+ assertEquals(expected.removeLast(), UNDO_PREPARE);
+ }
+
+ public void rollback(StoreContext context)
+ {
+ assertEquals(expected.removeLast(), ROLLBACK);
+ }
+
+ private MockOp expect(Object optype)
+ {
+ expected.addFirst(optype);
+ return this;
+ }
+
+ MockOp expectPrepare()
+ {
+ return expect(PREPARE);
+ }
+
+ MockOp expectCommit()
+ {
+ return expect(COMMIT);
+ }
+
+ MockOp expectUndoPrepare()
+ {
+ return expect(UNDO_PREPARE);
+ }
+
+ MockOp expectRollback()
+ {
+ return expect(ROLLBACK);
+ }
+
+ void validate()
+ {
+ assertEquals("Expected ops were not all invoked", new LinkedList(), expected);
+ }
+
+ void clear()
+ {
+ expected.clear();
+ }
+ }
+
+ class MockStore extends TestMemoryMessageStore
+ {
+ final Object BEGIN = "BEGIN";
+ final Object ABORT = "ABORT";
+ final Object COMMIT = "COMMIT";
+
+ private final LinkedList expected = new LinkedList();
+ private boolean inTran;
+
+ public void beginTran(StoreContext context) throws AMQException
+ {
+ inTran = true;
+ }
+
+ public void commitTran(StoreContext context) throws AMQException
+ {
+ assertEquals(expected.removeLast(), COMMIT);
+ inTran = false;
+ }
+
+ public void abortTran(StoreContext context) throws AMQException
+ {
+ assertEquals(expected.removeLast(), ABORT);
+ inTran = false;
+ }
+
+ public boolean inTran(StoreContext context)
+ {
+ return inTran;
+ }
+
+ private MockStore expect(Object optype)
+ {
+ expected.addFirst(optype);
+ return this;
+ }
+
+ MockStore expectBegin()
+ {
+ return expect(BEGIN);
+ }
+
+ MockStore expectCommit()
+ {
+ return expect(COMMIT);
+ }
+
+ MockStore expectAbort()
+ {
+ return expect(ABORT);
+ }
+
+ void clear()
+ {
+ expected.clear();
+ }
+
+ void validate()
+ {
+ assertEquals("Expected ops were not all invoked", new LinkedList(), expected);
+ }
+ }
+
+ class NullOp implements TxnOp
+ {
+ public void prepare(StoreContext context) throws AMQException
+ {
+ }
+ public void commit(StoreContext context)
+ {
+ }
+ public void undoPrepare()
+ {
+ }
+ public void rollback(StoreContext context)
+ {
+ }
+ }
+
+ class FailedPrepare extends NullOp
+ {
+ public void prepare() throws AMQException
+ {
+ throw new AMQException(null, "Fail!", null);
+ }
+ }
+
+ class TxnTester extends NullOp
+ {
+ private final MessageStore store;
+
+ private final StoreContext context = new StoreContext();
+
+ TxnTester(MessageStore store)
+ {
+ this.store = store;
+ }
+
+ public void prepare() throws AMQException
+ {
+ assertTrue("Expected prepare to be performed under txn", store.inTran(context));
+ }
+
+ public void commit()
+ {
+ assertTrue("Expected commit not to be performed under txn", !store.inTran(context));
+ }
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java b/java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java
new file mode 100644
index 0000000000..101c33043d
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/util/InternalBrokerBaseCase.java
@@ -0,0 +1,214 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.util;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.protocol.InternalTestProtocolSession;
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.ConsumerTagNotUniqueException;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.StoreContext;
+import org.apache.qpid.server.store.TestableMemoryMessageStore;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.util.MockChannel;
+import org.apache.qpid.common.AMQPFilterTypes;
+import org.apache.qpid.exchange.ExchangeDefaults;
+
+public class InternalBrokerBaseCase extends TestCase
+{
+ protected IApplicationRegistry _registry;
+ protected MessageStore _messageStore;
+ protected MockChannel _channel;
+ protected InternalTestProtocolSession _session;
+ protected VirtualHost _virtualHost;
+ protected StoreContext _storeContext = new StoreContext();
+ protected AMQQueue _queue;
+ protected AMQShortString QUEUE_NAME;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ PropertiesConfiguration configuration = new PropertiesConfiguration();
+ configuration.setProperty("virtualhosts.virtualhost.test.store.class", TestableMemoryMessageStore.class.getName());
+ _registry = new TestApplicationRegistry(new ServerConfiguration(configuration));
+ ApplicationRegistry.initialise(_registry);
+ _virtualHost = _registry.getVirtualHostRegistry().getVirtualHost("test");
+
+ _messageStore = _virtualHost.getMessageStore();
+
+ QUEUE_NAME = new AMQShortString("test");
+ _queue = AMQQueueFactory.createAMQQueueImpl(QUEUE_NAME, false, new AMQShortString("testowner"),
+ false, _virtualHost, null);
+
+ _virtualHost.getQueueRegistry().registerQueue(_queue);
+
+ Exchange defaultExchange = _virtualHost.getExchangeRegistry().getDefaultExchange();
+
+ _queue.bind(defaultExchange, QUEUE_NAME, null);
+
+ _session = new InternalTestProtocolSession();
+
+ _session.setVirtualHost(_virtualHost);
+
+ _channel = new MockChannel(_session, 1, _messageStore);
+
+ _session.addChannel(_channel);
+ }
+
+ public void tearDown() throws Exception
+ {
+ ApplicationRegistry.remove(1);
+ super.tearDown();
+ }
+
+ protected void checkStoreContents(int messageCount)
+ {
+ assertEquals("Message header count incorrect in the MetaDataMap", messageCount, ((TestableMemoryMessageStore) _messageStore).getMessageMetaDataMap().size());
+
+ //The above publish message is sufficiently small not to fit in the header so no Body is required.
+ //assertEquals("Message body count incorrect in the ContentBodyMap", messageCount, ((TestableMemoryMessageStore) _messageStore).getContentBodyMap().size());
+ }
+
+ protected AMQShortString subscribe(InternalTestProtocolSession session, AMQChannel channel, AMQQueue queue)
+ {
+ try
+ {
+ return channel.subscribeToQueue(null, queue, true, null, false, true);
+ }
+ catch (AMQException e)
+ {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ catch (ConsumerTagNotUniqueException e)
+ {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ //Keep the compiler happy
+ return null;
+ }
+
+ protected AMQShortString browse(AMQChannel channel, AMQQueue queue)
+ {
+ try
+ {
+ FieldTable filters = new FieldTable();
+ filters.put(AMQPFilterTypes.NO_CONSUME.getValue(), true);
+
+ return channel.subscribeToQueue(null, queue, true, filters, false, true);
+ }
+ catch (AMQException e)
+ {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ catch (ConsumerTagNotUniqueException e)
+ {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ //Keep the compiler happy
+ return null;
+ }
+
+ public void publishMessages(InternalTestProtocolSession session, AMQChannel channel, int messages) throws AMQException
+ {
+ MessagePublishInfo info = new MessagePublishInfo()
+ {
+ public AMQShortString getExchange()
+ {
+ return ExchangeDefaults.DEFAULT_EXCHANGE_NAME;
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+
+ }
+
+ public boolean isImmediate()
+ {
+ return false;
+ }
+
+ public boolean isMandatory()
+ {
+ return false;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return QUEUE_NAME;
+ }
+ };
+
+ for (int count = 0; count < messages; count++)
+ {
+ channel.setPublishFrame(info, _virtualHost.getExchangeRegistry().getExchange(info.getExchange()));
+
+ //Set the body size
+ ContentHeaderBody _headerBody = new ContentHeaderBody();
+ _headerBody.bodySize = 0;
+
+ //Set Minimum properties
+ BasicContentHeaderProperties properties = new BasicContentHeaderProperties();
+
+ properties.setExpiration(0L);
+ properties.setTimestamp(System.currentTimeMillis());
+
+ //Make Message Persistent
+ properties.setDeliveryMode((byte) 2);
+
+ _headerBody.properties = properties;
+
+ channel.publishContentHeader(_headerBody);
+ }
+
+ }
+
+ public void acknowledge(AMQChannel channel, long deliveryTag)
+ {
+ try
+ {
+ channel.acknowledgeMessage(deliveryTag, false);
+ }
+ catch (AMQException e)
+ {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/util/LoggingProxyTest.java b/java/broker/src/test/java/org/apache/qpid/server/util/LoggingProxyTest.java
new file mode 100644
index 0000000000..c7db51016e
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/util/LoggingProxyTest.java
@@ -0,0 +1,88 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.util;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+public class LoggingProxyTest extends TestCase
+{
+ static interface IFoo {
+ void foo();
+ void foo(int i, Collection c);
+ String bar();
+ String bar(String s, List l);
+ }
+
+ static class Foo implements IFoo {
+ public void foo()
+ {
+ }
+
+ public void foo(int i, Collection c)
+ {
+ }
+
+ public String bar()
+ {
+ return null;
+ }
+
+ public String bar(String s, List l)
+ {
+ return "ha";
+ }
+ }
+
+ public void testSimple() {
+ LoggingProxy proxy = new LoggingProxy(new Foo(), 20);
+ IFoo foo = (IFoo)proxy.getProxy(IFoo.class);
+ foo.foo();
+ assertEquals(2, proxy.getBufferSize());
+ assertTrue(proxy.getBuffer().get(0).toString().matches(".*: foo\\(\\) entered$"));
+ assertTrue(proxy.getBuffer().get(1).toString().matches(".*: foo\\(\\) returned$"));
+
+ foo.foo(3, Arrays.asList(0, 1, 2));
+ assertEquals(4, proxy.getBufferSize());
+ assertTrue(proxy.getBuffer().get(2).toString().matches(".*: foo\\(\\[3, \\[0, 1, 2\\]\\]\\) entered$"));
+ assertTrue(proxy.getBuffer().get(3).toString().matches(".*: foo\\(\\) returned$"));
+
+ foo.bar();
+ assertEquals(6, proxy.getBufferSize());
+ assertTrue(proxy.getBuffer().get(4).toString().matches(".*: bar\\(\\) entered$"));
+ assertTrue(proxy.getBuffer().get(5).toString().matches(".*: bar\\(\\) returned null$"));
+
+ foo.bar("hello", Arrays.asList(1, 2, 3));
+ assertEquals(8, proxy.getBufferSize());
+ assertTrue(proxy.getBuffer().get(6).toString().matches(".*: bar\\(\\[hello, \\[1, 2, 3\\]\\]\\) entered$"));
+ assertTrue(proxy.getBuffer().get(7).toString().matches(".*: bar\\(\\) returned ha$"));
+
+ proxy.dump();
+ }
+
+ public static junit.framework.Test suite()
+ {
+ return new junit.framework.TestSuite(LoggingProxyTest.class);
+ }
+}
diff --git a/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java b/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java
new file mode 100644
index 0000000000..c6ecac6a01
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java
@@ -0,0 +1,137 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.util;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.configuration.VirtualHostConfiguration;
+import org.apache.qpid.server.exchange.ExchangeFactory;
+import org.apache.qpid.server.exchange.ExchangeRegistry;
+import org.apache.qpid.server.management.NoopManagedObjectRegistry;
+import org.apache.qpid.server.queue.QueueRegistry;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.security.access.ACLManager;
+import org.apache.qpid.server.security.access.ACLPlugin;
+import org.apache.qpid.server.security.access.plugins.AllowAll;
+import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabaseManager;
+import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.TestableMemoryMessageStore;
+import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Properties;
+import java.util.Arrays;
+
+public class TestApplicationRegistry extends ApplicationRegistry
+{
+ private QueueRegistry _queueRegistry;
+
+ private ExchangeRegistry _exchangeRegistry;
+
+ private ExchangeFactory _exchangeFactory;
+
+ private MessageStore _messageStore;
+
+ private VirtualHost _vHost;
+
+
+ private ServerConfiguration _config;
+
+ public TestApplicationRegistry() throws ConfigurationException
+ {
+ super(new ServerConfiguration(new PropertiesConfiguration()));
+ }
+
+ public TestApplicationRegistry(ServerConfiguration config) throws ConfigurationException
+ {
+ super(config);
+ _config = config;
+ }
+
+ public void initialise() throws Exception
+ {
+ Properties users = new Properties();
+
+ users.put("guest", "guest");
+
+ _databaseManager = new PropertiesPrincipalDatabaseManager("default", users);
+
+ _accessManager = new ACLManager(_configuration.getSecurityConfiguration(), _pluginManager, AllowAll.FACTORY);
+
+ _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null);
+
+ _managedObjectRegistry = new NoopManagedObjectRegistry();
+
+ _messageStore = new TestableMemoryMessageStore();
+
+ _virtualHostRegistry = new VirtualHostRegistry();
+
+ PropertiesConfiguration vhostProps = new PropertiesConfiguration();
+ VirtualHostConfiguration hostConfig = new VirtualHostConfiguration("test", vhostProps);
+ _vHost = new VirtualHost(hostConfig, _messageStore);
+
+ _virtualHostRegistry.registerVirtualHost(_vHost);
+
+ _queueRegistry = _vHost.getQueueRegistry();
+ _exchangeFactory = _vHost.getExchangeFactory();
+ _exchangeRegistry = _vHost.getExchangeRegistry();
+
+ }
+
+ public QueueRegistry getQueueRegistry()
+ {
+ return _queueRegistry;
+ }
+
+ public ExchangeRegistry getExchangeRegistry()
+ {
+ return _exchangeRegistry;
+ }
+
+ public ExchangeFactory getExchangeFactory()
+ {
+ return _exchangeFactory;
+ }
+
+ public Collection<String> getVirtualHostNames()
+ {
+ String[] hosts = {"test"};
+ return Arrays.asList(hosts);
+ }
+
+ public void setAccessManager(ACLManager newManager)
+ {
+ _accessManager = newManager;
+ }
+
+ public MessageStore getMessageStore()
+ {
+ return _messageStore;
+ }
+
+}
+
+
diff --git a/java/broker/src/test/java/org/apache/qpid/util/MockChannel.java b/java/broker/src/test/java/org/apache/qpid/util/MockChannel.java
new file mode 100644
index 0000000000..447d09429d
--- /dev/null
+++ b/java/broker/src/test/java/org/apache/qpid/util/MockChannel.java
@@ -0,0 +1,43 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.util;
+
+import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQShortString;
+
+public class MockChannel extends AMQChannel
+{
+ public MockChannel(AMQProtocolSession session, int channelId, MessageStore messageStore)
+ throws AMQException
+ {
+ super(session, channelId, messageStore);
+ }
+
+ public Subscription getSubscription(AMQShortString subscription)
+ {
+ return _tag2SubscriptionMap.get(subscription);
+ }
+
+}