summaryrefslogtreecommitdiff
path: root/qpid/java/systests/src
diff options
context:
space:
mode:
authorRobert Gemmell <robbie@apache.org>2012-10-12 11:44:13 +0000
committerRobert Gemmell <robbie@apache.org>2012-10-12 11:44:13 +0000
commit65cba5397294ddd5349bdb9837c4a10d91f2ca0b (patch)
tree5ac98649e42a8d48ca46e94cae1120dde99044dc /qpid/java/systests/src
parenta0b7800e8d8554f76dcd8715768b08b6e8b9c507 (diff)
downloadqpid-python-65cba5397294ddd5349bdb9837c4a10d91f2ca0b.tar.gz
QPID-4335, QPID-4353: Refactored broker plugins to use simplified ServiceLoader-based model rather than embedding Felix to use OSGi.
Removed the ability to reload security configuration because this feature is not very useful in its current form and was making our code hard to refactor. Modified all tests to use jars rather than classes. This makes them closer to real-world deployments, e.g. the META-INF/services file is read from within the jar. Also moved various system tests from their respective modules into "systests". This removes the need for most modules to depend on systests, thus simplifying our dependency graph. Applied patch from myself, Keith Wall and Phil Harvey <phil@philharveyonline.com> git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1397519 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/java/systests/src')
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java9
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java10
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.java124
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java283
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java148
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java480
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java318
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java696
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java210
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java251
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java39
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/Asserts.java249
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java73
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java116
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BindingRestTest.java129
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java60
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestTest.java118
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/ConnectionRestTest.java213
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/ExchangeRestTest.java87
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java160
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupRestTest.java109
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/LogRecordsRestTest.java42
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/MessagesRestTest.java354
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PortRestTest.java61
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QpidRestTestCase.java83
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QueueRestTest.java225
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/RestTestHelper.java445
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/SaslRestTest.java42
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/StructureRestTest.java115
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/UserRestTest.java97
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java434
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java190
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java192
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java7
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java27
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestSSLConstants.java27
36 files changed, 6180 insertions, 43 deletions
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java
index 51d840629d..ee8855dc6c 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java
@@ -20,6 +20,11 @@
*/
package org.apache.qpid.client.ssl;
+import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE;
+import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE_PASSWORD;
+import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE;
+import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD;
+
import org.apache.qpid.client.AMQConnectionURL;
import org.apache.qpid.client.AMQTestConnection_0_10;
import org.apache.qpid.test.utils.QpidBrokerTestCase;
@@ -31,10 +36,6 @@ import java.io.PrintStream;
public class SSLTest extends QpidBrokerTestCase
{
- private static final String KEYSTORE = "test-profiles/test_resources/ssl/java_client_keystore.jks";
- private static final String KEYSTORE_PASSWORD = "password";
- private static final String TRUSTSTORE = "test-profiles/test_resources/ssl/java_client_truststore.jks";
- private static final String TRUSTSTORE_PASSWORD = "password";
private static final String CERT_ALIAS_APP1 = "app1";
private static final String CERT_ALIAS_APP2 = "app2";
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java
index 858b32c24c..34b62e0b92 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java
@@ -20,6 +20,11 @@
*/
package org.apache.qpid.server.security.auth.manager;
+import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE;
+import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE_PASSWORD;
+import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE;
+import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD;
+
import javax.jms.Connection;
import javax.jms.JMSException;
import org.apache.qpid.AMQException;
@@ -28,11 +33,6 @@ import org.apache.qpid.test.utils.QpidBrokerTestCase;
public class MultipleAuthenticationManagersTest extends QpidBrokerTestCase
{
- private static final String KEYSTORE = "test-profiles/test_resources/ssl/java_client_keystore.jks";
- private static final String KEYSTORE_PASSWORD = "password";
- private static final String TRUSTSTORE = "test-profiles/test_resources/ssl/java_client_truststore.jks";
- private static final String TRUSTSTORE_PASSWORD = "password";
-
@Override
protected void setUp() throws Exception
{
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.java
new file mode 100644
index 0000000000..7473a4d3e7
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.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.systest.management.jmx;
+
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedExchange;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+/**
+ * Tests the JMX API for the Managed Broker.
+ *
+ */
+public class BrokerManagementTest extends QpidBrokerTestCase
+{
+ private static final String VIRTUAL_HOST = "test";
+
+ /**
+ * JMX helper.
+ */
+ private JMXTestUtils _jmxUtils;
+ private ManagedBroker _managedBroker;
+
+ public void setUp() throws Exception
+ {
+ _jmxUtils = new JMXTestUtils(this);
+ _jmxUtils.setUp();
+ super.setUp();
+ _jmxUtils.open();
+ _managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST);
+ }
+
+ public void tearDown() throws Exception
+ {
+ if (_jmxUtils != null)
+ {
+ _jmxUtils.close();
+ }
+ super.tearDown();
+ }
+
+ /**
+ * Tests queue creation/deletion also verifying the automatic binding to the default exchange.
+ */
+ public void testCreateQueueAndDeletion() throws Exception
+ {
+ final String queueName = getTestQueueName();
+ final ManagedExchange defaultExchange = _jmxUtils.getManagedExchange(ExchangeDefaults.DEFAULT_EXCHANGE_NAME.asString());
+
+ // Check that bind does not exist before queue creation
+ assertFalse("Binding to " + queueName + " should not exist in default exchange before queue creation",
+ defaultExchange.bindings().containsKey(new String[] {queueName}));
+
+ _managedBroker.createNewQueue(queueName, "testowner", true);
+
+ // Ensure the queue exists
+ assertNotNull("Queue object name expected to exist", _jmxUtils.getQueueObjectName(VIRTUAL_HOST, queueName));
+ assertNotNull("Manager queue expected to be available", _jmxUtils.getManagedQueue(queueName));
+
+ // Now verify that the default exchange has been bound.
+ assertTrue("Binding to " + queueName + " should exist in default exchange after queue creation",
+ defaultExchange.bindings().containsKey(new String[] {queueName}));
+
+ // Now delete the queue
+ _managedBroker.deleteQueue(queueName);
+
+ // Finally ensure that the binding has been removed.
+ assertFalse("Binding to " + queueName + " should not exist in default exchange after queue deletion",
+ defaultExchange.bindings().containsKey(new String[] {queueName}));
+ }
+
+ /**
+ * Tests exchange creation/deletion via JMX API.
+ */
+ public void testCreateExchangeAndUnregister() throws Exception
+ {
+ String exchangeName = getTestName();
+ _managedBroker.createNewExchange(exchangeName, "topic", true);
+
+ ManagedExchange exchange = _jmxUtils.getManagedExchange(exchangeName);
+ assertNotNull("Exchange should exist", exchange);
+
+ _managedBroker.unregisterExchange(exchangeName);
+ }
+
+ /**
+ * Tests that it is disallowed to unregister the default exchange.
+ */
+ public void testUnregisterOfDefaultExchangeDisallowed() throws Exception
+ {
+ String defaultExchangeName = ExchangeDefaults.DEFAULT_EXCHANGE_NAME.asString();
+
+ try
+ {
+ _managedBroker.unregisterExchange(defaultExchangeName);
+ fail("Exception not thrown");
+ }
+ catch (UnsupportedOperationException e)
+ {
+ // PASS
+ assertEquals("'<<default>>' is a reserved exchange and can't be deleted", e.getMessage());
+ }
+ final ManagedExchange defaultExchange = _jmxUtils.getManagedExchange(defaultExchangeName);
+ assertNotNull("Exchange should exist", defaultExchange);
+ }
+
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java
new file mode 100644
index 0000000000..28d7bf4aed
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.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.systest.management.jmx;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.management.JMException;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.TabularData;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.qpid.common.QpidProperties;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
+import org.apache.qpid.management.common.mbeans.ManagedQueue;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+public class ConnectionManagementTest extends QpidBrokerTestCase
+{
+ private static final String VIRTUAL_HOST_NAME = "test";
+
+ private JMXTestUtils _jmxUtils;
+ private Connection _connection;
+
+ public void setUp() throws Exception
+ {
+ _jmxUtils = new JMXTestUtils(this);
+ _jmxUtils.setUp(); // modifies broker config therefore must be done before super.setUp()
+ super.setUp();
+ _jmxUtils.open();
+ }
+
+ public void tearDown() throws Exception
+ {
+ try
+ {
+ if (_jmxUtils != null)
+ {
+ _jmxUtils.close();
+ }
+ }
+ finally
+ {
+ super.tearDown();
+ }
+ }
+
+ public void testNumberOfManagedConnectionsMatchesNumberOfClientConnections() throws Exception
+ {
+ assertEquals("Expected no managed connections", 0, getManagedConnections().size());
+
+ _connection = getConnection();
+ assertEquals("Expected one managed connection", 1, getManagedConnections().size());
+
+ _connection.close();
+ assertEquals("Expected no managed connections after client connection closed", 0, getManagedConnections().size());
+ }
+
+ public void testGetAttributes() throws Exception
+ {
+ _connection = getConnection();
+ final ManagedConnection mBean = getConnectionMBean();
+
+ checkAuthorisedId(mBean);
+ checkClientVersion(mBean);
+ checkClientId(mBean);
+ }
+
+ public void testNonTransactedSession() throws Exception
+ {
+ _connection = getConnection();
+
+ boolean transactional = false;
+ boolean flowBlocked = false;
+
+ _connection.createSession(transactional, Session.AUTO_ACKNOWLEDGE);
+
+ final ManagedConnection mBean = getConnectionMBean();
+ final CompositeDataSupport row = getTheOneChannelRow(mBean);
+ assertChannelRowData(row, 0, transactional, flowBlocked);
+ }
+
+ public void testTransactedSessionWithUnackMessages() throws Exception
+ {
+ _connection = getConnection();
+ _connection.start();
+
+ boolean transactional = true;
+ int numberOfMessages = 2;
+ final Session session = _connection.createSession(transactional, Session.SESSION_TRANSACTED);
+ final Destination destination = session.createQueue(getTestQueueName());
+ final MessageConsumer consumer = session.createConsumer(destination);
+
+ sendMessage(session, destination, numberOfMessages);
+ receiveMessagesWithoutCommit(consumer, numberOfMessages);
+
+ final ManagedConnection mBean = getConnectionMBean();
+ final CompositeDataSupport row = getTheOneChannelRow(mBean);
+ boolean flowBlocked = false;
+ assertChannelRowData(row, numberOfMessages, transactional, flowBlocked);
+
+ // check that commit advances the lastIoTime
+ final Date initialLastIOTime = mBean.getLastIoTime();
+ session.commit();
+ assertTrue("commit should have caused last IO time to advance", mBean.getLastIoTime().after(initialLastIOTime));
+
+ // check that channels() now returns one session with no unacknowledged messages
+ final CompositeDataSupport rowAfterCommit = getTheOneChannelRow(mBean);
+ final Number unackCountAfterCommit = (Number) rowAfterCommit.get(ManagedConnection.UNACKED_COUNT);
+ assertEquals("Unexpected number of unacknowledged messages", 0, unackCountAfterCommit);
+ }
+
+
+ public void testProducerFlowBlocked() throws Exception
+ {
+ _connection = getConnection();
+ _connection.start();
+
+ String queueName = getTestQueueName();
+ Session session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ Queue queue = session.createQueue(queueName);
+ createQueueOnBroker(session, queue);
+
+ ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ managedQueue.setFlowResumeCapacity(DEFAULT_MESSAGE_SIZE * 2l);
+ managedQueue.setCapacity(DEFAULT_MESSAGE_SIZE * 3l);
+
+ final ManagedConnection managedConnection = getConnectionMBean();
+
+ // Check that producer flow is not block before test
+ final CompositeDataSupport rowBeforeSend = getTheOneChannelRow(managedConnection);
+ assertFlowBlocked(rowBeforeSend, false);
+
+
+ // Check that producer flow does not become block too soon
+ sendMessage(session, queue, 3);
+ final CompositeDataSupport rowBeforeFull = getTheOneChannelRow(managedConnection);
+ assertFlowBlocked(rowBeforeFull, false);
+
+ // Fourth message will over-fill the queue (but as we are not sending more messages, client thread wont't block)
+ sendMessage(session, queue, 1);
+ final CompositeDataSupport rowAfterFull = getTheOneChannelRow(managedConnection);
+ assertFlowBlocked(rowAfterFull, true);
+
+ // Consume two to bring the queue down to the resume capacity
+ MessageConsumer consumer = session.createConsumer(queue);
+ assertNotNull("Could not receive first message", consumer.receive(1000));
+ assertNotNull("Could not receive second message", consumer.receive(1000));
+ session.commit();
+
+ // Check that producer flow is no longer blocked
+ final CompositeDataSupport rowAfterReceive = getTheOneChannelRow(managedConnection);
+ assertFlowBlocked(rowAfterReceive, false);
+ }
+
+ private void createQueueOnBroker(Session session, Destination destination) throws JMSException
+ {
+ session.createConsumer(destination).close(); // Create a consumer only to cause queue creation
+ }
+
+ private void assertChannelRowData(final CompositeData row, int unacknowledgedMessages, boolean isTransactional, boolean flowBlocked)
+ {
+ assertNotNull(row);
+ assertEquals("Unexpected transactional flag", isTransactional, row.get(ManagedConnection.TRANSACTIONAL));
+ assertEquals("Unexpected unacknowledged message count", unacknowledgedMessages, row.get(ManagedConnection.UNACKED_COUNT));
+ assertEquals("Unexpected flow blocked", flowBlocked, row.get(ManagedConnection.FLOW_BLOCKED));
+ }
+
+ private void assertFlowBlocked(final CompositeData row, boolean flowBlocked)
+ {
+ assertNotNull(row);
+ assertEquals("Unexpected flow blocked", flowBlocked, row.get(ManagedConnection.FLOW_BLOCKED));
+ }
+
+ private void checkAuthorisedId(ManagedConnection mBean) throws Exception
+ {
+ assertEquals("Unexpected authorized id", GUEST_USERNAME, mBean.getAuthorizedId());
+ }
+
+ private void checkClientVersion(ManagedConnection mBean) throws Exception
+ {
+ String expectedVersion = QpidProperties.getReleaseVersion();
+ assertTrue(StringUtils.isNotBlank(expectedVersion));
+
+ assertEquals("Unexpected version", expectedVersion, mBean.getVersion());
+ }
+
+ private void checkClientId(ManagedConnection mBean) throws Exception
+ {
+ String expectedClientId = _connection.getClientID();
+ assertTrue(StringUtils.isNotBlank(expectedClientId));
+
+ assertEquals("Unexpected ClientId", expectedClientId, mBean.getClientId());
+ }
+
+ private ManagedConnection getConnectionMBean()
+ {
+ List<ManagedConnection> connections = getManagedConnections();
+ assertNotNull("Connection MBean is not found", connections);
+ assertEquals("Unexpected number of connection mbeans", 1, connections.size());
+ final ManagedConnection mBean = connections.get(0);
+ assertNotNull("Connection MBean is null", mBean);
+ return mBean;
+ }
+
+ private List<ManagedConnection> getManagedConnections()
+ {
+ return _jmxUtils.getManagedConnections(VIRTUAL_HOST_NAME);
+ }
+
+ private CompositeDataSupport getTheOneChannelRow(final ManagedConnection mBean) throws Exception
+ {
+ TabularData channelsData = getChannelsDataWithRetry(mBean);
+
+ assertEquals("Unexpected number of rows in channel table", 1, channelsData.size());
+
+ @SuppressWarnings("unchecked")
+ final Iterator<CompositeDataSupport> rowItr = (Iterator<CompositeDataSupport>) channelsData.values().iterator();
+ final CompositeDataSupport row = rowItr.next();
+ return row;
+ }
+
+ private void receiveMessagesWithoutCommit(final MessageConsumer consumer, int numberOfMessages) throws Exception
+ {
+ for (int i = 0; i < numberOfMessages; i++)
+ {
+ final Message m = consumer.receive(1000l);
+ assertNotNull("Message " + i + " is not received", m);
+ }
+ }
+
+ private TabularData getChannelsDataWithRetry(final ManagedConnection mBean)
+ throws IOException, JMException
+ {
+ TabularData channelsData = mBean.channels();
+ int retries = 0;
+ while(channelsData.size() == 0 && retries < 5)
+ {
+ sleep();
+ channelsData = mBean.channels();
+ retries++;
+ }
+ return channelsData;
+ }
+
+ private void sleep()
+ {
+ try
+ {
+ Thread.sleep(50);
+ }
+ catch (InterruptedException ie)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java
new file mode 100644
index 0000000000..2a112eab35
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.systest.management.jmx;
+
+import java.io.File;
+import java.util.List;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+
+import org.apache.qpid.management.common.mbeans.LoggingManagement;
+import org.apache.qpid.server.logging.log4j.LoggingManagementFacadeTest;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+import org.apache.qpid.util.FileUtils;
+import org.apache.qpid.util.LogMonitor;
+
+/**
+ * System test for Logging Management. <b>These tests rely on value set within
+ * test-profiles/log4j-test.xml</b>.
+ *
+ * @see LoggingManagementMBeanTest
+ * @see LoggingManagementFacadeTest
+ *
+ */
+public class LoggingManagementTest extends QpidBrokerTestCase
+{
+ private JMXTestUtils _jmxUtils;
+ private LoggingManagement _loggingManagement;
+ private LogMonitor _monitor;
+
+ public void setUp() throws Exception
+ {
+ _jmxUtils = new JMXTestUtils(this);
+ _jmxUtils.setUp();
+
+ // System test normally run with log for4j test config from beneath test-profiles. We need to
+ // copy it as some of our tests write to this file.
+
+ File tmpLogFile = File.createTempFile("log4j" + "." + getName(), ".xml");
+ tmpLogFile.deleteOnExit();
+ FileUtils.copy(_logConfigFile, tmpLogFile);
+
+ _logConfigFile = tmpLogFile;
+
+ super.setUp();
+ _jmxUtils.open();
+
+ _loggingManagement = _jmxUtils.getLoggingManagement();
+ _monitor = new LogMonitor(_outputFile);
+ }
+
+ public void tearDown() throws Exception
+ {
+ try
+ {
+ if (_jmxUtils != null)
+ {
+ _jmxUtils.close();
+ }
+ }
+ finally
+ {
+ super.tearDown();
+ }
+ }
+
+ public void testViewEffectiveRuntimeLoggerLevels() throws Exception
+ {
+ final String qpidMainLogger = "org.apache.qpid";
+
+ TabularData table = _loggingManagement.viewEffectiveRuntimeLoggerLevels();
+ final CompositeData row = table.get(new String[] {qpidMainLogger} );
+ assertChannelRow(row, qpidMainLogger, "DEBUG");
+ }
+
+ public void testViewConfigFileLoggerLevels() throws Exception
+ {
+ final String operationalLoggingLogger = "qpid.message";
+
+ TabularData table = _loggingManagement.viewConfigFileLoggerLevels();
+ final CompositeData row = table.get(new String[] {operationalLoggingLogger} );
+ assertChannelRow(row, operationalLoggingLogger, "INFO");
+ }
+
+ public void testTurnOffOrgApacheQpidAtRuntime() throws Exception
+ {
+ final String logger = "org.apache.qpid";
+ _monitor.markDiscardPoint();
+ _loggingManagement.setRuntimeLoggerLevel(logger, "OFF");
+
+ List<String> matches = _monitor.findMatches("Setting level to OFF for logger 'org.apache.qpid'");
+ assertEquals(1, matches.size());
+
+ TabularData table = _loggingManagement.viewEffectiveRuntimeLoggerLevels();
+ final CompositeData row1 = table.get(new String[] {logger} );
+ assertChannelRow(row1, logger, "OFF");
+ }
+
+ public void testChangesToConfigFileBecomeEffectiveAfterReload() throws Exception
+ {
+ final String operationalLoggingLogger = "qpid.message";
+ assertEffectiveLoggingLevel(operationalLoggingLogger, "INFO");
+
+ _monitor.markDiscardPoint();
+ _loggingManagement.setConfigFileLoggerLevel(operationalLoggingLogger, "OFF");
+
+ List<String> matches = _monitor.findMatches("Setting level to OFF for logger 'qpid.message'");
+ assertEquals(1, matches.size());
+
+ assertEffectiveLoggingLevel(operationalLoggingLogger, "INFO");
+
+ _loggingManagement.reloadConfigFile();
+
+ assertEffectiveLoggingLevel(operationalLoggingLogger, "OFF");
+ }
+
+ private void assertEffectiveLoggingLevel(String operationalLoggingLogger, String expectedLevel)
+ {
+ TabularData table = _loggingManagement.viewEffectiveRuntimeLoggerLevels();
+ final CompositeData row1 = table.get(new String[] {operationalLoggingLogger} );
+ assertChannelRow(row1, operationalLoggingLogger, expectedLevel);
+ }
+
+ private void assertChannelRow(final CompositeData row, String logger, String level)
+ {
+ assertNotNull("No row for " + logger, row);
+ assertEquals("Unexpected logger name", logger, row.get(LoggingManagement.LOGGER_NAME));
+ assertEquals("Unexpected level", level, row.get(LoggingManagement.LOGGER_LEVEL));
+ }
+
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java
new file mode 100644
index 0000000000..47b38381c5
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java
@@ -0,0 +1,480 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.management.jmx;
+
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
+import org.apache.qpid.management.common.mbeans.ManagedExchange;
+import org.apache.qpid.server.logging.AbstractTestLogging;
+import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject;
+import org.apache.qpid.test.utils.JMXTestUtils;
+
+import javax.jms.Connection;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.management.JMException;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test class to test if any change in the broker JMX code is affesting the management console
+ * There are some hardcoding of management feature names and parameter names to create a customized
+ * look in the console.
+ */
+public class ManagementActorLoggingTest extends AbstractTestLogging
+{
+ private JMXTestUtils _jmxUtils;
+ private boolean _closed = false;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _jmxUtils = new JMXTestUtils(this);
+ _jmxUtils.setUp();
+ super.setUp();
+ _jmxUtils.open();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ if(!_closed)
+ {
+ _jmxUtils.close();
+ }
+ super.tearDown();
+ }
+
+ /**
+ * Description:
+ * When a connected client has its connection closed via the Management Console this will be logged as a CON-1002 message.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Connected Client
+ * 3. Connection is closed via Management Console
+ * Output:
+ *
+ * <date> CON-1002 : Close
+ *
+ * Validation Steps:
+ * 4. The CON ID is correct
+ * 5. This must be the last CON message for the Connection
+ * 6. It must be preceded by a CON-1001 for this Connection
+ *
+ * @throws Exception - {@see ManagedConnection.closeConnection and #getConnection}
+ * @throws java.io.IOException - if there is a problem reseting the log monitor
+ */
+ public void testConnectionCloseViaManagement() throws IOException, Exception
+ {
+ //Create a connection to the broker
+ Connection connection = getConnection();
+
+ // Monitor the connection for an exception being thrown
+ // this should be a DisconnectionException but it is not this tests
+ // job to valiate that. Only use the exception as a synchronisation
+ // to check the log file for the Close message
+ final CountDownLatch exceptionReceived = new CountDownLatch(1);
+ connection.setExceptionListener(new ExceptionListener()
+ {
+ public void onException(JMSException e)
+ {
+ //Failover being attempted.
+ exceptionReceived.countDown();
+ }
+ });
+
+ //Remove the connection close from any 0-10 connections
+ _monitor.markDiscardPoint();
+
+ // Get a managedConnection
+ ManagedConnection mangedConnection = _jmxUtils.getManagedObject(ManagedConnection.class, "org.apache.qpid:type=VirtualHost.Connection,*");
+
+ //Close the connection
+ mangedConnection.closeConnection();
+
+ //Wait for the connection to close
+ assertTrue("Timed out waiting for conneciton to report close",
+ exceptionReceived.await(2, TimeUnit.SECONDS));
+
+ //Validate results
+ List<String> results = waitAndFindMatches("CON-1002");
+
+ assertEquals("Unexpected Connection Close count", 1, results.size());
+ }
+
+ /**
+ * Description:
+ * Exchange creation is possible from the Management Console.
+ * When an exchanged is created in this way then a EXH-1001 create message
+ * is expected to be logged.
+ * Input:
+ *
+ * 1. Running broker
+ * 2. Connected Management Console
+ * 3. Exchange Created via Management Console
+ * Output:
+ *
+ * EXH-1001 : Create : [Durable] Type:<value> Name:<value>
+ *
+ * Validation Steps:
+ * 4. The EXH ID is correct
+ * 5. The correct tags are present in the message based on the create options
+ *
+ * @throws java.io.IOException - if there is a problem reseting the log monitor
+ * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.deleteQueue}
+ */
+ public void testCreateExchangeDirectTransientViaManagementConsole() throws IOException, JMException
+ {
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createExchange("test", getName(), "direct", false);
+
+ // Validate
+
+ //1 - ID is correct
+ List<String> results = waitAndFindMatches("EXH-1001");
+
+ assertEquals("More than one exchange creation found", 1, results.size());
+
+ String log = getLogMessage(results, 0);
+
+ // Validate correct exchange name
+ assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ }
+
+ public void testCreateExchangeTopicTransientViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous exchange declares
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createExchange("test", getName(), "topic", false);
+
+ // Validate
+
+ //1 - ID is correct
+ List<String> results = waitAndFindMatches("EXH-1001");
+
+ assertEquals("More than one exchange creation found", 1, results.size());
+
+ String log = getLogMessage(results, 0);
+
+ // Validate correct exchange name
+ assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+
+ }
+
+ public void testCreateExchangeFanoutTransientViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous exchange declares
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createExchange("test", getName(), "fanout", false);
+
+ // Validate
+
+ //1 - ID is correct
+ List<String> results = waitAndFindMatches("EXH-1001");
+
+ assertEquals("More than one exchange creation found", 1, results.size());
+
+ String log = getLogMessage(results, 0);
+
+ // Validate correct exchange name
+ assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+
+ }
+
+ public void testCreateExchangeHeadersTransientViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous exchange declares
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createExchange("test", getName(), "headers", false);
+
+ // Validate
+
+ //1 - ID is correct
+ List<String> results = waitAndFindMatches("EXH-1001");
+
+ assertEquals("More than one exchange creation found", 1, results.size());
+
+ String log = getLogMessage(results, 0);
+
+ // Validate correct exchange name
+ assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName()));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+
+ }
+
+ /**
+ * Description:
+ * Queue creation is possible from the Management Console. When a queue is created in this way then a QUE-1001 create message is expected to be logged.
+ * Input:
+ *
+ * 1. Running broker
+ * 2. Connected Management Console
+ * 3. Queue Created via Management Console
+ * Output:
+ *
+ * <date> QUE-1001 : Create : Transient Owner:<name>
+ *
+ * Validation Steps:
+ * 4. The QUE ID is correct
+ * 5. The correct tags are present in the message based on the create options
+ *
+ * @throws java.io.IOException - if there is a problem reseting the log monitor
+ * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.deleteQueue}
+ */
+ public void testCreateQueueTransientViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous queue declares
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createQueue("test", getName(), null, false);
+
+ // Validate
+
+ List<String> results = waitAndFindMatches("QUE-1001");
+
+ assertEquals("More than one queue creation found", 1, results.size());
+
+ String log = getLogMessage(results, 0);
+
+ // Validate correct queue name
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue name created", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ }
+
+ /**
+ * Description:
+ * The ManagementConsole can be used to delete a queue. When this is done a QUE-1002 Deleted message must be logged.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Queue created on the broker with no subscribers
+ * 3. Management Console connected
+ * 4. Queue is deleted via Management Console
+ * Output:
+ *
+ * <date> QUE-1002 : Deleted
+ *
+ * Validation Steps:
+ * 5. The QUE ID is correct
+ *
+ * @throws java.io.IOException - if there is a problem reseting the log monitor
+ * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.deleteQueue}
+ */
+ public void testQueueDeleteViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous queue declares
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createQueue("test", getName(), null, false);
+
+ ManagedBroker managedBroker = _jmxUtils.getManagedBroker("test");
+
+ managedBroker.deleteQueue(getName());
+
+ List<String> results = waitAndFindMatches("QUE-1002");
+
+ assertEquals("More than one queue deletion found", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue named in delete", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+
+ }
+
+ /**
+ * Description:
+ * The binding of a Queue and an Exchange is done via a Binding. When this Binding is created via the Management Console a BND-1001 Create message will be logged.
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Connected Management Console
+ * 3. Use Management Console to perform binding
+ * Output:
+ *
+ * <date> BND-1001 : Create
+ *
+ * Validation Steps:
+ * 4. The BND ID is correct
+ * 5. This will be the first message for the given binding
+ *
+ * @throws java.io.IOException - if there is a problem reseting the log monitor
+ * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.createNewBinding}
+ */
+ public void testBindingCreateOnDirectViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous queue declares
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createQueue("test", getName(), null, false);
+
+ ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.direct");
+
+ managedExchange.createNewBinding(getName(), getName());
+
+ List<String> results = waitAndFindMatches("BND-1001");
+
+ assertEquals("Unexpected number of bindings logged", 2, results.size());
+
+ String log = getLogMessage(results, 0);
+
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+ assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ }
+
+ public void testBindingCreateOnTopicViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous queue declares
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createQueue("test", getName(), null, false);
+
+ ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.topic");
+
+ managedExchange.createNewBinding(getName(), getName());
+
+ List<String> results = waitAndFindMatches("BND-1001");
+
+ assertEquals("Unexpected number of bindings logged", 2, results.size());
+
+ String log = getLogMessage(results, 0);
+
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+ assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ }
+
+ public void testBindingCreateOnFanoutViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous queue declares
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createQueue("test", getName(), null, false);
+
+ ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.fanout");
+
+ managedExchange.createNewBinding(getName(), getName());
+
+ List<String> results = waitAndFindMatches("BND-1001");
+
+ assertEquals("Unexpected number of bindings logged", 2, results.size());
+
+ String log = getLogMessage(results, 0);
+
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject));
+ assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ }
+
+ /**
+ * Description:
+ * Bindings can be deleted so that a queue can be rebound with a different set of values. This can be performed via the Management Console
+ * Input:
+ *
+ * 1. Running Broker
+ * 2. Management Console connected
+ * 3. Management Console is used to perform unbind.
+ * Output:
+ *
+ * <date> BND-1002 : Deleted
+ *
+ * Validation Steps:
+ * 4. The BND ID is correct
+ * 5. There must have been a BND-1001 Create message first.
+ * 6. This will be the last message for the given binding
+ *
+ * @throws java.io.IOException - if there is a problem reseting the log monitor or an issue with the JMX Connection
+ * @throws javax.management.JMException - {@see #createExchange and ManagedBroker.unregisterExchange}
+ */
+ public void testUnRegisterExchangeViaManagementConsole() throws IOException, JMException
+ {
+ //Remove any previous queue declares
+ _monitor.markDiscardPoint();
+
+ _jmxUtils.createExchange("test", getName(), "direct", false);
+
+ ManagedBroker managedBroker = _jmxUtils.getManagedBroker("test");
+
+ managedBroker.unregisterExchange(getName());
+
+ List<String> results = waitAndFindMatches("EXH-1002");
+
+ assertEquals("More than one exchange deletion found", 1, results.size());
+
+ String log = getLog(results.get(0));
+
+ // Validate correct binding
+ String subject = fromSubject(log);
+ assertEquals("Incorrect exchange named in delete", "direct/" + getName(), AbstractTestLogSubject.getSlice("ex", subject));
+
+ // Validate it was a management actor.
+ String actor = fromActor(log);
+ assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng"));
+ }
+
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java
new file mode 100644
index 0000000000..9fe043b23d
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java
@@ -0,0 +1,318 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.management.jmx;
+
+
+import org.apache.qpid.server.configuration.ServerConfiguration;
+import org.apache.qpid.server.logging.AbstractTestLogging;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.util.LogMonitor;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * Management Console Test Suite
+ *
+ * The Management Console test suite validates that the follow log messages as specified in the Functional Specification.
+ *
+ * This suite of tests validate that the management console messages occur correctly and according to the following format:
+ *
+ * MNG-1001 : <type> Management Startup
+ * MNG-1002 : Starting : <service> : Listening on port <Port>
+ * MNG-1003 : Shutting down : <service> : port <Port>
+ * MNG-1004 : <type> Management Ready
+ * MNG-1005 : <type> Management Stopped
+ * MNG-1006 : Using SSL Keystore : <path>
+ * MNG-1007 : Open : User <username>
+ * MNG-1008 : Close : User <username>
+ */
+public class ManagementLoggingTest extends AbstractTestLogging
+{
+ private static final String MNG_PREFIX = "MNG-";
+
+ public void setUp() throws Exception
+ {
+ setLogMessagePrefix();
+
+ // We either do this here or have a null check in tearDown.
+ // As when this test is run against profiles other than java it will NPE
+ _monitor = new LogMonitor(_outputFile);
+ //We explicitly do not call super.setUp as starting up the broker is
+ //part of the test case.
+
+ }
+
+ /**
+ * Description:
+ * Using the startup configuration validate that the management startup
+ * message is logged correctly.
+ * Input:
+ * Standard configuration with management enabled
+ * Output:
+ *
+ * <date> MNG-1001 : Startup
+ *
+ * Constraints:
+ * This is the FIRST message logged by MNG
+ * Validation Steps:
+ *
+ * 1. The BRK ID is correct
+ * 2. This is the FIRST message logged by MNG
+ */
+ public void testManagementStartupEnabled() throws Exception
+ {
+ // This test only works on java brokers
+ if (isJavaBroker())
+ {
+ startBrokerAndCreateMonitor(true, false);
+
+ // Ensure we have received the MNG log msg.
+ waitForMessage("MNG-1001");
+
+ List<String> results = findMatches(MNG_PREFIX);
+ // Validation
+
+ assertTrue("MNGer message not logged", results.size() > 0);
+
+ String log = getLogMessage(results, 0);
+
+ //1
+ validateMessageID("MNG-1001", log);
+
+ //2
+ //There will be 2 copies of the startup message (one via SystemOut, and one via Log4J)
+ results = findMatches("MNG-1001");
+ assertEquals("Unexpected startup message count.",
+ 2, results.size());
+
+ //3
+ assertEquals("Startup log message is not 'Startup'.", "JMX Management Startup",
+ getMessageString(log));
+ }
+ }
+
+ /**
+ * Description:
+ * Verify that when management is disabled in the configuration file the
+ * startup message is not logged.
+ * Input:
+ * Standard configuration with management disabled
+ * Output:
+ * NO MNG messages
+ * Validation Steps:
+ *
+ * 1. Validate that no MNG messages are produced.
+ */
+ public void testManagementStartupDisabled() throws Exception
+ {
+ if (isJavaBroker())
+ {
+ startBrokerAndCreateMonitor(false, false);
+
+ List<String> results = findMatches(MNG_PREFIX);
+ // Validation
+
+ assertEquals("MNGer messages logged", 0, results.size());
+ }
+ }
+
+ /**
+ * The two MNG-1002 messages are logged at the same time so lets test them
+ * at the same time.
+ *
+ * Description:
+ * Using the default configuration validate that the RMI Registry socket is
+ * correctly reported as being opened
+ *
+ * Input:
+ * The default configuration file
+ * Output:
+ *
+ * <date> MESSAGE MNG-1002 : Starting : RMI Registry : Listening on port 8999
+ *
+ * Constraints:
+ * The RMI ConnectorServer and Registry log messages do not have a prescribed order
+ * Validation Steps:
+ *
+ * 1. The MNG ID is correct
+ * 2. The specified port is the correct '8999'
+ *
+ * Description:
+ * Using the default configuration validate that the RMI ConnectorServer
+ * socket is correctly reported as being opened
+ *
+ * Input:
+ * The default configuration file
+ * Output:
+ *
+ * <date> MESSAGE MNG-1002 : Starting : RMI ConnectorServer : Listening on port 9099
+ *
+ * Constraints:
+ * The RMI ConnectorServer and Registry log messages do not have a prescribed order
+ * Validation Steps:
+ *
+ * 1. The MNG ID is correct
+ * 2. The specified port is the correct '9099'
+ */
+ public void testManagementStartupRMIEntries() throws Exception
+ {
+ if (isJavaBroker())
+ {
+ startBrokerAndCreateMonitor(true, false);
+
+ List<String> results = waitAndFindMatches("MNG-1002");
+ // Validation
+
+ //There will be 4 startup messages (two via SystemOut, and two via Log4J)
+ assertEquals("Unexpected MNG-1002 message count", 4, results.size());
+
+ String log = getLogMessage(results, 0);
+
+ //1
+ validateMessageID("MNG-1002", log);
+
+ //Check the RMI Registry port is as expected
+ int mPort = getManagementPort(getPort());
+ assertTrue("RMI Registry port not as expected(" + mPort + ").:" + getMessageString(log),
+ getMessageString(log).endsWith(String.valueOf(mPort)));
+
+ log = getLogMessage(results, 2);
+
+ //1
+ validateMessageID("MNG-1002", log);
+
+ // We expect the RMI Registry port (the defined 'management port') to be
+ // 100 lower than the JMX RMIConnector Server Port (the actual JMX server)
+ int jmxPort = mPort + ServerConfiguration.JMXPORT_CONNECTORSERVER_OFFSET;
+ assertTrue("JMX RMIConnectorServer port not as expected(" + jmxPort + ").:" + getMessageString(log),
+ getMessageString(log).endsWith(String.valueOf(jmxPort)));
+ }
+ }
+
+ /**
+ * Description:
+ * Using the default configuration with SSL enabled for the management port the SSL Keystore path should be reported via MNG-1006
+ * Input:
+ * Management SSL enabled default configuration.
+ * Output:
+ *
+ * <date> MESSAGE MNG-1006 : Using SSL Keystore : test_resources/ssl/keystore.jks
+ *
+ * Validation Steps:
+ *
+ * 1. The MNG ID is correct
+ * 2. The keystore path is as specified in the configuration
+ */
+ public void testManagementStartupSSLKeystore() throws Exception
+ {
+ if (isJavaBroker())
+ {
+ setSystemProperty("javax.net.debug", "ssl");
+ startBrokerAndCreateMonitor(true, true);
+
+ List<String> results = waitAndFindMatches("MNG-1006");
+
+ assertTrue("MNGer message not logged", results.size() > 0);
+
+ String log = getLogMessage(results, 0);
+
+ //1
+ validateMessageID("MNG-1006", log);
+
+ // Validate we only have two MNG-1002 (one via stdout, one via log4j)
+ results = findMatches("MNG-1006");
+ assertEquals("Upexpected SSL Keystore message count",
+ 2, results.size());
+
+ // Validate the keystore path is as expected
+ assertTrue("SSL Keystore entry expected.:" + getMessageString(log),
+ getMessageString(log).endsWith(new File(getConfigurationStringProperty("management.ssl.keyStorePath")).getName()));
+ }
+ }
+
+ /**
+ * Description: Tests the management connection open/close are logged correctly.
+ *
+ * Output:
+ *
+ * <date> MESSAGE MNG-1007 : Open : User <username>
+ * <date> MESSAGE MNG-1008 : Close : User <username>
+ *
+ * Validation Steps:
+ *
+ * 1. The MNG ID is correct
+ * 2. The message and username are correct
+ */
+ public void testManagementUserOpenClose() throws Exception
+ {
+ if (isJavaBroker())
+ {
+ startBrokerAndCreateMonitor(true, false);
+
+ final JMXTestUtils jmxUtils = new JMXTestUtils(this);
+ List<String> openResults = null;
+ List<String> closeResults = null;
+ try
+ {
+ jmxUtils.setUp();
+ jmxUtils.open();
+ openResults = waitAndFindMatches("MNG-1007");
+ }
+ finally
+ {
+ if (jmxUtils != null)
+ {
+ jmxUtils.close();
+ closeResults = waitAndFindMatches("MNG-1008");
+ }
+ }
+
+ assertNotNull("Management Open results null", openResults.size());
+ assertEquals("Management Open logged unexpected number of times", 1, openResults.size());
+
+ assertNotNull("Management Close results null", closeResults.size());
+ assertEquals("Management Close logged unexpected number of times", 1, closeResults.size());
+
+ final String openMessage = getMessageString(getLogMessage(openResults, 0));
+ assertTrue("Unexpected open message " + openMessage, openMessage.endsWith("Open : User admin"));
+ final String closeMessage = getMessageString(getLogMessage(closeResults, 0));
+ assertTrue("Unexpected close message " + closeMessage, closeMessage.endsWith("Close : User admin"));
+ }
+ }
+
+ private void startBrokerAndCreateMonitor(boolean managementEnabled, boolean useManagementSSL) throws Exception
+ {
+ //Ensure management is on
+ setConfigurationProperty("management.enabled", String.valueOf(managementEnabled));
+
+ if(useManagementSSL)
+ {
+ // This test requires we have an ssl connection
+ setConfigurationProperty("management.ssl.enabled", "true");
+ }
+
+ startBroker();
+
+ // Now we can create the monitor as _outputFile will now be defined
+ _monitor = new LogMonitor(_outputFile);
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java
new file mode 100644
index 0000000000..79d04b239e
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java
@@ -0,0 +1,696 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.systest.management.jmx;
+
+import org.apache.commons.lang.time.FastDateFormat;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.configuration.ClientProperties;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedQueue;
+import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.apache.qpid.server.queue.NotificationCheckTest;
+import org.apache.qpid.server.queue.SimpleAMQQueueTest;
+import org.apache.qpid.test.client.destination.AddressBasedDestinationTest;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+import javax.naming.NamingException;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Tests the JMX API for the Managed Queue.
+ *
+ */
+public class QueueManagementTest extends QpidBrokerTestCase
+{
+
+ private static final Logger LOGGER = Logger.getLogger(QueueManagementTest.class);
+
+ private static final String VIRTUAL_HOST = "test";
+ private static final String TEST_QUEUE_DESCRIPTION = "my description";
+
+ private JMXTestUtils _jmxUtils;
+ private Connection _connection;
+ private Session _session;
+
+ private String _sourceQueueName;
+ private String _destinationQueueName;
+ private Destination _sourceQueue;
+ private Destination _destinationQueue;
+ private ManagedQueue _managedSourceQueue;
+ private ManagedQueue _managedDestinationQueue;
+
+ public void setUp() throws Exception
+ {
+ _jmxUtils = new JMXTestUtils(this);
+ _jmxUtils.setUp();
+
+ super.setUp();
+ _sourceQueueName = getTestQueueName() + "_src";
+ _destinationQueueName = getTestQueueName() + "_dest";
+
+ createConnectionAndSession();
+
+ _sourceQueue = _session.createQueue(_sourceQueueName);
+ _destinationQueue = _session.createQueue(_destinationQueueName);
+ createQueueOnBroker(_sourceQueue);
+ createQueueOnBroker(_destinationQueue);
+
+ _jmxUtils.open();
+
+ createManagementInterfacesForQueues();
+ }
+
+ public void tearDown() throws Exception
+ {
+ if (_jmxUtils != null)
+ {
+ _jmxUtils.close();
+ }
+ super.tearDown();
+ }
+
+ public void testQueueAttributes() throws Exception
+ {
+ Queue queue = _session.createQueue(getTestQueueName());
+ createQueueOnBroker(queue);
+
+ final String queueName = queue.getQueueName();
+
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertEquals("Unexpected name", queueName, managedQueue.getName());
+ assertEquals("Unexpected queue type", "standard", managedQueue.getQueueType());
+ }
+
+ public void testExclusiveQueueHasJmsClientIdAsOwner() throws Exception
+ {
+ Queue tmpQueue = _session.createTemporaryQueue();
+
+ final String queueName = tmpQueue.getQueueName();
+
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertNotNull(_connection.getClientID());
+ assertEquals("Unexpected owner", _connection.getClientID(), managedQueue.getOwner());
+ }
+
+ public void testNonExclusiveQueueHasNoOwner() throws Exception
+ {
+ Queue nonExclusiveQueue = _session.createQueue(getTestQueueName());
+ createQueueOnBroker(nonExclusiveQueue);
+
+ final String queueName = nonExclusiveQueue.getQueueName();
+
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertNull("Unexpected owner", managedQueue.getOwner());
+ }
+
+ public void testSetNewQueueDescriptionOnExistingQueue() throws Exception
+ {
+ Queue queue = _session.createQueue(getTestQueueName());
+ createQueueOnBroker(queue);
+
+ final String queueName = queue.getQueueName();
+
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertNull("Unexpected description", managedQueue.getDescription());
+
+ managedQueue.setDescription(TEST_QUEUE_DESCRIPTION);
+ assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription());
+ }
+
+ public void testNewQueueWithDescription() throws Exception
+ {
+ String queueName = getTestQueueName();
+ Map<String, Object> arguments = Collections.singletonMap(AMQQueueFactory.X_QPID_DESCRIPTION, (Object)TEST_QUEUE_DESCRIPTION);
+ ((AMQSession<?, ?>)_session).createQueue(AMQShortString.valueOf(queueName), false, true, false, arguments);
+
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription());
+ }
+
+ /**
+ * Requires persistent store.
+ */
+ public void testQueueDescriptionSurvivesRestart() throws Exception
+ {
+ String queueName = getTestQueueName();
+ Map<String, Object> arguments = Collections.singletonMap(AMQQueueFactory.X_QPID_DESCRIPTION, (Object)TEST_QUEUE_DESCRIPTION);
+
+ ((AMQSession<?, ?>)_session).createQueue(AMQShortString.valueOf(queueName), false, true, false, arguments);
+
+ ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription());
+
+ restartBroker();
+
+ managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription());
+ }
+
+ /**
+ * Tests queue creation with {@link AMQQueueFactory#X_QPID_MAXIMUM_DELIVERY_COUNT} argument. Also tests
+ * that the attribute is exposed correctly through {@link ManagedQueue#getMaximumDeliveryCount()}.
+ */
+ public void testCreateQueueWithMaximumDeliveryCountSet() throws Exception
+ {
+ final String queueName = getName();
+ final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST);
+
+ final Integer deliveryCount = 1;
+ final Map<String, Object> arguments = Collections.singletonMap(AMQQueueFactory.X_QPID_MAXIMUM_DELIVERY_COUNT, (Object)deliveryCount);
+ managedBroker.createNewQueue(queueName, null, true, arguments);
+
+ // Ensure the queue exists
+ assertNotNull("Queue object name expected to exist", _jmxUtils.getQueueObjectName("test", queueName));
+ assertNotNull("Manager queue expected to be available", _jmxUtils.getManagedQueue(queueName));
+
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertEquals("Unexpected maximum delivery count", deliveryCount, managedQueue.getMaximumDeliveryCount());
+ }
+
+ /**
+ * Requires 0-10 as relies on ADDR addresses.
+ * @see AddressBasedDestinationTest for the testing of message routing to the alternate exchange
+ */
+ public void testGetSetAlternateExchange() throws Exception
+ {
+ String queueName = getTestQueueName();
+ String altExchange = "amq.fanout";
+ String addrWithAltExch = String.format("ADDR:%s;{create:always,node:{type:queue,x-declare:{alternate-exchange:'%s'}}}", queueName, altExchange);
+ Queue queue = _session.createQueue(addrWithAltExch);
+
+ createQueueOnBroker(queue);
+
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertEquals("Newly created queue does not have expected alternate exchange", altExchange, managedQueue.getAlternateExchange());
+
+ String newAltExch = "amq.topic";
+ managedQueue.setAlternateExchange(newAltExch);
+ assertEquals("Unexpected alternate exchange after set", newAltExch, managedQueue.getAlternateExchange());
+ }
+
+ /**
+ * Requires 0-10 as relies on ADDR addresses.
+ */
+ public void testRemoveAlternateExchange() throws Exception
+ {
+ String queueName = getTestQueueName();
+ String altExchange = "amq.fanout";
+ String addrWithAltExch = String.format("ADDR:%s;{create:always,node:{type:queue,x-declare:{alternate-exchange:'%s'}}}", queueName, altExchange);
+ Queue queue = _session.createQueue(addrWithAltExch);
+
+ createQueueOnBroker(queue);
+
+ final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ assertEquals("Newly created queue does not have expected alternate exchange", altExchange, managedQueue.getAlternateExchange());
+
+ managedQueue.setAlternateExchange("");
+ assertNull("Unexpected alternate exchange after set", managedQueue.getAlternateExchange());
+ }
+
+ /**
+ * Requires persistent store
+ * Requires 0-10 as relies on ADDR addresses.
+ */
+ public void testAlternateExchangeSurvivesRestart() throws Exception
+ {
+ String nonMandatoryExchangeName = "exch" + getName();
+
+ final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST);
+ managedBroker.createNewExchange(nonMandatoryExchangeName, "fanout", true);
+
+ String queueName1 = getTestQueueName() + "1";
+ String altExchange1 = "amq.fanout";
+ String addr1WithAltExch = String.format("ADDR:%s;{create:always,node:{durable: true,type:queue,x-declare:{alternate-exchange:'%s'}}}", queueName1, altExchange1);
+ Queue queue1 = _session.createQueue(addr1WithAltExch);
+
+ String queueName2 = getTestQueueName() + "2";
+ String addr2WithoutAltExch = String.format("ADDR:%s;{create:always,node:{durable: true,type:queue}}", queueName2);
+ Queue queue2 = _session.createQueue(addr2WithoutAltExch);
+
+ createQueueOnBroker(queue1);
+ createQueueOnBroker(queue2);
+
+ ManagedQueue managedQueue1 = _jmxUtils.getManagedQueue(queueName1);
+ assertEquals("Newly created queue1 does not have expected alternate exchange", altExchange1, managedQueue1.getAlternateExchange());
+
+ ManagedQueue managedQueue2 = _jmxUtils.getManagedQueue(queueName2);
+ assertNull("Newly created queue2 does not have expected alternate exchange", managedQueue2.getAlternateExchange());
+
+ String altExchange2 = nonMandatoryExchangeName;
+ managedQueue2.setAlternateExchange(altExchange2);
+
+ restartBroker();
+
+ managedQueue1 = _jmxUtils.getManagedQueue(queueName1);
+ assertEquals("Queue1 does not have expected alternate exchange after restart", altExchange1, managedQueue1.getAlternateExchange());
+
+ managedQueue2 = _jmxUtils.getManagedQueue(queueName2);
+ assertEquals("Queue2 does not have expected updated alternate exchange after restart", altExchange2, managedQueue2.getAlternateExchange());
+ }
+
+ /**
+ * Tests the ability to receive queue alerts as JMX notifications.
+ *
+ * @see NotificationCheckTest
+ * @see SimpleAMQQueueTest#testNotificationFiredAsync()
+ * @see SimpleAMQQueueTest#testNotificationFiredOnEnqueue()
+ */
+ public void testQueueNotification() throws Exception
+ {
+ final String queueName = getName();
+ final long maximumMessageCount = 3;
+
+ Queue queue = _session.createQueue(queueName);
+ createQueueOnBroker(queue);
+
+ ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName);
+ managedQueue.setMaximumMessageCount(maximumMessageCount);
+
+ RecordingNotificationListener listener = new RecordingNotificationListener(1);
+
+ _jmxUtils.addNotificationListener(_jmxUtils.getQueueObjectName(VIRTUAL_HOST, queueName), listener, null, null);
+
+ // Send two messages - this should *not* trigger the notification
+ sendMessage(_session, queue, 2);
+
+ assertEquals("Premature notification received", 0, listener.getNumberOfNotificationsReceived());
+
+ // A further message should trigger the message count alert
+ sendMessage(_session, queue, 1);
+
+ listener.awaitExpectedNotifications(5, TimeUnit.SECONDS);
+
+ assertEquals("Unexpected number of JMX notifications received", 1, listener.getNumberOfNotificationsReceived());
+
+ Notification notification = listener.getLastNotification();
+ assertEquals("Unexpected notification message", "MESSAGE_COUNT_ALERT 3: Maximum count on queue threshold (3) breached.", notification.getMessage());
+ }
+
+ /**
+ * Tests {@link ManagedQueue#viewMessages(long, long)} interface.
+ */
+ public void testViewSingleMessage() throws Exception
+ {
+ final List<Message> sentMessages = sendMessage(_session, _sourceQueue, 1);
+ syncSession(_session);
+ final Message sentMessage = sentMessages.get(0);
+
+ assertEquals("Unexpected queue depth", 1, _managedSourceQueue.getMessageCount().intValue());
+
+ // Check the contents of the message
+ final TabularData tab = _managedSourceQueue.viewMessages(1l, 1l);
+ assertEquals("Unexpected number of rows in table", 1, tab.size());
+ final Iterator<CompositeData> rowItr = (Iterator<CompositeData>) tab.values().iterator();
+
+ final CompositeData row1 = rowItr.next();
+ assertNotNull("Message should have AMQ message id", row1.get(ManagedQueue.MSG_AMQ_ID));
+ assertEquals("Unexpected queue position", 1l, row1.get(ManagedQueue.MSG_QUEUE_POS));
+ assertEquals("Unexpected redelivered flag", Boolean.FALSE, row1.get(ManagedQueue.MSG_REDELIVERED));
+
+ // Check the contents of header (encoded in a string array)
+ final String[] headerArray = (String[]) row1.get(ManagedQueue.MSG_HEADER);
+ assertNotNull("Expected message header array", headerArray);
+ final Map<String, String> headers = headerArrayToMap(headerArray);
+
+ final String expectedJMSMessageID = isBroker010() ? sentMessage.getJMSMessageID().replace("ID:", "") : sentMessage.getJMSMessageID();
+ final String expectedFormattedJMSTimestamp = FastDateFormat.getInstance(ManagedQueue.JMSTIMESTAMP_DATETIME_FORMAT).format(sentMessage.getJMSTimestamp());
+ assertEquals("Unexpected JMSMessageID within header", expectedJMSMessageID, headers.get("JMSMessageID"));
+ assertEquals("Unexpected JMSPriority within header", String.valueOf(sentMessage.getJMSPriority()), headers.get("JMSPriority"));
+ assertEquals("Unexpected JMSTimestamp within header", expectedFormattedJMSTimestamp, headers.get("JMSTimestamp"));
+ }
+
+ /**
+ * Tests {@link ManagedQueue#moveMessages(long, long, String)} interface.
+ */
+ public void testMoveMessagesBetweenQueues() throws Exception
+ {
+ final int numberOfMessagesToSend = 10;
+
+ sendMessage(_session, _sourceQueue, numberOfMessagesToSend);
+ syncSession(_session);
+ assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue());
+
+ List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend);
+
+ // Move first three messages to destination
+ long fromMessageId = amqMessagesIds.get(0);
+ long toMessageId = amqMessagesIds.get(2);
+ _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName);
+
+ assertEquals("Unexpected queue depth on destination queue after first move", 3, _managedDestinationQueue.getMessageCount().intValue());
+ assertEquals("Unexpected queue depth on source queue after first move", 7, _managedSourceQueue.getMessageCount().intValue());
+
+ // Now move a further two messages to destination
+ fromMessageId = amqMessagesIds.get(7);
+ toMessageId = amqMessagesIds.get(8);
+ _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName);
+ assertEquals("Unexpected queue depth on destination queue after second move", 5, _managedDestinationQueue.getMessageCount().intValue());
+ assertEquals("Unexpected queue depth on source queue after second move", 5, _managedSourceQueue.getMessageCount().intValue());
+
+ assertMessageIndicesOn(_destinationQueue, 0, 1, 2, 7, 8);
+ }
+
+ /**
+ * Tests {@link ManagedQueue#copyMessages(long, long, String)} interface.
+ */
+ public void testCopyMessagesBetweenQueues() throws Exception
+ {
+ final int numberOfMessagesToSend = 10;
+ sendMessage(_session, _sourceQueue, numberOfMessagesToSend);
+ syncSession(_session);
+ assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue());
+
+ List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend);
+
+ // Copy first three messages to destination
+ long fromMessageId = amqMessagesIds.get(0);
+ long toMessageId = amqMessagesIds.get(2);
+ _managedSourceQueue.copyMessages(fromMessageId, toMessageId, _destinationQueueName);
+
+ assertEquals("Unexpected queue depth on destination queue after first copy", 3, _managedDestinationQueue.getMessageCount().intValue());
+ assertEquals("Unexpected queue depth on source queue after first copy", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue());
+
+ // Now copy a further two messages to destination
+ fromMessageId = amqMessagesIds.get(7);
+ toMessageId = amqMessagesIds.get(8);
+ _managedSourceQueue.copyMessages(fromMessageId, toMessageId, _destinationQueueName);
+ assertEquals("Unexpected queue depth on destination queue after second copy", 5, _managedDestinationQueue.getMessageCount().intValue());
+ assertEquals("Unexpected queue depth on source queue after second copy", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue());
+
+ assertMessageIndicesOn(_destinationQueue, 0, 1, 2, 7, 8);
+ }
+
+ public void testMoveMessagesBetweenQueuesWithActiveConsumerOnSourceQueue() throws Exception
+ {
+ setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, new Integer(1).toString());
+ Connection asyncConnection = getConnection();
+ asyncConnection.start();
+
+ final int numberOfMessagesToSend = 50;
+ sendMessage(_session, _sourceQueue, numberOfMessagesToSend);
+ syncSession(_session);
+ assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue());
+
+ List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend);
+
+ long fromMessageId = amqMessagesIds.get(0);
+ long toMessageId = amqMessagesIds.get(numberOfMessagesToSend - 1);
+
+ CountDownLatch consumerReadToHalfwayLatch = new CountDownLatch(numberOfMessagesToSend / 2);
+ AtomicInteger totalConsumed = new AtomicInteger(0);
+ startAsyncConsumerOn(_sourceQueue, asyncConnection, consumerReadToHalfwayLatch, totalConsumed);
+
+ boolean halfwayPointReached = consumerReadToHalfwayLatch.await(5000, TimeUnit.MILLISECONDS);
+ assertTrue("Did not read half of messages within time allowed", halfwayPointReached);
+
+ _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName);
+
+ asyncConnection.stop();
+
+ // The exact number of messages moved will be non deterministic, as the number of messages processed
+ // by the consumer cannot be predicted. There is also the possibility that a message can remain
+ // on the source queue. This situation will arise if a message has been acquired by the consumer, but not
+ // yet delivered to the client application (i.e. MessageListener#onMessage()) when the Connection#stop() occurs.
+ //
+ // The number of messages moved + the number consumed + any messages remaining on source should
+ // *always* be equal to the number we originally sent.
+
+ int numberOfMessagesReadByConsumer = totalConsumed.intValue();
+ int numberOfMessagesOnDestinationQueue = _managedDestinationQueue.getMessageCount().intValue();
+ int numberOfMessagesRemainingOnSourceQueue = _managedSourceQueue.getMessageCount().intValue();
+
+ LOGGER.debug("Async consumer read : " + numberOfMessagesReadByConsumer
+ + " Number of messages moved to destination : " + numberOfMessagesOnDestinationQueue
+ + " Number of messages remaining on source : " + numberOfMessagesRemainingOnSourceQueue);
+ assertEquals("Unexpected number of messages after move", numberOfMessagesToSend, numberOfMessagesReadByConsumer + numberOfMessagesOnDestinationQueue + numberOfMessagesRemainingOnSourceQueue);
+ }
+
+ public void testMoveMessagesBetweenQueuesWithActiveConsumerOnDestinationQueue() throws Exception
+ {
+ setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, new Integer(1).toString());
+ Connection asyncConnection = getConnection();
+ asyncConnection.start();
+
+ final int numberOfMessagesToSend = 50;
+ sendMessage(_session, _sourceQueue, numberOfMessagesToSend);
+ syncSession(_session);
+ assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue());
+
+ List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend);
+ long fromMessageId = amqMessagesIds.get(0);
+ long toMessageId = amqMessagesIds.get(numberOfMessagesToSend - 1);
+
+ AtomicInteger totalConsumed = new AtomicInteger(0);
+ CountDownLatch allMessagesConsumedLatch = new CountDownLatch(numberOfMessagesToSend);
+ startAsyncConsumerOn(_destinationQueue, asyncConnection, allMessagesConsumedLatch, totalConsumed);
+
+ _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName);
+
+ allMessagesConsumedLatch.await(5000, TimeUnit.MILLISECONDS);
+ assertEquals("Did not consume all messages from destination queue", numberOfMessagesToSend, totalConsumed.intValue());
+ }
+
+ /**
+ * Tests {@link ManagedQueue#moveMessages(long, long, String)} interface.
+ */
+ public void testMoveMessageBetweenQueuesWithBrokerRestart() throws Exception
+ {
+ final int numberOfMessagesToSend = 1;
+
+ sendMessage(_session, _sourceQueue, numberOfMessagesToSend);
+ syncSession(_session);
+ assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue());
+
+ restartBroker();
+
+ createManagementInterfacesForQueues();
+ createConnectionAndSession();
+
+ List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend);
+
+ // Move messages to destination
+ long messageId = amqMessagesIds.get(0);
+ _managedSourceQueue.moveMessages(messageId, messageId, _destinationQueueName);
+
+ assertEquals("Unexpected queue depth on destination queue after move", 1, _managedDestinationQueue.getMessageCount().intValue());
+ assertEquals("Unexpected queue depth on source queue after move", 0, _managedSourceQueue.getMessageCount().intValue());
+
+ assertMessageIndicesOn(_destinationQueue, 0);
+ }
+
+ /**
+ * Tests {@link ManagedQueue#copyMessages(long, long, String)} interface.
+ */
+ public void testCopyMessageBetweenQueuesWithBrokerRestart() throws Exception
+ {
+ final int numberOfMessagesToSend = 1;
+
+ sendMessage(_session, _sourceQueue, numberOfMessagesToSend);
+ syncSession(_session);
+ assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue());
+
+ restartBroker();
+
+ createManagementInterfacesForQueues();
+ createConnectionAndSession();
+
+ List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend);
+
+ // Move messages to destination
+ long messageId = amqMessagesIds.get(0);
+ _managedSourceQueue.copyMessages(messageId, messageId, _destinationQueueName);
+
+ assertEquals("Unexpected queue depth on destination queue after copy", 1, _managedDestinationQueue.getMessageCount().intValue());
+ assertEquals("Unexpected queue depth on source queue after copy", 1, _managedSourceQueue.getMessageCount().intValue());
+
+ assertMessageIndicesOn(_destinationQueue, 0);
+ }
+
+ @Override
+ public Message createNextMessage(Session session, int messageNumber) throws JMSException
+ {
+ Message message = session.createTextMessage(getContentForMessageNumber(messageNumber));
+ message.setIntProperty(INDEX, messageNumber);
+ return message;
+ }
+
+ private void startAsyncConsumerOn(Destination queue, Connection asyncConnection,
+ final CountDownLatch requiredNumberOfMessagesRead, final AtomicInteger totalConsumed) throws Exception
+ {
+ Session session = asyncConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ MessageConsumer consumer = session.createConsumer(queue);
+ consumer.setMessageListener(new MessageListener()
+ {
+
+ @Override
+ public void onMessage(Message arg0)
+ {
+ totalConsumed.incrementAndGet();
+ requiredNumberOfMessagesRead.countDown();
+ }
+ });
+ }
+
+ private void assertMessageIndicesOn(Destination queue, int... expectedIndices) throws Exception
+ {
+ MessageConsumer consumer = _session.createConsumer(queue);
+
+ for (int i : expectedIndices)
+ {
+ TextMessage message = (TextMessage)consumer.receive(1000);
+ assertNotNull("Expected message with index " + i, message);
+ assertEquals("Expected message with index " + i, i, message.getIntProperty(INDEX));
+ assertEquals("Expected message content", getContentForMessageNumber(i), message.getText());
+ }
+
+ assertNull("Unexpected message encountered", consumer.receive(1000));
+ }
+
+ private List<Long> getAMQMessageIdsOn(ManagedQueue managedQueue, long startIndex, long endIndex) throws Exception
+ {
+ final SortedSet<Long> messageIds = new TreeSet<Long>();
+
+ final TabularData tab = managedQueue.viewMessages(startIndex, endIndex);
+ final Iterator<CompositeData> rowItr = (Iterator<CompositeData>) tab.values().iterator();
+ while(rowItr.hasNext())
+ {
+ final CompositeData row = rowItr.next();
+ long amqMessageId = (Long)row.get(ManagedQueue.MSG_AMQ_ID);
+ messageIds.add(amqMessageId);
+ }
+
+ return new ArrayList<Long>(messageIds);
+ }
+
+ /**
+ *
+ * Utility method to convert array of Strings in the form x = y into a
+ * map with key/value x =&gt; y.
+ *
+ */
+ private Map<String,String> headerArrayToMap(final String[] headerArray)
+ {
+ final Map<String, String> headerMap = new HashMap<String, String>();
+ final List<String> headerList = Arrays.asList(headerArray);
+ for (Iterator<String> iterator = headerList.iterator(); iterator.hasNext();)
+ {
+ final String nameValuePair = iterator.next();
+ final String[] nameValue = nameValuePair.split(" *= *", 2);
+ headerMap.put(nameValue[0], nameValue[1]);
+ }
+ return headerMap;
+ }
+
+ private void createQueueOnBroker(Destination destination) throws JMSException
+ {
+ _session.createConsumer(destination).close(); // Create a consumer only to cause queue creation
+ }
+
+ private void syncSession(Session session) throws Exception
+ {
+ ((AMQSession<?,?>)session).sync();
+ }
+
+ private void createConnectionAndSession() throws JMSException,
+ NamingException
+ {
+ _connection = getConnection();
+ _connection.start();
+ _session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ }
+
+ private void createManagementInterfacesForQueues()
+ {
+ _managedSourceQueue = _jmxUtils.getManagedQueue(_sourceQueueName);
+ _managedDestinationQueue = _jmxUtils.getManagedQueue(_destinationQueueName);
+ }
+
+ private String getContentForMessageNumber(int msgCount)
+ {
+ return "Message count " + msgCount;
+ }
+
+ private final class RecordingNotificationListener implements NotificationListener
+ {
+ private final CountDownLatch _notificationReceivedLatch;
+ private final AtomicInteger _numberOfNotifications;
+ private final AtomicReference<Notification> _lastNotification;
+
+ private RecordingNotificationListener(int expectedNumberOfNotifications)
+ {
+ _notificationReceivedLatch = new CountDownLatch(expectedNumberOfNotifications);
+ _numberOfNotifications = new AtomicInteger(0);
+ _lastNotification = new AtomicReference<Notification>();
+ }
+
+ @Override
+ public void handleNotification(Notification notification, Object handback)
+ {
+ _lastNotification.set(notification);
+ _numberOfNotifications.incrementAndGet();
+ _notificationReceivedLatch.countDown();
+ }
+
+ public int getNumberOfNotificationsReceived()
+ {
+ return _numberOfNotifications.get();
+ }
+
+ public Notification getLastNotification()
+ {
+ return _lastNotification.get();
+ }
+
+ public void awaitExpectedNotifications(long timeout, TimeUnit timeunit) throws InterruptedException
+ {
+ _notificationReceivedLatch.await(timeout, timeunit);
+ }
+ }
+
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java
new file mode 100644
index 0000000000..49207e2d7a
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java
@@ -0,0 +1,210 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.management.jmx;
+
+import java.util.List;
+
+import javax.jms.Connection;
+import javax.jms.MessageConsumer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.management.common.mbeans.ManagedBroker;
+import org.apache.qpid.management.common.mbeans.ManagedConnection;
+import org.apache.qpid.management.common.mbeans.ServerInformation;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+public class StatisticsTest extends QpidBrokerTestCase
+{
+ private static final String TEST_VIRTUALHOST1 = "test1";
+ private static final String TEST_VIRTUALHOST2 = "test2";
+
+ private static final String TEST_USER = "admin";
+ private static final String TEST_PASSWORD = "admin";
+ private static final int MESSAGE_COUNT_TEST = 5;
+ private static final int MESSAGE_COUNT_DEV = 9;
+
+ private JMXTestUtils _jmxUtils;
+ private Connection _vhost1Connection, _vhost2Connection;
+ private Session _vhost1Session, _vhost2Session;
+ private Queue _vhost1Queue, _vhost2Queue;
+ protected String _brokerUrl;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ createTestVirtualHost(TEST_VIRTUALHOST1);
+ createTestVirtualHost(TEST_VIRTUALHOST2);
+
+ _jmxUtils = new JMXTestUtils(this, TEST_USER, TEST_PASSWORD);
+ _jmxUtils.setUp();
+
+ super.setUp();
+
+ _brokerUrl = getBroker().toString();
+ _vhost1Connection = new AMQConnection(_brokerUrl, TEST_USER, TEST_PASSWORD, "clientid", TEST_VIRTUALHOST1);
+ _vhost2Connection = new AMQConnection(_brokerUrl, TEST_USER, TEST_PASSWORD, "clientid", TEST_VIRTUALHOST2);
+ _vhost1Connection.start();
+ _vhost2Connection.start();
+
+ _vhost1Session = _vhost1Connection.createSession(true, Session.SESSION_TRANSACTED);
+ _vhost2Session = _vhost2Connection.createSession(true, Session.SESSION_TRANSACTED);
+
+ _vhost1Queue = _vhost2Session.createQueue(getTestQueueName());
+ _vhost2Queue = _vhost1Session.createQueue(getTestQueueName());
+
+ //Create queues by opening and closing consumers
+ final MessageConsumer vhost1Consumer = _vhost1Session.createConsumer(_vhost2Queue);
+ vhost1Consumer.close();
+ final MessageConsumer vhost2Consumer = _vhost2Session.createConsumer(_vhost1Queue);
+ vhost2Consumer.close();
+
+ _jmxUtils.open();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ _jmxUtils.close();
+
+ super.tearDown();
+ }
+
+ public void testInitialStatisticValues() throws Exception
+ {
+ //Check initial values
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, 0, 0, 0, 0);
+ checkVHostStatistics(TEST_VIRTUALHOST1, 0, 0, 0, 0);
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0);
+ checkVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0);
+ checkBrokerStatistics(0, 0, 0, 0);
+ }
+
+ public void testSendOnSingleVHost() throws Exception
+ {
+ sendMessagesAndSync(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST);
+
+ //Check values
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0);
+ checkVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0);
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0);
+ checkVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0);
+ checkBrokerStatistics(MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0);
+ }
+
+ public void testSendOnTwoVHosts() throws Exception
+ {
+ sendMessagesAndSync(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST);
+ sendMessagesAndSync(_vhost2Session, _vhost1Queue, MESSAGE_COUNT_DEV);
+
+ //Check values
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0);
+ checkVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0);
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, MESSAGE_COUNT_DEV, 0, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, 0);
+ checkVHostStatistics(TEST_VIRTUALHOST2, MESSAGE_COUNT_DEV, 0, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, 0);
+ checkBrokerStatistics(MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV, 0, (MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV) * DEFAULT_MESSAGE_SIZE, 0);
+ }
+
+ public void testSendAndConsumeOnSingleVHost() throws Exception
+ {
+ sendMessagesAndSync(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST);
+ consumeMessages(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST);
+
+ //Check values
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE);
+ checkVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE);
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0);
+ checkVHostStatistics(TEST_VIRTUALHOST2, 0, 0, 0, 0);
+ checkBrokerStatistics(MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE);
+ }
+
+ public void testSendAndConsumeOnTwoVHosts() throws Exception
+ {
+ sendMessagesAndSync(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST);
+ sendMessagesAndSync(_vhost2Session, _vhost1Queue, MESSAGE_COUNT_DEV);
+ consumeMessages(_vhost1Session, _vhost2Queue, MESSAGE_COUNT_TEST);
+ consumeMessages(_vhost2Session, _vhost1Queue, MESSAGE_COUNT_DEV);
+
+ //Check values
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE);
+ checkVHostStatistics(TEST_VIRTUALHOST1, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE);
+ checkSingleConnectionOnVHostStatistics(TEST_VIRTUALHOST2, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE);
+ checkVHostStatistics(TEST_VIRTUALHOST2, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE);
+ checkBrokerStatistics(MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV, MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV, (MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV) * DEFAULT_MESSAGE_SIZE, (MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV) * DEFAULT_MESSAGE_SIZE);
+ }
+
+ private void sendMessagesAndSync(Session session, Queue queue, int numberOfMessages) throws Exception
+ {
+ //Send messages via connection on and sync
+ sendMessage(session, queue, numberOfMessages);
+ ((AMQSession<?,?>)session).sync();
+ }
+
+ private void consumeMessages(Session session, Queue queue, int numberOfMessages) throws Exception
+ {
+ //consume the messages on the virtual host
+ final MessageConsumer consumer = session.createConsumer(queue);
+ for (int i = 0 ; i < numberOfMessages ; i++)
+ {
+ assertNotNull("an expected message was not received", consumer.receive(1500));
+ }
+ session.commit();
+ consumer.close();
+ }
+
+ private void checkSingleConnectionOnVHostStatistics(String vHostName, long messagesSent, long messagesReceived, long dataSent, long dataReceived)
+ {
+ List<ManagedConnection> managedConnections = _jmxUtils.getManagedConnections(vHostName);
+ assertEquals(1, managedConnections.size());
+
+ ManagedConnection managedConnection = managedConnections.get(0);
+
+ assertEquals(messagesSent, managedConnection.getTotalMessagesReceived());
+ assertEquals(messagesReceived, managedConnection.getTotalMessagesDelivered());
+
+ assertEquals(dataSent, managedConnection.getTotalDataReceived());
+ assertEquals(dataReceived, managedConnection.getTotalDataDelivered());
+ }
+
+ private void checkVHostStatistics(String vHostName, long messagesSent, long messagesReceived, long dataSent, long dataReceived)
+ {
+ ManagedBroker vhost = _jmxUtils.getManagedBroker(vHostName);
+
+ assertEquals(messagesSent, vhost.getTotalMessagesReceived());
+ assertEquals(messagesReceived, vhost.getTotalMessagesDelivered());
+
+ assertEquals(dataSent, vhost.getTotalDataReceived());
+ assertEquals(dataReceived, vhost.getTotalDataDelivered());
+ }
+
+ private void checkBrokerStatistics(long messagesSent, long messagesReceived, long dataSent, long dataReceived)
+ {
+ ServerInformation broker = _jmxUtils.getServerInformation();
+
+ assertEquals(messagesSent, broker.getTotalMessagesReceived());
+ assertEquals(messagesReceived, broker.getTotalMessagesDelivered());
+
+ assertEquals(dataSent, broker.getTotalDataReceived());
+ assertEquals(dataReceived, broker.getTotalDataDelivered());
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java
new file mode 100644
index 0000000000..62b1b554a9
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java
@@ -0,0 +1,251 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.systest.management.jmx;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+
+import org.apache.qpid.management.common.mbeans.UserManagement;
+import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase;
+import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
+import org.apache.qpid.test.utils.JMXTestUtils;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+import org.apache.qpid.tools.security.Passwd;
+
+/**
+ * System test for User Management.
+ *
+ */
+public class UserManagementTest extends QpidBrokerTestCase
+{
+ private static final String TEST_NEWPASSWORD = "newpassword";
+ private static final String TEST_PASSWORD = "password";
+ private JMXTestUtils _jmxUtils;
+ private String _testUserName;
+ private File _passwordFile;
+ private UserManagement _userManagement;
+ private Passwd _passwd;
+
+ public void setUp() throws Exception
+ {
+ _passwd = createPasswordEncodingUtility();
+ _passwordFile = createTemporaryPasswordFileWithJmxAdminUser();
+
+ setConfigurationProperty("security.pd-auth-manager.principal-database.class", getPrincipalDatabaseImplClass().getName());
+ setConfigurationProperty("security.pd-auth-manager.principal-database.attributes.attribute.name", "passwordFile");
+ setConfigurationProperty("security.pd-auth-manager.principal-database.attributes.attribute.value", _passwordFile.getAbsolutePath());
+
+ _jmxUtils = new JMXTestUtils(this);
+ _jmxUtils.setUp();
+
+ super.setUp();
+ _jmxUtils.open();
+
+ _testUserName = getTestName() + System.currentTimeMillis();
+
+ _userManagement = _jmxUtils.getUserManagement();
+ }
+
+
+ public void tearDown() throws Exception
+ {
+ try
+ {
+ if (_jmxUtils != null)
+ {
+ _jmxUtils.close();
+ }
+ }
+ finally
+ {
+ super.tearDown();
+ }
+ }
+
+ public void testCreateUser() throws Exception
+ {
+ final int initialNumberOfUsers = _userManagement.viewUsers().size();
+ assertFileDoesNotContainsPasswordForUser(_testUserName);
+
+ boolean success = _userManagement.createUser(_testUserName, TEST_PASSWORD);
+ assertTrue("Should have been able to create new user " + _testUserName, success);
+ assertEquals("Unexpected number of users after add", initialNumberOfUsers + 1, _userManagement.viewUsers().size());
+
+ assertFileContainsPasswordForUser(_testUserName);
+ }
+
+ public void testJmsLoginForNewUser() throws Exception
+ {
+ assertJmsConnectionFails(_testUserName, TEST_PASSWORD);
+ testCreateUser();
+
+ assertJmsConnectionSucceeds(_testUserName, TEST_PASSWORD);
+ }
+
+ public void testDeleteUser() throws Exception
+ {
+ final int initialNumberOfUsers = _userManagement.viewUsers().size();
+
+ testCreateUser();
+
+ boolean success = _userManagement.deleteUser(_testUserName);
+ assertTrue("Should have been able to delete new user " + _testUserName, success);
+ assertEquals("Unexpected number of users after delete", initialNumberOfUsers, _userManagement.viewUsers().size());
+ assertFileDoesNotContainsPasswordForUser(_testUserName);
+ }
+
+ public void testJmsLoginNotPossibleForDeletedUser() throws Exception
+ {
+ testDeleteUser();
+
+ assertJmsConnectionFails(_testUserName, TEST_PASSWORD);
+ }
+
+ public void testSetPassword() throws Exception
+ {
+ testCreateUser();
+
+ _userManagement.setPassword(_testUserName, TEST_NEWPASSWORD);
+
+ assertFileContainsPasswordForUser(_testUserName);
+ }
+
+ public void testJmsLoginForPasswordChangedUser() throws Exception
+ {
+ testSetPassword();
+
+ assertJmsConnectionSucceeds(_testUserName, TEST_NEWPASSWORD);
+ assertJmsConnectionFails(_testUserName, TEST_PASSWORD);
+ }
+
+ public void testReload() throws Exception
+ {
+ writePasswordFile(_passwordFile, JMXTestUtils.DEFAULT_USERID, JMXTestUtils.DEFAULT_PASSWORD, _testUserName, TEST_PASSWORD);
+
+ assertJmsConnectionFails(_testUserName, TEST_PASSWORD);
+
+ _userManagement.reloadData();
+
+ assertJmsConnectionSucceeds(_testUserName, TEST_PASSWORD);
+ }
+
+ protected Passwd createPasswordEncodingUtility()
+ {
+ return new Passwd()
+ {
+ @Override
+ public String getOutput(String username, String password)
+ {
+ return username + ":" + password;
+ }
+ };
+ }
+
+ protected Class<? extends PrincipalDatabase> getPrincipalDatabaseImplClass()
+ {
+ return PlainPasswordFilePrincipalDatabase.class;
+ }
+
+ private File createTemporaryPasswordFileWithJmxAdminUser() throws Exception
+ {
+ File passwordFile = File.createTempFile("passwd", "pwd");
+ passwordFile.deleteOnExit();
+ writePasswordFile(passwordFile, JMXTestUtils.DEFAULT_USERID, JMXTestUtils.DEFAULT_PASSWORD);
+ return passwordFile;
+ }
+
+ private void writePasswordFile(File passwordFile, String... userNamePasswordPairs) throws Exception
+ {
+ FileWriter writer = null;
+ try
+ {
+ writer = new FileWriter(passwordFile);
+ for (int i = 0; i < userNamePasswordPairs.length; i=i+2)
+ {
+ String username = userNamePasswordPairs[i];
+ String password = userNamePasswordPairs[i+1];
+ writer.append(_passwd.getOutput(username, password) + "\n");
+ }
+ }
+ finally
+ {
+ writer.close();
+ }
+ }
+
+
+ private void assertFileContainsPasswordForUser(String username) throws IOException
+ {
+ assertTrue("Could not find password for user " + username + " within " + _passwordFile, passwordFileContainsUser(username));
+ }
+
+ private void assertFileDoesNotContainsPasswordForUser(String username) throws IOException
+ {
+ assertFalse("Could not find password for user " + username + " within " + _passwordFile, passwordFileContainsUser(username));
+ }
+
+ private boolean passwordFileContainsUser(String username) throws IOException
+ {
+ BufferedReader reader = null;
+ try
+ {
+ reader = new BufferedReader(new FileReader(_passwordFile));
+ String line = reader.readLine();
+ while(line != null)
+ {
+ if (line.startsWith(username))
+ {
+ return true;
+ }
+ line = reader.readLine();
+ }
+
+ return false;
+ }
+ finally
+ {
+ reader.close();
+ }
+ }
+
+ private void assertJmsConnectionSucceeds(String username, String password) throws Exception
+ {
+ Connection connection = getConnection(username, password);
+ assertNotNull(connection);
+ }
+
+ private void assertJmsConnectionFails(String username, String password) throws Exception
+ {
+ try
+ {
+ getConnection(username, password);
+ fail("Exception not thrown");
+ }
+ catch (JMSException e)
+ {
+ // PASS
+ }
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java
new file mode 100644
index 0000000000..84a66232ce
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.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.systest.management.jmx;
+
+import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrincipalDatabase;
+import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
+import org.apache.qpid.tools.security.Passwd;
+
+public class UserManagementWithBase64MD5PasswordsTest extends UserManagementTest
+{
+ @Override
+ protected Passwd createPasswordEncodingUtility()
+ {
+ return new Passwd();
+ }
+
+ @Override
+ protected Class<? extends PrincipalDatabase> getPrincipalDatabaseImplClass()
+ {
+ return Base64MD5PasswordFilePrincipalDatabase.class;
+ }
+
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/Asserts.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/Asserts.java
new file mode 100644
index 0000000000..2991ba7890
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/Asserts.java
@@ -0,0 +1,249 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.rest;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.server.model.Binding;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.Connection;
+import org.apache.qpid.server.model.Exchange;
+import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Queue;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.VirtualHost;
+
+public class Asserts
+{
+ public static final String STATISTICS_ATTRIBUTE = "statistics";
+
+ public static void assertVirtualHost(String virtualHostName, Map<String, Object> virtualHost)
+ {
+ assertNotNull("Virtualhost " + virtualHostName + " data are not found", virtualHost);
+ assertAttributesPresent(virtualHost, VirtualHost.AVAILABLE_ATTRIBUTES, VirtualHost.TIME_TO_LIVE,
+ VirtualHost.CREATED, VirtualHost.UPDATED, VirtualHost.SUPPORTED_QUEUE_TYPES, VirtualHost.STORE_CONFIGURATION);
+
+ assertEquals("Unexpected value of attribute " + VirtualHost.NAME, virtualHostName, virtualHost.get(VirtualHost.NAME));
+ assertNotNull("Unexpected value of attribute " + VirtualHost.ID, virtualHost.get(VirtualHost.ID));
+ assertEquals("Unexpected value of attribute " + VirtualHost.STATE, State.ACTIVE.name(),
+ virtualHost.get(VirtualHost.STATE));
+ assertEquals("Unexpected value of attribute " + VirtualHost.DURABLE, Boolean.TRUE,
+ virtualHost.get(VirtualHost.DURABLE));
+ assertEquals("Unexpected value of attribute " + VirtualHost.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(),
+ virtualHost.get(VirtualHost.LIFETIME_POLICY));
+ assertEquals("Unexpected value of attribute " + VirtualHost.DEAD_LETTER_QUEUE_ENABLED, Boolean.FALSE,
+ virtualHost.get(VirtualHost.DEAD_LETTER_QUEUE_ENABLED));
+
+ @SuppressWarnings("unchecked")
+ Collection<String> exchangeTypes = (Collection<String>) virtualHost.get(VirtualHost.SUPPORTED_EXCHANGE_TYPES);
+ assertEquals("Unexpected value of attribute " + VirtualHost.SUPPORTED_EXCHANGE_TYPES,
+ new HashSet<String>(Arrays.asList("headers", "topic", "direct", "fanout")),
+ new HashSet<String>(exchangeTypes));
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) virtualHost.get(STATISTICS_ATTRIBUTE);
+ Asserts.assertAttributesPresent(statistics, VirtualHost.AVAILABLE_STATISTICS, VirtualHost.BYTES_RETAINED,
+ VirtualHost.LOCAL_TRANSACTION_BEGINS, VirtualHost.LOCAL_TRANSACTION_ROLLBACKS,
+ VirtualHost.MESSAGES_RETAINED, VirtualHost.STATE_CHANGED, VirtualHost.XA_TRANSACTION_BRANCH_ENDS,
+ VirtualHost.XA_TRANSACTION_BRANCH_STARTS, VirtualHost.XA_TRANSACTION_BRANCH_SUSPENDS);
+
+ }
+
+ public static void assertQueue(String queueName, String queueType, Map<String, Object> queueData)
+ {
+ assertQueue(queueName, queueType, queueData, null);
+ }
+
+ public static void assertQueue(String queueName, String queueType, Map<String, Object> queueData, Map<String, Object> expectedAttributes)
+ {
+ assertNotNull("Queue " + queueName + " is not found!", queueData);
+ Asserts.assertAttributesPresent(queueData, Queue.AVAILABLE_ATTRIBUTES, Queue.CREATED, Queue.UPDATED,
+ Queue.DESCRIPTION, Queue.TIME_TO_LIVE, Queue.ALTERNATE_EXCHANGE, Queue.OWNER, Queue.NO_LOCAL, Queue.LVQ_KEY,
+ Queue.SORT_KEY, Queue.MESSAGE_GROUP_KEY, Queue.MESSAGE_GROUP_DEFAULT_GROUP,
+ Queue.MESSAGE_GROUP_SHARED_GROUPS, Queue.PRIORITIES);
+
+ assertEquals("Unexpected value of queue attribute " + Queue.NAME, queueName, queueData.get(Queue.NAME));
+ assertNotNull("Unexpected value of queue attribute " + Queue.ID, queueData.get(Queue.ID));
+ assertEquals("Unexpected value of queue attribute " + Queue.STATE, State.ACTIVE.name(), queueData.get(Queue.STATE));
+ assertEquals("Unexpected value of queue attribute " + Queue.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(),
+ queueData.get(Queue.LIFETIME_POLICY));
+ assertEquals("Unexpected value of queue attribute " + Queue.TYPE, queueType, queueData.get(Queue.TYPE));
+ if (expectedAttributes == null)
+ {
+ assertEquals("Unexpected value of queue attribute " + Queue.EXCLUSIVE, Boolean.FALSE, queueData.get(Queue.EXCLUSIVE));
+ assertEquals("Unexpected value of queue attribute " + Queue.MAXIMUM_DELIVERY_ATTEMPTS, 0,
+ queueData.get(Queue.MAXIMUM_DELIVERY_ATTEMPTS));
+ assertEquals("Unexpected value of queue attribute " + Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 0,
+ queueData.get(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES));
+ assertEquals("Unexpected value of queue attribute " + Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 0,
+ queueData.get(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES));
+ assertEquals("Unexpected value of queue attribute " + Queue.QUEUE_FLOW_STOPPED, Boolean.FALSE,
+ queueData.get(Queue.QUEUE_FLOW_STOPPED));
+ }
+ else
+ {
+ for (Map.Entry<String, Object> attribute : expectedAttributes.entrySet())
+ {
+ assertEquals("Unexpected value of " + queueName + " queue attribute " + attribute.getKey(),
+ attribute.getValue(), queueData.get(attribute.getKey()));
+ }
+ }
+
+ assertNotNull("Unexpected value of queue attribute statistics", queueData.get(Asserts.STATISTICS_ATTRIBUTE));
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) queueData.get(Asserts.STATISTICS_ATTRIBUTE);
+ Asserts.assertAttributesPresent(statistics, Queue.AVAILABLE_STATISTICS, Queue.DISCARDS_TTL_BYTES,
+ Queue.DISCARDS_TTL_MESSAGES, Queue.STATE_CHANGED);
+ }
+
+ public static void assertAttributesPresent(Map<String, Object> data, String[] attributes)
+ {
+ for (String name : attributes)
+ {
+ assertNotNull("Attribute " + name + " is not present", data.get(name));
+ }
+ }
+
+ public static void assertAttributesPresent(Map<String, Object> data, Collection<String> attributes,
+ String... unsupportedAttributes)
+ {
+ for (String name : attributes)
+ {
+ boolean unsupported = false;
+ for (String unsupportedAttribute : unsupportedAttributes)
+ {
+ if (unsupportedAttribute.equals(name))
+ {
+ unsupported = true;
+ break;
+ }
+ }
+ if (unsupported)
+ {
+ continue;
+ }
+ assertNotNull("Attribute " + name + " is not present", data.get(name));
+ }
+ }
+
+ public static void assertConnection(Map<String, Object> connectionData, AMQConnection connection) throws JMSException
+ {
+ assertNotNull("Unexpected connection data", connectionData);
+ assertAttributesPresent(connectionData, Connection.AVAILABLE_ATTRIBUTES, Connection.STATE, Connection.DURABLE,
+ Connection.LIFETIME_POLICY, Connection.TIME_TO_LIVE, Connection.CREATED, Connection.UPDATED,
+ Connection.INCOMING, Connection.REMOTE_PROCESS_NAME, Connection.REMOTE_PROCESS_PID,
+ Connection.LOCAL_ADDRESS, Connection.PROPERTIES);
+
+ assertEquals("Unexpected value of connection attribute " + Connection.SESSION_COUNT_LIMIT,
+ (int) connection.getMaximumChannelCount(), connectionData.get(Connection.SESSION_COUNT_LIMIT));
+ assertEquals("Unexpected value of connection attribute " + Connection.CLIENT_ID, "clientid",
+ connectionData.get(Connection.CLIENT_ID));
+ assertEquals("Unexpected value of connection attribute " + Connection.PRINCIPAL, "guest",
+ connectionData.get(Connection.PRINCIPAL));
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) connectionData.get(STATISTICS_ATTRIBUTE);
+ assertAttributesPresent(statistics, Connection.AVAILABLE_STATISTICS, Connection.LOCAL_TRANSACTION_BEGINS,
+ Connection.LOCAL_TRANSACTION_ROLLBACKS, Connection.STATE_CHANGED, Connection.XA_TRANSACTION_BRANCH_ENDS,
+ Connection.XA_TRANSACTION_BRANCH_STARTS, Connection.XA_TRANSACTION_BRANCH_SUSPENDS);
+ assertEquals("Unexpected value of connection statistics attribute " + Connection.SESSION_COUNT, 1,
+ statistics.get(Connection.SESSION_COUNT));
+ }
+
+ public static void assertPortAttributes(Map<String, Object> port)
+ {
+ assertAttributesPresent(port, Port.AVAILABLE_ATTRIBUTES, Port.CREATED, Port.UPDATED);
+
+ assertNotNull("Unexpected value of attribute " + Port.ID, port.get(Port.ID));
+ assertEquals("Unexpected value of attribute " + Port.DURABLE, Boolean.FALSE, port.get(Port.DURABLE));
+ assertEquals("Unexpected value of attribute " + Port.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(),
+ port.get(Broker.LIFETIME_POLICY));
+ assertEquals("Unexpected value of attribute " + Port.STATE, State.ACTIVE.name(), port.get(Port.STATE));
+ assertEquals("Unexpected value of attribute " + Port.TIME_TO_LIVE, 0, port.get(Port.TIME_TO_LIVE));
+ assertNotNull("Unexpected value of attribute " + Port.BINDING_ADDRESS, port.get(Port.BINDING_ADDRESS));
+ assertNotNull("Unexpected value of attribute " + Port.PROTOCOLS, port.get(Port.PROTOCOLS));
+ assertNotNull("Unexpected value of attribute " + Port.NAME, port.get(Port.NAME));
+
+ @SuppressWarnings("unchecked")
+ Collection<String> transports = (Collection<String>) port.get(Port.TRANSPORTS);
+ assertEquals("Unexpected value of attribute " + Port.TRANSPORTS, new HashSet<String>(Arrays.asList("TCP")),
+ new HashSet<String>(transports));
+ }
+
+ public static void assertDurableExchange(String exchangeName, String type, Map<String, Object> exchangeData)
+ {
+ assertExchange(exchangeName, type, exchangeData);
+
+ assertEquals("Unexpected value of exchange attribute " + Exchange.DURABLE, Boolean.TRUE,
+ exchangeData.get(Exchange.DURABLE));
+ }
+
+ public static void assertExchange(String exchangeName, String type, Map<String, Object> exchangeData)
+ {
+ assertNotNull("Exchange " + exchangeName + " is not found!", exchangeData);
+ assertAttributesPresent(exchangeData, Exchange.AVAILABLE_ATTRIBUTES, Exchange.CREATED, Exchange.UPDATED,
+ Exchange.ALTERNATE_EXCHANGE, Exchange.TIME_TO_LIVE);
+
+ assertEquals("Unexpected value of exchange attribute " + Exchange.NAME, exchangeName,
+ exchangeData.get(Exchange.NAME));
+ assertNotNull("Unexpected value of exchange attribute " + Exchange.ID, exchangeData.get(VirtualHost.ID));
+ assertEquals("Unexpected value of exchange attribute " + Exchange.STATE, State.ACTIVE.name(),
+ exchangeData.get(Exchange.STATE));
+
+ assertEquals("Unexpected value of exchange attribute " + Exchange.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(),
+ exchangeData.get(Exchange.LIFETIME_POLICY));
+ assertEquals("Unexpected value of exchange attribute " + Exchange.TYPE, type, exchangeData.get(Exchange.TYPE));
+ assertNotNull("Unexpected value of exchange attribute statistics", exchangeData.get(STATISTICS_ATTRIBUTE));
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) exchangeData.get(STATISTICS_ATTRIBUTE);
+ assertAttributesPresent(statistics, Exchange.AVAILABLE_STATISTICS, Exchange.STATE_CHANGED, Exchange.PRODUCER_COUNT);
+ }
+
+ public static void assertBinding(String bindingName, String queueName, String exchange, Map<String, Object> binding)
+ {
+ assertNotNull("Binding map should not be null", binding);
+ assertAttributesPresent(binding, Binding.AVAILABLE_ATTRIBUTES, Binding.STATE, Binding.TIME_TO_LIVE,
+ Binding.CREATED, Binding.UPDATED);
+
+ assertEquals("Unexpected binding attribute " + Binding.NAME, bindingName, binding.get(Binding.NAME));
+ assertEquals("Unexpected binding attribute " + Binding.QUEUE, queueName, binding.get(Binding.QUEUE));
+ assertEquals("Unexpected binding attribute " + Binding.EXCHANGE, exchange, binding.get(Binding.EXCHANGE));
+ assertEquals("Unexpected binding attribute " + Binding.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(),
+ binding.get(Binding.LIFETIME_POLICY));
+ }
+
+ public static void assertBinding(String queueName, String exchange, Map<String, Object> binding)
+ {
+ assertBinding(queueName, queueName, exchange, binding);
+ }
+
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java
new file mode 100644
index 0000000000..a171b4459b
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java
@@ -0,0 +1,73 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.rest;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.User;
+
+public class AuthenticationProviderRestTest extends QpidRestTestCase
+{
+
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> providerDetails = getRestTestHelper().getJsonAsList("/rest/authenticationprovider");
+ assertNotNull("Providers details cannot be null", providerDetails);
+ assertEquals("Unexpected number of providers", 1, providerDetails.size());
+ for (Map<String, Object> provider : providerDetails)
+ {
+ assertProvider("PrincipalDatabaseAuthenticationManager", provider);
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("/rest/authenticationprovider/"
+ + provider.get(AuthenticationProvider.NAME));
+ assertNotNull("Cannot load data for " + provider.get(AuthenticationProvider.NAME), data);
+ assertProvider("PrincipalDatabaseAuthenticationManager", data);
+ }
+ }
+
+ private void assertProvider(String type, Map<String, Object> provider)
+ {
+ Asserts.assertAttributesPresent(provider, AuthenticationProvider.AVAILABLE_ATTRIBUTES,
+ AuthenticationProvider.CREATED, AuthenticationProvider.UPDATED, AuthenticationProvider.DESCRIPTION,
+ AuthenticationProvider.TIME_TO_LIVE);
+ assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.STATE, State.ACTIVE.name(),
+ provider.get(AuthenticationProvider.STATE));
+ assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.LIFETIME_POLICY,
+ LifetimePolicy.PERMANENT.name(), provider.get(AuthenticationProvider.LIFETIME_POLICY));
+ assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.DURABLE, Boolean.TRUE,
+ provider.get(AuthenticationProvider.DURABLE));
+ assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.TYPE, type,
+ provider.get(AuthenticationProvider.TYPE));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> users = (List<Map<String, Object>>) provider.get("users");
+ assertNotNull("Users are not found", users);
+ assertTrue("Unexpected number of users", users.size() > 1);
+ for (Map<String, Object> user : users)
+ {
+ assertNotNull("Attribute " + User.ID, user.get(User.ID));
+ assertNotNull("Attribute " + User.NAME, user.get(User.NAME));
+ }
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java
new file mode 100644
index 0000000000..74b773c1fa
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java
@@ -0,0 +1,116 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.rest;
+
+import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE;
+import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.configuration.ConfigurationException;
+
+public class BasicAuthRestTest extends QpidRestTestCase
+{
+ private static final String USERNAME = "admin";
+
+ @Override
+ public void setUp() throws Exception
+ {
+ setSystemProperty("javax.net.debug", "ssl");
+
+ //don't call super method, we will configure the broker in the test before doing so
+ }
+
+ @Override
+ protected void customizeConfiguration() throws ConfigurationException, IOException
+ {
+ //do nothing, we will configure this locally
+ }
+
+ private void configure(boolean useSsl) throws ConfigurationException, IOException
+ {
+ getRestTestHelper().setUseSsl(useSsl);
+ setConfigurationProperty("management.http.enabled", String.valueOf(!useSsl));
+ setConfigurationProperty("management.http.port", Integer.toString(getRestTestHelper().getHttpPort()));
+ setConfigurationProperty("management.https.enabled", String.valueOf(useSsl));
+ setConfigurationProperty("management.https.port", Integer.toString(getRestTestHelper().getHttpPort()));
+ setConfigurationProperty("management.enabled", "false"); //JMX
+ }
+
+ private void verifyGetBrokerAttempt(int responseCode) throws IOException
+ {
+ HttpURLConnection conn = getRestTestHelper().openManagementConnection("/rest/broker", "GET");
+ assertEquals(responseCode, conn.getResponseCode());
+ }
+
+ public void testDefaultEnabledWithHttps() throws Exception
+ {
+ configure(true);
+ super.setUp();
+ setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE);
+ setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD);
+
+ // Try the attempt with authentication, it should succeed because
+ // BASIC auth is enabled by default on secure connections.
+ getRestTestHelper().setUsernameAndPassword(USERNAME, USERNAME);
+ verifyGetBrokerAttempt(HttpServletResponse.SC_OK);
+ }
+
+ public void testDefaultDisabledWithHttp() throws Exception
+ {
+ configure(false);
+ super.setUp();
+
+ // Try the attempt with authentication, it should fail because
+ // BASIC auth is disabled by default on non-secure connections.
+ getRestTestHelper().setUsernameAndPassword(USERNAME, USERNAME);
+ verifyGetBrokerAttempt(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+
+ public void testEnablingForHttp() throws Exception
+ {
+ configure(false);
+ setConfigurationProperty("management.http.basic-auth", "true");
+ super.setUp();
+
+ // Try the attempt with authentication, it should succeed because
+ // BASIC auth is now enabled on non-secure connections.
+ getRestTestHelper().setUsernameAndPassword(USERNAME, USERNAME);
+ verifyGetBrokerAttempt(HttpServletResponse.SC_OK);
+ }
+
+ public void testDisablingForHttps() throws Exception
+ {
+ configure(true);
+ setConfigurationProperty("management.https.basic-auth", "false");
+ super.setUp();
+ setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE);
+ setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD);
+
+ // Try the attempt with authentication, it should fail because
+ // BASIC auth is now disabled on secure connections.
+ getRestTestHelper().setUsernameAndPassword(USERNAME, USERNAME);
+ verifyGetBrokerAttempt(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BindingRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BindingRestTest.java
new file mode 100644
index 0000000000..7daac0eb46
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BindingRestTest.java
@@ -0,0 +1,129 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.rest;
+
+import java.net.HttpURLConnection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.model.Binding;
+
+public class BindingRestTest extends QpidRestTestCase
+{
+
+ public void testGetAllBindings() throws Exception
+ {
+ List<Map<String, Object>> bindings = getRestTestHelper().getJsonAsList("/rest/binding");
+ assertNotNull("Bindings cannot be null", bindings);
+ assertTrue("Unexpected number of bindings", bindings.size() >= EXPECTED_VIRTUALHOSTS.length * EXPECTED_QUEUES.length);
+ for (Map<String, Object> binding : bindings)
+ {
+ Asserts.assertBinding((String) binding.get(Binding.NAME), (String) binding.get(Binding.EXCHANGE), binding);
+ }
+ }
+
+ public void testGetVirtualHostBindings() throws Exception
+ {
+ List<Map<String, Object>> bindings = getRestTestHelper().getJsonAsList("/rest/binding/test");
+ assertNotNull("Bindings cannot be null", bindings);
+ assertEquals("Unexpected number of bindings", EXPECTED_QUEUES.length * 2, bindings.size());
+ for (String queueName : EXPECTED_QUEUES)
+ {
+ Map<String, Object> searchAttributes = new HashMap<String, Object>();
+ searchAttributes.put(Binding.NAME, queueName);
+ searchAttributes.put(Binding.EXCHANGE, "amq.direct");
+
+ Map<String, Object> binding = getRestTestHelper().find(searchAttributes, bindings);
+ Asserts.assertBinding(queueName, "amq.direct", binding);
+
+ searchAttributes.put(Binding.EXCHANGE, "<<default>>");
+
+ binding = getRestTestHelper().find(searchAttributes, bindings);
+ Asserts.assertBinding(queueName, "<<default>>", binding);
+ }
+ }
+
+ public void testGetVirtualHostExchangeBindings() throws Exception
+ {
+ List<Map<String, Object>> bindings = getRestTestHelper().getJsonAsList("/rest/binding/test/amq.direct");
+ assertNotNull("Bindings cannot be null", bindings);
+ assertEquals("Unexpected number of bindings", EXPECTED_QUEUES.length, bindings.size());
+ for (String queueName : EXPECTED_QUEUES)
+ {
+ Map<String, Object> binding = getRestTestHelper().find(Binding.NAME, queueName, bindings);
+ Asserts.assertBinding(queueName, "amq.direct", binding);
+ }
+ }
+
+ public void testGetVirtualHostExchangeQueueBindings() throws Exception
+ {
+ List<Map<String, Object>> bindings = getRestTestHelper().getJsonAsList("/rest/binding/test/amq.direct/queue");
+ assertNotNull("Bindings cannot be null", bindings);
+ assertEquals("Unexpected number of bindings", 1, bindings.size());
+ Asserts.assertBinding("queue", "amq.direct", bindings.get(0));
+ }
+
+
+ public void testDeleteBinding() throws Exception
+ {
+ List<Map<String, Object>> bindings = getRestTestHelper().getJsonAsList("/rest/binding/test/amq.direct/queue/queue");
+ assertEquals("Unexpected number of bindings", 1, bindings.size());
+ Asserts.assertBinding("queue", "amq.direct", bindings.get(0));
+
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/binding/test/amq.direct/queue/queue", "DELETE");
+ connection.connect();
+ assertEquals("Unexpected response code", 200, connection.getResponseCode());
+
+ bindings = getRestTestHelper().getJsonAsList("/rest/binding/test/amq.direct/queue/queue");
+ assertEquals("Binding should be deleted", 0, bindings.size());
+ }
+
+ public void testDeleteBindingById() throws Exception
+ {
+ Map<String, Object> binding = getRestTestHelper().getJsonAsSingletonList("/rest/binding/test/amq.direct/queue");
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/binding/test/amq.direct?id=" + binding.get(Binding.ID), "DELETE");
+ connection.connect();
+ assertEquals("Unexpected response code", 200, connection.getResponseCode());
+ List<Map<String, Object>> bindings = getRestTestHelper().getJsonAsList("/rest/binding/test/amq.direct/queue");
+ assertEquals("Binding should be deleted", 0, bindings.size());
+ }
+
+ public void testCreateBinding() throws Exception
+ {
+ String bindingName = getTestName();
+ Map<String, Object> bindingData = new HashMap<String, Object>();
+ bindingData.put(Binding.NAME, bindingName);
+ bindingData.put(Binding.QUEUE, "queue");
+ bindingData.put(Binding.EXCHANGE, "amq.direct");
+
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/binding/test/amq.direct/queue/" + bindingName, "PUT");
+ connection.connect();
+ getRestTestHelper().writeJsonRequest(connection, bindingData);
+ int responseCode = connection.getResponseCode();
+ connection.disconnect();
+ assertEquals("Unexpected response code", 201, responseCode);
+ Map<String, Object> binding = getRestTestHelper().getJsonAsSingletonList("/rest/binding/test/amq.direct/queue/" + bindingName);
+
+ Asserts.assertBinding(bindingName, "queue", "amq.direct", binding);
+ }
+
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java
new file mode 100644
index 0000000000..c25f160ec8
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.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.systest.rest;
+
+import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE;
+import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.server.model.Broker;
+
+public class BrokerRestHttpsTest extends QpidRestTestCase
+{
+ @Override
+ public void setUp() throws Exception
+ {
+ setSystemProperty("javax.net.debug", "ssl");
+ super.setUp();
+ setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE);
+ setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD);
+ }
+
+ @Override
+ protected void customizeConfiguration() throws ConfigurationException, IOException
+ {
+ getRestTestHelper().setUseSsl(true);
+ setConfigurationProperty("management.enabled", "true");
+ setConfigurationProperty("management.http.enabled", "false");
+ setConfigurationProperty("management.https.enabled", "true");
+ setConfigurationProperty("management.https.port", Integer.toString(getRestTestHelper().getHttpPort()));
+ }
+
+ public void testGetWithHttps() throws Exception
+ {
+ Map<String, Object> brokerDetails = getRestTestHelper().getJsonAsSingletonList("/rest/broker");
+
+ Asserts.assertAttributesPresent(brokerDetails, Broker.AVAILABLE_ATTRIBUTES, Broker.BYTES_RETAINED,
+ Broker.PROCESS_PID, Broker.SUPPORTED_STORE_TYPES, Broker.CREATED, Broker.TIME_TO_LIVE, Broker.UPDATED);
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestTest.java
new file mode 100644
index 0000000000..e5b4ffb297
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestTest.java
@@ -0,0 +1,118 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.rest;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.common.QpidProperties;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.VirtualHost;
+
+public class BrokerRestTest extends QpidRestTestCase
+{
+
+ private static final String BROKER_AUTHENTICATIONPROVIDERS_ATTRIBUTE = "authenticationproviders";
+ private static final String BROKER_PORTS_ATTRIBUTE = "ports";
+ private static final String BROKER_VIRTUALHOSTS_ATTRIBUTE = "virtualhosts";
+ private static final String BROKER_STATISTICS_ATTRIBUTE = "statistics";
+
+ public void testGet() throws Exception
+ {
+ Map<String, Object> brokerDetails = getRestTestHelper().getJsonAsSingletonList("/rest/broker");
+
+ assertBrokerAttributes(brokerDetails);
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) brokerDetails.get(BROKER_STATISTICS_ATTRIBUTE);
+ Asserts.assertAttributesPresent(statistics, new String[]{ "bytesIn", "messagesOut", "bytesOut", "messagesIn" });
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> virtualhosts = (List<Map<String, Object>>) brokerDetails.get(BROKER_VIRTUALHOSTS_ATTRIBUTE);
+ assertEquals("Unexpected number of virtual hosts", 3, virtualhosts.size());
+
+ Asserts.assertVirtualHost(TEST3_VIRTUALHOST, getRestTestHelper().find(VirtualHost.NAME, TEST3_VIRTUALHOST, virtualhosts));
+ Asserts.assertVirtualHost(TEST2_VIRTUALHOST, getRestTestHelper().find(VirtualHost.NAME, TEST2_VIRTUALHOST, virtualhosts));
+ Asserts.assertVirtualHost(TEST1_VIRTUALHOST, getRestTestHelper().find(VirtualHost.NAME, TEST1_VIRTUALHOST, virtualhosts));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> ports = (List<Map<String, Object>>) brokerDetails.get(BROKER_PORTS_ATTRIBUTE);
+ assertEquals("Unexpected number of ports", 2, ports.size());
+
+ for (Map<String, Object> port : ports)
+ {
+ Asserts.assertPortAttributes(port);
+ }
+
+ String bindingAddress = (String)ports.get(0).get(Port.BINDING_ADDRESS);
+
+ Map<String, Object> amqpPort = getRestTestHelper().find(Port.NAME, bindingAddress + ":" + getPort(), ports);
+ Map<String, Object> httpPort = getRestTestHelper().find(Port.NAME, bindingAddress + ":" + getRestTestHelper().getHttpPort(), ports);
+
+ assertNotNull("Cannot find AMQP port", amqpPort);
+ assertNotNull("Cannot find HTTP port", httpPort);
+
+ @SuppressWarnings("unchecked")
+ Collection<String> port1Protocols = (Collection<String>) amqpPort.get(Port.PROTOCOLS);
+ assertFalse("AMQP protocol list cannot contain HTTP", port1Protocols.contains("HTTP"));
+
+ @SuppressWarnings("unchecked")
+ Collection<String> port2Protocols = (Collection<String>) httpPort.get(Port.PROTOCOLS);
+ assertEquals("Unexpected value of attribute " + Port.PROTOCOLS, new HashSet<String>(Arrays.asList("HTTP")),
+ new HashSet<String>(port2Protocols));
+ }
+
+ protected void assertBrokerAttributes(Map<String, Object> brokerDetails)
+ {
+ Asserts.assertAttributesPresent(brokerDetails, Broker.AVAILABLE_ATTRIBUTES,
+ Broker.BYTES_RETAINED, Broker.PROCESS_PID, Broker.SUPPORTED_STORE_TYPES,
+ Broker.CREATED, Broker.TIME_TO_LIVE, Broker.UPDATED);
+
+ assertEquals("Unexpected value of attribute " + Broker.BUILD_VERSION, QpidProperties.getBuildVersion(),
+ brokerDetails.get(Broker.BUILD_VERSION));
+ assertEquals("Unexpected value of attribute " + Broker.OPERATING_SYSTEM, System.getProperty("os.name") + " "
+ + System.getProperty("os.version") + " " + System.getProperty("os.arch"),
+ brokerDetails.get(Broker.OPERATING_SYSTEM));
+ assertEquals(
+ "Unexpected value of attribute " + Broker.PLATFORM,
+ System.getProperty("java.vendor") + " "
+ + System.getProperty("java.runtime.version", System.getProperty("java.version")),
+ brokerDetails.get(Broker.PLATFORM));
+ assertEquals("Unexpected value of attribute " + Broker.DURABLE, Boolean.TRUE, brokerDetails.get(Broker.DURABLE));
+ assertEquals("Unexpected value of attribute " + Broker.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(),
+ brokerDetails.get(Broker.LIFETIME_POLICY));
+ assertEquals("Unexpected value of attribute " + Broker.NAME, "Broker", brokerDetails.get(Broker.NAME));
+ assertEquals("Unexpected value of attribute " + Broker.STATE, State.ACTIVE.name(), brokerDetails.get(Broker.STATE));
+
+ assertNotNull("Unexpected value of attribute " + Broker.ID, brokerDetails.get(Broker.ID));
+ assertNotNull("Unexpected value of attribute statistics", brokerDetails.get(BROKER_STATISTICS_ATTRIBUTE));
+ assertNotNull("Unexpected value of attribute virtualhosts", brokerDetails.get(BROKER_VIRTUALHOSTS_ATTRIBUTE));
+ assertNotNull("Unexpected value of attribute ports", brokerDetails.get(BROKER_PORTS_ATTRIBUTE));
+ assertNotNull("Unexpected value of attribute authenticationproviders", brokerDetails.get(BROKER_AUTHENTICATIONPROVIDERS_ATTRIBUTE));
+ }
+
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/ConnectionRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/ConnectionRestTest.java
new file mode 100644
index 0000000000..05c8e362a1
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/ConnectionRestTest.java
@@ -0,0 +1,213 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.rest;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.List;
+import java.util.Map;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.server.model.Connection;
+import org.apache.qpid.server.model.Session;
+
+public class ConnectionRestTest extends QpidRestTestCase
+{
+ /**
+ * Message number to publish into queue
+ */
+ private static final int MESSAGE_NUMBER = 5;
+ private static final int MESSAGE_SIZE = 6;
+
+ private static final String SESSIONS_ATTRIBUTE = "sessions";
+
+ private javax.jms.Connection _connection;
+ private javax.jms.Session _session;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+
+ _connection = getConnection();
+ _session = _connection.createSession(true, javax.jms.Session.SESSION_TRANSACTED);
+ String queueName = getTestQueueName();
+ Destination queue = _session.createQueue(queueName);
+ MessageConsumer consumer = _session.createConsumer(queue);
+ MessageProducer producer = _session.createProducer(queue);
+ _connection.start();
+
+ // send messages
+ for (int i = 0; i < MESSAGE_NUMBER; i++)
+ {
+ producer.send(_session.createTextMessage("Test-" + i));
+ }
+ _session.commit();
+
+ Message m = consumer.receive(1000l);
+ assertNotNull("Message was not received", m);
+ _session.commit();
+
+ // receive the rest of messages for rollback
+ for (int i = 0; i < MESSAGE_NUMBER - 1; i++)
+ {
+ m = consumer.receive(1000l);
+ assertNotNull("Message was not received", m);
+ }
+ _session.rollback();
+
+ // receive them again
+ for (int i = 0; i < MESSAGE_NUMBER - 1; i++)
+ {
+ m = consumer.receive(1000l);
+ assertNotNull("Message was not received", m);
+ }
+ }
+
+ public void testGetAllConnections() throws Exception
+ {
+ List<Map<String, Object>> connections = getRestTestHelper().getJsonAsList("/rest/connection");
+ assertEquals("Unexpected number of connections", 1, connections.size());
+ Asserts.assertConnection(connections.get(0), (AMQConnection) _connection);
+ }
+
+ public void testGetVirtualHostConnections() throws Exception
+ {
+ List<Map<String, Object>> connections = getRestTestHelper().getJsonAsList("/rest/connection/test");
+ assertEquals("Unexpected number of connections", 1, connections.size());
+ Asserts.assertConnection(connections.get(0), (AMQConnection) _connection);
+ }
+
+ public void testGetConnectionByName() throws Exception
+ {
+ // get connection name
+ String connectionName = getConnectionName();
+
+ Map<String, Object> connectionDetails = getRestTestHelper().getJsonAsSingletonList("/rest/connection/test/"
+ + URLDecoder.decode(connectionName, "UTF-8"));
+ assertConnection(connectionDetails);
+ }
+
+ public void testGetAllSessions() throws Exception
+ {
+ List<Map<String, Object>> sessions = getRestTestHelper().getJsonAsList("/rest/session");
+ assertEquals("Unexpected number of sessions", 1, sessions.size());
+ assertSession(sessions.get(0), (AMQSession<?, ?>) _session);
+ }
+
+ public void testGetVirtualHostSessions() throws Exception
+ {
+ List<Map<String, Object>> sessions = getRestTestHelper().getJsonAsList("/rest/session/test");
+ assertEquals("Unexpected number of sessions", 1, sessions.size());
+ assertSession(sessions.get(0), (AMQSession<?, ?>) _session);
+ }
+
+ public void testGetConnectionSessions() throws Exception
+ {
+ // get connection name
+ String connectionName = getConnectionName();
+
+ List<Map<String, Object>> sessions = getRestTestHelper().getJsonAsList("/rest/session/test/"
+ + URLDecoder.decode(connectionName, "UTF-8"));
+ assertEquals("Unexpected number of sessions", 1, sessions.size());
+ assertSession(sessions.get(0), (AMQSession<?, ?>) _session);
+ }
+
+ public void testGetSessionByName() throws Exception
+ {
+ // get connection name
+ String connectionName = getConnectionName();
+
+ List<Map<String, Object>> sessions = getRestTestHelper().getJsonAsList("/rest/session/test/"
+ + URLDecoder.decode(connectionName, "UTF-8") + "/" + ((AMQSession<?, ?>) _session).getChannelId());
+ assertEquals("Unexpected number of sessions", 1, sessions.size());
+ assertSession(sessions.get(0), (AMQSession<?, ?>) _session);
+ }
+
+ private void assertConnection(Map<String, Object> connectionDetails) throws JMSException
+ {
+ Asserts.assertConnection(connectionDetails, (AMQConnection) _connection);
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) connectionDetails.get(Asserts.STATISTICS_ATTRIBUTE);
+ assertEquals("Unexpected value of connection statistics attribute " + Connection.BYTES_IN, MESSAGE_NUMBER
+ * MESSAGE_SIZE, statistics.get(Connection.BYTES_IN));
+ assertEquals("Unexpected value of connection statistics attribute " + Connection.BYTES_OUT, MESSAGE_SIZE
+ + ((MESSAGE_NUMBER - 1) * MESSAGE_SIZE) * 2, statistics.get(Connection.BYTES_OUT));
+ assertEquals("Unexpected value of connection statistics attribute " + Connection.MESSAGES_IN, MESSAGE_NUMBER,
+ statistics.get(Connection.MESSAGES_IN));
+ assertEquals("Unexpected value of connection statistics attribute " + Connection.MESSAGES_OUT,
+ MESSAGE_NUMBER * 2 - 1, statistics.get(Connection.MESSAGES_OUT));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> sessions = (List<Map<String, Object>>) connectionDetails.get(SESSIONS_ATTRIBUTE);
+ assertNotNull("Sessions cannot be found", sessions);
+ assertEquals("Unexpected number of sessions", 1, sessions.size());
+ assertSession(sessions.get(0), (AMQSession<?, ?>) _session);
+ }
+
+ private void assertSession(Map<String, Object> sessionData, AMQSession<?, ?> session)
+ {
+ assertNotNull("Session map cannot be null", sessionData);
+ Asserts.assertAttributesPresent(sessionData, Session.AVAILABLE_ATTRIBUTES, Session.STATE, Session.DURABLE,
+ Session.LIFETIME_POLICY, Session.TIME_TO_LIVE, Session.CREATED, Session.UPDATED);
+ assertEquals("Unexpecte value of attribute " + Session.NAME, session.getChannelId() + "",
+ sessionData.get(Session.NAME));
+ assertEquals("Unexpecte value of attribute " + Session.PRODUCER_FLOW_BLOCKED, Boolean.FALSE,
+ sessionData.get(Session.PRODUCER_FLOW_BLOCKED));
+ assertEquals("Unexpecte value of attribute " + Session.CHANNEL_ID, session.getChannelId(),
+ sessionData.get(Session.CHANNEL_ID));
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) sessionData.get(Asserts.STATISTICS_ATTRIBUTE);
+ Asserts.assertAttributesPresent(statistics, Session.AVAILABLE_STATISTICS, Session.BYTES_IN, Session.BYTES_OUT,
+ Session.STATE_CHANGED, Session.UNACKNOWLEDGED_BYTES, Session.LOCAL_TRANSACTION_OPEN,
+ Session.XA_TRANSACTION_BRANCH_ENDS, Session.XA_TRANSACTION_BRANCH_STARTS,
+ Session.XA_TRANSACTION_BRANCH_SUSPENDS);
+
+ assertEquals("Unexpecte value of statistic attribute " + Session.UNACKNOWLEDGED_MESSAGES, MESSAGE_NUMBER - 1,
+ statistics.get(Session.UNACKNOWLEDGED_MESSAGES));
+ assertEquals("Unexpecte value of statistic attribute " + Session.LOCAL_TRANSACTION_BEGINS, 4,
+ statistics.get(Session.LOCAL_TRANSACTION_BEGINS));
+ assertEquals("Unexpecte value of statistic attribute " + Session.LOCAL_TRANSACTION_ROLLBACKS, 1,
+ statistics.get(Session.LOCAL_TRANSACTION_ROLLBACKS));
+ assertEquals("Unexpecte value of statistic attribute " + Session.CONSUMER_COUNT, 1,
+ statistics.get(Session.CONSUMER_COUNT));
+ }
+
+ private String getConnectionName() throws IOException
+ {
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> connections = (List<Map<String, Object>>) hostDetails
+ .get(VirtualHostRestTest.VIRTUALHOST_CONNECTIONS_ATTRIBUTE);
+ assertEquals("Unexpected number of connections", 1, connections.size());
+ Map<String, Object> connection = connections.get(0);
+ String connectionName = (String) connection.get(Connection.NAME);
+ return connectionName;
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/ExchangeRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/ExchangeRestTest.java
new file mode 100644
index 0000000000..ec9791db13
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/ExchangeRestTest.java
@@ -0,0 +1,87 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.rest;
+
+import java.net.URLDecoder;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.model.Binding;
+import org.apache.qpid.server.model.Exchange;
+
+public class ExchangeRestTest extends QpidRestTestCase
+{
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> exchanges = getRestTestHelper().getJsonAsList("/rest/exchange");
+ assertNotNull("Exchanges cannot be null", exchanges);
+ assertTrue("Unexpected number of exchanges", exchanges.size() >= EXPECTED_VIRTUALHOSTS.length * EXPECTED_EXCHANGES.length);
+ for (Map<String, Object> exchange : exchanges)
+ {
+ Asserts.assertExchange((String) exchange.get(Exchange.NAME), (String) exchange.get(Exchange.TYPE), exchange);
+ }
+ }
+
+ public void testGetHostExchanges() throws Exception
+ {
+ List<Map<String, Object>> exchanges = getRestTestHelper().getJsonAsList("/rest/exchange/test");
+ assertNotNull("Users cannot be null", exchanges);
+ assertEquals("Unexpected number of exchanges", exchanges.size(), EXPECTED_EXCHANGES.length);
+ for (String exchangeName : EXPECTED_EXCHANGES)
+ {
+ Map<String, Object> exchange = getRestTestHelper().find(Exchange.NAME, exchangeName, exchanges);
+ assertExchange(exchangeName, exchange);
+ }
+ }
+
+ public void testGetHostExchangeByName() throws Exception
+ {
+ for (String exchangeName : EXPECTED_EXCHANGES)
+ {
+ Map<String, Object> exchange = getRestTestHelper().getJsonAsSingletonList("/rest/exchange/test/"
+ + URLDecoder.decode(exchangeName, "UTF-8"));
+ assertExchange(exchangeName, exchange);
+ }
+ }
+
+ private void assertExchange(String exchangeName, Map<String, Object> exchange)
+ {
+ assertNotNull("Exchange with name " + exchangeName + " is not found", exchange);
+ String type = (String) exchange.get(Exchange.TYPE);
+ Asserts.assertExchange(exchangeName, type, exchange);
+ if ("direct".equals(type))
+ {
+ assertBindings(exchange);
+ }
+ }
+
+ private void assertBindings(Map<String, Object> exchange)
+ {
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> bindings = (List<Map<String, Object>>) exchange.get("bindings");
+ for (String queueName : EXPECTED_QUEUES)
+ {
+ Map<String, Object> binding = getRestTestHelper().find(Binding.NAME, queueName, bindings);
+ Asserts.assertBinding(queueName, (String) exchange.get(Exchange.NAME), binding);
+ }
+ }
+
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java
new file mode 100644
index 0000000000..2852de6fb3
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupProviderRestTest.java
@@ -0,0 +1,160 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.rest;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.qpid.server.model.Group;
+import org.apache.qpid.server.model.GroupProvider;
+import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.UUIDGenerator;
+
+public class GroupProviderRestTest extends QpidRestTestCase
+{
+ private static final String FILE_GROUP_MANAGER = "FileGroupManager";
+ private File _groupFile;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _groupFile = createTemporaryGroupFile();
+
+ setConfigurationProperty("security.file-group-manager.attributes.attribute.name", "groupFile");
+ setConfigurationProperty("security.file-group-manager.attributes.attribute.value", _groupFile.getAbsolutePath());
+
+ super.setUp();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ super.tearDown();
+
+ if (_groupFile != null)
+ {
+ if (_groupFile.exists())
+ {
+ _groupFile.delete();
+ }
+ }
+ }
+
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> providerDetails = getRestTestHelper().getJsonAsList("/rest/groupprovider");
+ assertNotNull("Providers details cannot be null", providerDetails);
+ assertEquals("Unexpected number of providers", 1, providerDetails.size());
+ for (Map<String, Object> provider : providerDetails)
+ {
+ assertProvider(FILE_GROUP_MANAGER, provider);
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/"
+ + provider.get(GroupProvider.NAME));
+ assertNotNull("Cannot load data for " + provider.get(GroupProvider.NAME), data);
+ assertProvider(FILE_GROUP_MANAGER, data);
+ }
+ }
+
+ public void testCreateNewGroup() throws Exception
+ {
+ String groupName = "newGroup";
+
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ assertNotNull("Cannot load data for provider", data);
+
+ getRestTestHelper().assertNumberOfGroups(data, 1);
+
+ getRestTestHelper().createGroup(groupName, FILE_GROUP_MANAGER);
+
+ data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ assertNotNull("Cannot load data for provider", data);
+
+ getRestTestHelper().assertNumberOfGroups(data, 2);
+ }
+
+ public void testRemoveGroup() throws Exception
+ {
+ String groupName = "myGroup";
+
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ assertNotNull("Cannot load data for provider", data);
+
+ getRestTestHelper().assertNumberOfGroups(data, 1);
+
+ getRestTestHelper().removeGroup(groupName, FILE_GROUP_MANAGER);
+
+ data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ assertNotNull("Cannot load data for provider", data);
+
+ getRestTestHelper().assertNumberOfGroups(data, 0);
+ }
+
+
+ private void assertProvider(String type, Map<String, Object> provider)
+ {
+ Asserts.assertAttributesPresent(provider, GroupProvider.AVAILABLE_ATTRIBUTES,
+ GroupProvider.CREATED, GroupProvider.UPDATED, GroupProvider.DESCRIPTION,
+ GroupProvider.TIME_TO_LIVE);
+ assertEquals("Unexpected value of provider attribute " + GroupProvider.STATE, State.ACTIVE.name(),
+ provider.get(GroupProvider.STATE));
+ assertEquals("Unexpected value of provider attribute " + GroupProvider.LIFETIME_POLICY,
+ LifetimePolicy.PERMANENT.name(), provider.get(GroupProvider.LIFETIME_POLICY));
+ assertEquals("Unexpected value of provider attribute " + GroupProvider.DURABLE, Boolean.TRUE,
+ provider.get(GroupProvider.DURABLE));
+ assertEquals("Unexpected value of provider attribute " + GroupProvider.TYPE, type,
+ provider.get(GroupProvider.TYPE));
+
+ final String name = (String) provider.get(GroupProvider.NAME);
+ assertEquals("Unexpected value of provider attribute " + GroupProvider.NAME, type,
+ name);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> groups = (List<Map<String, Object>>) provider.get("groups");
+ assertNotNull("Groups were not found", groups);
+ assertEquals("Unexpected number of groups", 1, groups.size());
+ for (Map<String, Object> group : groups)
+ {
+
+ final String groupName = (String) group.get(Group.NAME);
+ assertNotNull("Attribute " + Group.NAME, groupName);
+
+ assertNotNull("Attribute " + Group.ID, group.get(Group.ID));
+ assertEquals("Attribute " + Group.ID, UUIDGenerator.generateGroupUUID(name, groupName).toString(), group.get(Group.ID));
+ }
+ }
+
+ private File createTemporaryGroupFile() throws Exception
+ {
+ File groupFile = File.createTempFile("group", "grp");
+ groupFile.deleteOnExit();
+
+ Properties props = new Properties();
+ props.put("myGroup.users", "guest");
+
+ props.store(new FileOutputStream(groupFile), "test group file");
+
+ return groupFile;
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupRestTest.java
new file mode 100644
index 0000000000..cbfd943f8f
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/GroupRestTest.java
@@ -0,0 +1,109 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.rest;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.qpid.server.model.GroupMember;
+
+public class GroupRestTest extends QpidRestTestCase
+{
+ private static final String GROUP_NAME = "myGroup";
+ private static final String FILE_GROUP_MANAGER = "FileGroupManager";
+ private static final String EXISTING_MEMBER = "user1";
+ private static final String NEW_MEMBER = "user2";
+
+ private File _groupFile;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _groupFile = createTemporaryGroupFile();
+
+ setConfigurationProperty("security.file-group-manager.attributes.attribute.name", "groupFile");
+ setConfigurationProperty("security.file-group-manager.attributes.attribute.value", _groupFile.getAbsolutePath());
+
+ super.setUp();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ super.tearDown();
+
+ if (_groupFile != null)
+ {
+ if (_groupFile.exists())
+ {
+ _groupFile.delete();
+ }
+ }
+ }
+
+ public void testGet() throws Exception
+ {
+ Map<String, Object> group = getRestTestHelper().getJsonAsSingletonList("/rest/group/FileGroupManager/myGroup");
+ List<Map<String, Object>> groupmembers = (List<Map<String, Object>>) group.get("groupmembers");
+ assertEquals(1, groupmembers.size());
+
+ Map<String, Object> member1 = groupmembers.get(0);
+ assertEquals(EXISTING_MEMBER, (String)member1.get(GroupMember.NAME));
+ }
+
+ public void testCreateNewMemberOfGroup() throws Exception
+ {
+ Map<String, Object> group = getRestTestHelper().getJsonAsSingletonList("/rest/group/FileGroupManager/myGroup");
+ getRestTestHelper().assertNumberOfGroupMembers(group, 1);
+
+ getRestTestHelper().createNewGroupMember(FILE_GROUP_MANAGER, GROUP_NAME, NEW_MEMBER);
+
+ group = getRestTestHelper().getJsonAsSingletonList("/rest/group/FileGroupManager/myGroup");
+ getRestTestHelper().assertNumberOfGroupMembers(group, 2);
+ }
+
+ public void testRemoveMemberFromGroup() throws Exception
+ {
+ Map<String, Object> group = getRestTestHelper().getJsonAsSingletonList("/rest/group/FileGroupManager/myGroup");
+ getRestTestHelper().assertNumberOfGroupMembers(group, 1);
+
+ getRestTestHelper().removeMemberFromGroup(FILE_GROUP_MANAGER, GROUP_NAME, EXISTING_MEMBER);
+
+ group = getRestTestHelper().getJsonAsSingletonList("/rest/group/FileGroupManager/myGroup");
+ getRestTestHelper().assertNumberOfGroupMembers(group, 0);
+ }
+
+ private File createTemporaryGroupFile() throws Exception
+ {
+ File groupFile = File.createTempFile("group", "grp");
+ groupFile.deleteOnExit();
+
+ Properties props = new Properties();
+ props.put(GROUP_NAME + ".users", EXISTING_MEMBER);
+
+ props.store(new FileOutputStream(groupFile), "test group file");
+
+ return groupFile;
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/LogRecordsRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/LogRecordsRestTest.java
new file mode 100644
index 0000000000..a2f9d3189c
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/LogRecordsRestTest.java
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.rest;
+
+import java.util.List;
+import java.util.Map;
+
+public class LogRecordsRestTest extends QpidRestTestCase
+{
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> logs = getRestTestHelper().getJsonAsList("/rest/logrecords");
+ assertNotNull("Logs data cannot be null", logs);
+ assertTrue("Logs are not found", logs.size() > 0);
+ Map<String, Object> record = getRestTestHelper().find("message", "[Broker] BRK-1004 : Qpid Broker Ready", logs);
+
+ assertNotNull("BRK-1004 message is not found", record);
+ assertNotNull("Message id cannot be null", record.get("id"));
+ assertNotNull("Message timestamp cannot be null", record.get("timestamp"));
+ assertEquals("Unexpected log level", "INFO", record.get("level"));
+ assertEquals("Unexpected thread", "main", record.get("thread"));
+ assertEquals("Unexpected logger", "qpid.message.broker.ready", record.get("logger"));
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/MessagesRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/MessagesRestTest.java
new file mode 100644
index 0000000000..fb6bfca1d8
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/MessagesRestTest.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.systest.rest;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.BytesMessage;
+import javax.jms.Connection;
+import javax.jms.DeliveryMode;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+
+public class MessagesRestTest extends QpidRestTestCase
+{
+
+ /**
+ * Message number to publish into queue
+ */
+ private static final int MESSAGE_NUMBER = 12;
+
+ private Connection _connection;
+ private Session _session;
+ private MessageProducer _producer;
+ private long _startTime;
+ private long _ttl;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _startTime = System.currentTimeMillis();
+ _connection = getConnection();
+ _session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ String queueName = getTestQueueName();
+ Destination queue = _session.createQueue(queueName);
+ _session.createConsumer(queue);
+ _producer = _session.createProducer(queue);
+
+ _ttl = TimeUnit.DAYS.toMillis(1);
+ for (int i = 0; i < MESSAGE_NUMBER; i++)
+ {
+ Message m = _session.createTextMessage("Test-" + i);
+ m.setIntProperty("index", i);
+ if (i % 2 == 0)
+ {
+ _producer.send(m);
+ }
+ else
+ {
+ _producer.send(m, DeliveryMode.NON_PERSISTENT, 5, _ttl);
+ }
+ }
+ _session.commit();
+ }
+
+ public void testGet() throws Exception
+ {
+ String queueName = getTestQueueName();
+ List<Map<String, Object>> messages = getRestTestHelper().getJsonAsList("/rest/message/test/" + queueName);
+ assertNotNull("Messages are not found", messages);
+ assertEquals("Unexpected number of messages", MESSAGE_NUMBER, messages.size());
+ int position = 0;
+ for (Map<String, Object> message : messages)
+ {
+ assertMessage(position, message);
+ position++;
+ }
+ }
+
+ public void testGetMessageContent() throws Exception
+ {
+ String queueName = getTestQueueName();
+
+ // add bytes message
+ BytesMessage byteMessage = _session.createBytesMessage();
+ byte[] messageBytes = "Test".getBytes();
+ byteMessage.writeBytes(messageBytes);
+ byteMessage.setStringProperty("test", "value");
+ _producer.send(byteMessage);
+ _session.commit();
+
+ // get message IDs
+ List<Long> ids = getMesssageIds(queueName);
+
+ Map<String, Object> message = getRestTestHelper().getJsonAsMap("/rest/message/test/" + queueName + "/" + ids.get(0));
+ assertMessageAttributes(message);
+ assertMessageAttributeValues(message, true);
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> headers = (Map<String, Object>) message.get("headers");
+ assertNotNull("Message headers are not found", headers);
+ assertEquals("Unexpected message header", 0, headers.get("index"));
+
+ Long lastMessageId = ids.get(ids.size() - 1);
+ message = getRestTestHelper().getJsonAsMap("/rest/message/test/" + queueName + "/" + lastMessageId);
+ assertMessageAttributes(message);
+ assertEquals("Unexpected message attribute mimeType", "application/octet-stream", message.get("mimeType"));
+ assertEquals("Unexpected message attribute size", 4, message.get("size"));
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> bytesMessageHeader = (Map<String, Object>) message.get("headers");
+ assertNotNull("Message headers are not found", bytesMessageHeader);
+ assertEquals("Unexpected message header", "value", bytesMessageHeader.get("test"));
+
+ // get content
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/message-content/test/" + queueName + "/"
+ + lastMessageId, "GET");
+ connection.connect();
+ byte[] data = getRestTestHelper().readConnectionInputStream(connection);
+ assertTrue("Unexpected message", Arrays.equals(messageBytes, data));
+
+ }
+
+ public void testPostMoveMessages() throws Exception
+ {
+ String queueName = getTestQueueName();
+ String queueName2 = queueName + "_2";
+ Destination queue2 = _session.createQueue(queueName2);
+ _session.createConsumer(queue2);
+
+ // get message IDs
+ List<Long> ids = getMesssageIds(queueName);
+
+ // move half of the messages
+ int movedNumber = ids.size() / 2;
+ List<Long> movedMessageIds = new ArrayList<Long>();
+ for (int i = 0; i < movedNumber; i++)
+ {
+ movedMessageIds.add(ids.remove(i));
+ }
+
+ // move messages
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/message/test/" + queueName, "POST");
+
+ Map<String, Object> messagesData = new HashMap<String, Object>();
+ messagesData.put("messages", movedMessageIds);
+ messagesData.put("destinationQueue", queueName2);
+ messagesData.put("move", Boolean.TRUE);
+
+ getRestTestHelper().writeJsonRequest(connection, messagesData);
+ assertEquals("Unexpected response code", 200, connection.getResponseCode());
+
+ // check messages on target queue
+ List<Map<String, Object>> messages = getRestTestHelper().getJsonAsList("/rest/message/test/" + queueName2);
+ assertNotNull("Messages are not found", messages);
+ assertEquals("Unexpected number of messages", movedMessageIds.size(), messages.size());
+ for (Long id : movedMessageIds)
+ {
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
+ assertMessageAttributes(message);
+ }
+
+ // check messages on original queue
+ messages = getRestTestHelper().getJsonAsList("/rest/message/test/" + queueName);
+ assertNotNull("Messages are not found", messages);
+ assertEquals("Unexpected number of messages", ids.size(), messages.size());
+ for (Long id : ids)
+ {
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
+ assertMessageAttributes(message);
+ }
+ for (Long id : movedMessageIds)
+ {
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
+ assertNull("Moved message " + id + " is found on original queue", message);
+ }
+ }
+
+ public void testPostCopyMessages() throws Exception
+ {
+ String queueName = getTestQueueName();
+ String queueName2 = queueName + "_2";
+ Destination queue2 = _session.createQueue(queueName2);
+ _session.createConsumer(queue2);
+
+ // get message IDs
+ List<Long> ids = getMesssageIds(queueName);
+
+ // copy half of the messages
+ int copyNumber = ids.size() / 2;
+ List<Long> copyMessageIds = new ArrayList<Long>();
+ for (int i = 0; i < copyNumber; i++)
+ {
+ copyMessageIds.add(ids.remove(i));
+ }
+
+ // copy messages
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/message/test/" + queueName, "POST");
+
+ Map<String, Object> messagesData = new HashMap<String, Object>();
+ messagesData.put("messages", copyMessageIds);
+ messagesData.put("destinationQueue", queueName2);
+
+ getRestTestHelper().writeJsonRequest(connection, messagesData);
+ assertEquals("Unexpected response code", 200, connection.getResponseCode());
+
+ // check messages on target queue
+ List<Map<String, Object>> messages = getRestTestHelper().getJsonAsList("/rest/message/test/" + queueName2);
+ assertNotNull("Messages are not found", messages);
+ assertEquals("Unexpected number of messages", copyMessageIds.size(), messages.size());
+ for (Long id : copyMessageIds)
+ {
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
+ assertMessageAttributes(message);
+ }
+
+ // check messages on original queue
+ messages = getRestTestHelper().getJsonAsList("/rest/message/test/" + queueName);
+ assertNotNull("Messages are not found", messages);
+ assertEquals("Unexpected number of messages", MESSAGE_NUMBER, messages.size());
+ for (Long id : ids)
+ {
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
+ assertMessageAttributes(message);
+ }
+ for (Long id : copyMessageIds)
+ {
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
+ assertMessageAttributes(message);
+ }
+ }
+
+ public void testDeleteMessages() throws Exception
+ {
+ String queueName = getTestQueueName();
+
+ // get message IDs
+ List<Long> ids = getMesssageIds(queueName);
+
+ // delete half of the messages
+ int deleteNumber = ids.size() / 2;
+ StringBuilder queryString = new StringBuilder();
+ List<Long> deleteMessageIds = new ArrayList<Long>();
+ for (int i = 0; i < deleteNumber; i++)
+ {
+ Long id = ids.remove(i);
+ deleteMessageIds.add(id);
+ if (queryString.length() > 0)
+ {
+ queryString.append("&");
+ }
+ queryString.append("id=").append(id);
+ }
+
+ // delete messages
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection(
+ "/rest/message/test/" + queueName + "?" + queryString.toString(), "DELETE");
+ connection.connect();
+ assertEquals("Unexpected response code", 200, connection.getResponseCode());
+
+ // check messages on queue
+ List<Map<String, Object>> messages = getRestTestHelper().getJsonAsList("/rest/message/test/" + queueName);
+ assertNotNull("Messages are not found", messages);
+ assertEquals("Unexpected number of messages", ids.size(), messages.size());
+ for (Long id : ids)
+ {
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
+ assertMessageAttributes(message);
+ }
+ for (Long id : deleteMessageIds)
+ {
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
+ assertNull("Message with id " + id + " was not deleted", message);
+ }
+ }
+
+ private List<Long> getMesssageIds(String queueName) throws IOException, JsonParseException, JsonMappingException
+ {
+ List<Map<String, Object>> messages = getRestTestHelper().getJsonAsList("/rest/message/test/" + queueName);
+ List<Long> ids = new ArrayList<Long>();
+ for (Map<String, Object> message : messages)
+ {
+ ids.add(((Number) message.get("id")).longValue());
+ }
+ return ids;
+ }
+
+ private void assertMessage(int position, Map<String, Object> message)
+ {
+ assertMessageAttributes(message);
+
+ assertEquals("Unexpected message attribute position", position, message.get("position"));
+ assertEquals("Unexpected message attribute size", position < 10 ? 6 : 7, message.get("size"));
+ boolean even = position % 2 == 0;
+ assertMessageAttributeValues(message, even);
+ }
+
+ private void assertMessageAttributeValues(Map<String, Object> message, boolean even)
+ {
+ if (even)
+ {
+ assertEquals("Unexpected message attribute expirationTime", 0, message.get("expirationTime"));
+ assertEquals("Unexpected message attribute priority", 4, message.get("priority"));
+ assertEquals("Unexpected message attribute persistent", Boolean.TRUE, message.get("persistent"));
+ }
+ else
+ {
+ assertEquals("Unexpected message attribute expirationTime", ((Number) message.get("timestamp")).longValue()
+ + _ttl, message.get("expirationTime"));
+ assertEquals("Unexpected message attribute priority", 5, message.get("priority"));
+ assertEquals("Unexpected message attribute persistent", Boolean.FALSE, message.get("persistent"));
+ }
+ assertEquals("Unexpected message attribute mimeType", "text/plain", message.get("mimeType"));
+ assertEquals("Unexpected message attribute userId", "guest", message.get("userId"));
+ assertEquals("Unexpected message attribute deliveryCount", 0, message.get("deliveryCount"));
+ assertEquals("Unexpected message attribute state", "Available", message.get("state"));
+ }
+
+ private void assertMessageAttributes(Map<String, Object> message)
+ {
+ assertNotNull("Message map cannot be null", message);
+ assertNotNull("Unexpected message attribute deliveryCount", message.get("deliveryCount"));
+ assertNotNull("Unexpected message attribute state", message.get("state"));
+ assertNotNull("Unexpected message attribute id", message.get("id"));
+ assertNotNull("Message arrivalTime cannot be null", message.get("arrivalTime"));
+ assertNotNull("Message timestamp cannot be null", message.get("timestamp"));
+ assertTrue("Message arrivalTime cannot be null", ((Number) message.get("arrivalTime")).longValue() > _startTime);
+ assertNotNull("Message messageId cannot be null", message.get("messageId"));
+ assertNotNull("Unexpected message attribute mimeType", message.get("mimeType"));
+ assertNotNull("Unexpected message attribute userId", message.get("userId"));
+ assertNotNull("Message priority cannot be null", message.get("priority"));
+ assertNotNull("Message expirationTime cannot be null", message.get("expirationTime"));
+ assertNotNull("Message persistent cannot be null", message.get("persistent"));
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PortRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PortRestTest.java
new file mode 100644
index 0000000000..d5a8c31010
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PortRestTest.java
@@ -0,0 +1,61 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.rest;
+
+import java.net.URLDecoder;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.model.Port;
+
+public class PortRestTest extends QpidRestTestCase
+{
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> ports = getRestTestHelper().getJsonAsList("/rest/port/");
+ assertNotNull("Port data cannot be null", ports);
+ assertEquals("Unexpected number of ports", 2, ports.size());
+ int[] expectedPorts = { getPort(), getRestTestHelper().getHttpPort() };
+ for (int port : expectedPorts)
+ {
+ String portName = "0.0.0.0:" + port;
+ Map<String, Object> portData = getRestTestHelper().find(Port.NAME, portName, ports);
+ assertNotNull("Port " + portName + " is not found", portData);
+ Asserts.assertPortAttributes(portData);
+ }
+ }
+
+ public void testGetPort() throws Exception
+ {
+ List<Map<String, Object>> ports = getRestTestHelper().getJsonAsList("/rest/port/");
+ assertNotNull("Ports data cannot be null", ports);
+ assertEquals("Unexpected number of ports", 2, ports.size());
+ for (Map<String, Object> portMap : ports)
+ {
+ String portName = (String) portMap.get(Port.NAME);
+ assertNotNull("Port name attribute is not found", portName);
+ Map<String, Object> portData = getRestTestHelper().getJsonAsSingletonList("/rest/port/" + URLDecoder.decode(portName, "UTF-8"));
+ assertNotNull("Port " + portName + " is not found", portData);
+ Asserts.assertPortAttributes(portData);
+ }
+ }
+
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QpidRestTestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QpidRestTestCase.java
new file mode 100644
index 0000000000..d63d17f6e5
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QpidRestTestCase.java
@@ -0,0 +1,83 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.rest;
+
+import java.io.IOException;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+public class QpidRestTestCase extends QpidBrokerTestCase
+{
+ public static final String TEST1_VIRTUALHOST = "test";
+ public static final String TEST2_VIRTUALHOST = "test2";
+ public static final String TEST3_VIRTUALHOST = "test3";
+
+ public static final String[] EXPECTED_VIRTUALHOSTS = { TEST1_VIRTUALHOST, TEST2_VIRTUALHOST, TEST3_VIRTUALHOST};
+ public static final String[] EXPECTED_QUEUES = { "queue", "ping" };
+ public static final String[] EXPECTED_EXCHANGES = { "amq.fanout", "amq.match", "amq.direct","amq.topic","<<default>>" };
+
+ private RestTestHelper _restTestHelper = new RestTestHelper(findFreePort());
+
+ @Override
+ public void setUp() throws Exception
+ {
+ // Set up virtualhost config with queues and bindings to the amq.direct
+ for (String virtualhost : EXPECTED_VIRTUALHOSTS)
+ {
+ createTestVirtualHost(virtualhost);
+ for (String queue : EXPECTED_QUEUES)
+ {
+ setConfigurationProperty("virtualhosts.virtualhost." + virtualhost + ".queues.exchange", "amq.direct");
+ setConfigurationProperty("virtualhosts.virtualhost." + virtualhost + ".queues.queue(-1).name", queue);
+ }
+ }
+
+ customizeConfiguration();
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ try
+ {
+ super.tearDown();
+ }
+ finally
+ {
+ getRestTestHelper().tearDown();
+ }
+ }
+
+ protected void customizeConfiguration() throws ConfigurationException, IOException
+ {
+ setConfigurationProperty("management.enabled", "false");
+ setConfigurationProperty("management.http.enabled", "true");
+ setConfigurationProperty("management.https.enabled", "false");
+ setConfigurationProperty("management.http.port", Integer.toString(_restTestHelper.getHttpPort()));
+ }
+
+ public RestTestHelper getRestTestHelper()
+ {
+ return _restTestHelper;
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QueueRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QueueRestTest.java
new file mode 100644
index 0000000000..1f441e7cbb
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QueueRestTest.java
@@ -0,0 +1,225 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.rest;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URLDecoder;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+import org.apache.qpid.server.model.Binding;
+import org.apache.qpid.server.model.Consumer;
+import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.Queue;
+
+public class QueueRestTest extends QpidRestTestCase
+{
+ private static final String QUEUE_ATTRIBUTE_CONSUMERS = "consumers";
+ private static final String QUEUE_ATTRIBUTE_BINDINGS = "bindings";
+
+ /**
+ * Message number to publish into queue
+ */
+ private static final int MESSAGE_NUMBER = 2;
+ private static final int MESSAGE_PAYLOAD_SIZE = 6;
+ private static final int ENQUEUED_MESSAGES = 1;
+ private static final int DEQUEUED_MESSAGES = 1;
+ private static final int ENQUEUED_BYTES = MESSAGE_PAYLOAD_SIZE;
+ private static final int DEQUEUED_BYTES = MESSAGE_PAYLOAD_SIZE;
+
+ private Connection _connection;
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ _connection = getConnection();
+ Session session = _connection.createSession(true, Session.SESSION_TRANSACTED);
+ String queueName = getTestQueueName();
+ Destination queue = session.createQueue(queueName);
+ MessageConsumer consumer = session.createConsumer(queue);
+ MessageProducer producer = session.createProducer(queue);
+
+ for (int i = 0; i < MESSAGE_NUMBER; i++)
+ {
+ producer.send(session.createTextMessage("Test-" + i));
+ }
+ session.commit();
+ _connection.start();
+ Message m = consumer.receive(1000l);
+ assertNotNull("Message is not received", m);
+ session.commit();
+ }
+
+ public void testGetVirtualHostQueues() throws Exception
+ {
+ String queueName = getTestQueueName();
+ List<Map<String, Object>> queues = getRestTestHelper().getJsonAsList("/rest/queue/test");
+ assertEquals("Unexpected number of queues", EXPECTED_QUEUES.length + 1, queues.size());
+ String[] expectedQueues = new String[EXPECTED_QUEUES.length + 1];
+ System.arraycopy(EXPECTED_QUEUES, 0, expectedQueues, 0, EXPECTED_QUEUES.length);
+ expectedQueues[EXPECTED_QUEUES.length] = queueName;
+
+ for (String name : expectedQueues)
+ {
+ Map<String, Object> queueDetails = getRestTestHelper().find(Queue.NAME, name, queues);
+ Asserts.assertQueue(name, "standard", queueDetails);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> bindings = (List<Map<String, Object>>) queueDetails.get(QUEUE_ATTRIBUTE_BINDINGS);
+ assertNotNull("Queue bindings are not found", bindings);
+ assertEquals("Unexpected number of bindings", 2, bindings.size());
+
+ Map<String, Object> defaultExchangeBinding = getRestTestHelper().find(Binding.EXCHANGE, "<<default>>", bindings);
+ Map<String, Object> directExchangeBinding = getRestTestHelper().find(Binding.EXCHANGE, "amq.direct", bindings);
+ Asserts.assertBinding(name, "<<default>>", defaultExchangeBinding);
+ Asserts.assertBinding(name, "amq.direct", directExchangeBinding);
+ }
+ }
+
+ public void testGetByName() throws Exception
+ {
+ String queueName = getTestQueueName();
+ Map<String, Object> queueDetails = getRestTestHelper().getJsonAsSingletonList("/rest/queue/test/" + queueName);
+ Asserts.assertQueue(queueName, "standard", queueDetails);
+ assertStatistics(queueDetails);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> bindings = (List<Map<String, Object>>) queueDetails.get(QUEUE_ATTRIBUTE_BINDINGS);
+ assertNotNull("Queue bindings are not found", bindings);
+ assertEquals("Unexpected number of bindings", 2, bindings.size());
+
+ Map<String, Object> defaultExchangeBinding = getRestTestHelper().find(Binding.EXCHANGE, "<<default>>", bindings);
+ Map<String, Object> directExchangeBinding = getRestTestHelper().find(Binding.EXCHANGE, "amq.direct", bindings);
+ Asserts.assertBinding(queueName, "<<default>>", defaultExchangeBinding);
+ Asserts.assertBinding(queueName, "amq.direct", directExchangeBinding);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> consumers = (List<Map<String, Object>>) queueDetails.get(QUEUE_ATTRIBUTE_CONSUMERS);
+ assertNotNull("Queue consumers are not found", consumers);
+ assertEquals("Unexpected number of consumers", 1, consumers.size());
+ assertConsumer(consumers.get(0));
+ }
+
+ public void testPutCreateBinding() throws Exception
+ {
+ String queueName = getTestQueueName();
+ String bindingName = queueName + 2;
+ String[] exchanges = { "amq.direct", "amq.fanout", "amq.topic", "amq.match", "<<default>>" };
+
+ for (int i = 0; i < exchanges.length; i++)
+ {
+ createBinding(bindingName, exchanges[i], queueName);
+ }
+
+ Map<String, Object> queueDetails = getRestTestHelper().getJsonAsSingletonList("/rest/queue/test/" + queueName);
+ Asserts.assertQueue(queueName, "standard", queueDetails);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> bindings = (List<Map<String, Object>>) queueDetails.get(QUEUE_ATTRIBUTE_BINDINGS);
+ assertNotNull("Queue bindings are not found", bindings);
+ assertEquals("Unexpected number of bindings", exchanges.length + 2, bindings.size());
+
+ Map<String, Object> searchAttributes = new HashMap<String, Object>();
+ searchAttributes.put(Binding.NAME, bindingName);
+
+ for (int i = 0; i < exchanges.length; i++)
+ {
+ searchAttributes.put(Binding.EXCHANGE, exchanges[i]);
+ Map<String, Object> binding = getRestTestHelper().find(searchAttributes, bindings);
+ Asserts.assertBinding(bindingName, queueName, exchanges[i], binding);
+ }
+ }
+
+ private void createBinding(String bindingName, String exchangeName, String queueName) throws IOException
+ {
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection(
+ "/rest/binding/test/" + URLDecoder.decode(exchangeName, "UTF-8") + "/" + queueName + "/" + bindingName,
+ "PUT");
+
+ Map<String, Object> bindingData = new HashMap<String, Object>();
+ bindingData.put(Binding.NAME, bindingName);
+ bindingData.put(Binding.EXCHANGE, exchangeName);
+ bindingData.put(Binding.QUEUE, queueName);
+
+ getRestTestHelper().writeJsonRequest(connection, bindingData);
+ assertEquals("Unexpected response code", 201, connection.getResponseCode());
+
+ connection.disconnect();
+ }
+
+ private void assertConsumer(Map<String, Object> consumer)
+ {
+ assertNotNull("Consumer map should not be null", consumer);
+ Asserts.assertAttributesPresent(consumer, Consumer.AVAILABLE_ATTRIBUTES, Consumer.STATE, Consumer.TIME_TO_LIVE,
+ Consumer.CREATED, Consumer.UPDATED, Consumer.SETTLEMENT_MODE, Consumer.EXCLUSIVE, Consumer.SELECTOR,
+ Consumer.NO_LOCAL);
+
+ assertEquals("Unexpected binding attribute " + Consumer.NAME, "1", consumer.get(Consumer.NAME));
+ assertEquals("Unexpected binding attribute " + Consumer.DURABLE, Boolean.FALSE, consumer.get(Consumer.DURABLE));
+ assertEquals("Unexpected binding attribute " + Consumer.LIFETIME_POLICY, LifetimePolicy.AUTO_DELETE.name(),
+ consumer.get(Consumer.LIFETIME_POLICY));
+ assertEquals("Unexpected binding attribute " + Consumer.DISTRIBUTION_MODE, "MOVE",
+ consumer.get(Consumer.DISTRIBUTION_MODE));
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) consumer.get(Asserts.STATISTICS_ATTRIBUTE);
+ assertNotNull("Consumer statistics is not present", statistics);
+ Asserts.assertAttributesPresent(statistics, Consumer.AVAILABLE_STATISTICS, Consumer.STATE_CHANGED);
+ }
+
+ private void assertStatistics(Map<String, Object> queueDetails)
+ {
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) queueDetails.get(Asserts.STATISTICS_ATTRIBUTE);
+ assertEquals("Unexpected queue statistics attribute " + Queue.PERSISTENT_DEQUEUED_MESSAGES, DEQUEUED_MESSAGES,
+ statistics.get(Queue.PERSISTENT_DEQUEUED_MESSAGES));
+ assertEquals("Unexpected queue statistics attribute " + Queue.QUEUE_DEPTH_MESSAGES, ENQUEUED_MESSAGES,
+ statistics.get(Queue.QUEUE_DEPTH_MESSAGES));
+ assertEquals("Unexpected queue statistics attribute " + Queue.CONSUMER_COUNT, 1,
+ statistics.get(Queue.CONSUMER_COUNT));
+ assertEquals("Unexpected queue statistics attribute " + Queue.CONSUMER_COUNT_WITH_CREDIT, 1,
+ statistics.get(Queue.CONSUMER_COUNT_WITH_CREDIT));
+ assertEquals("Unexpected queue statistics attribute " + Queue.BINDING_COUNT, 2, statistics.get(Queue.BINDING_COUNT));
+ assertEquals("Unexpected queue statistics attribute " + Queue.PERSISTENT_DEQUEUED_MESSAGES, DEQUEUED_MESSAGES,
+ statistics.get(Queue.PERSISTENT_DEQUEUED_MESSAGES));
+ assertEquals("Unexpected queue statistics attribute " + Queue.TOTAL_DEQUEUED_MESSAGES, DEQUEUED_MESSAGES,
+ statistics.get(Queue.TOTAL_DEQUEUED_MESSAGES));
+ assertEquals("Unexpected queue statistics attribute " + Queue.TOTAL_DEQUEUED_BYTES, DEQUEUED_BYTES,
+ statistics.get(Queue.TOTAL_DEQUEUED_BYTES));
+ assertEquals("Unexpected queue statistics attribute " + Queue.PERSISTENT_DEQUEUED_BYTES, DEQUEUED_BYTES,
+ statistics.get(Queue.TOTAL_DEQUEUED_BYTES));
+ assertEquals("Unexpected queue statistics attribute " + Queue.PERSISTENT_ENQUEUED_BYTES, ENQUEUED_BYTES
+ + DEQUEUED_BYTES, statistics.get(Queue.PERSISTENT_ENQUEUED_BYTES));
+ assertEquals("Unexpected queue statistics attribute " + Queue.TOTAL_ENQUEUED_BYTES, ENQUEUED_BYTES + DEQUEUED_BYTES,
+ statistics.get(Queue.TOTAL_ENQUEUED_BYTES));
+ assertEquals("Unexpected queue statistics attribute " + Queue.QUEUE_DEPTH_BYTES, ENQUEUED_BYTES,
+ statistics.get(Queue.QUEUE_DEPTH_BYTES));
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/RestTestHelper.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/RestTestHelper.java
new file mode 100644
index 0000000000..4de603ae6e
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/RestTestHelper.java
@@ -0,0 +1,445 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.systest.rest;
+
+import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE;
+import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD;
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManagerFactory;
+import javax.servlet.http.HttpServletResponse;
+
+import junit.framework.Assert;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.log4j.Logger;
+import org.apache.qpid.ssl.SSLContextFactory;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.type.TypeReference;
+
+public class RestTestHelper
+{
+ private static final Logger LOGGER = Logger.getLogger(RestTestHelper.class);
+
+ private int _httpPort;
+
+ private boolean _useSsl;
+
+ private String _username;
+
+ private String _password;
+
+ private File _passwdFile;
+
+ public RestTestHelper(int httpPort)
+ {
+ _httpPort = httpPort;
+ }
+
+ public int getHttpPort()
+ {
+ return _httpPort;
+ }
+
+ private String getHostName()
+ {
+ return "localhost";
+ }
+
+ private String getProtocol()
+ {
+ return _useSsl ? "https" : "http";
+ }
+
+ public String getManagementURL()
+ {
+ return getProtocol() + "://" + getHostName() + ":" + getHttpPort();
+ }
+
+ public URL getManagementURL(String path) throws MalformedURLException
+ {
+ return new URL(getManagementURL() + path);
+ }
+
+ public HttpURLConnection openManagementConnection(String path, String method) throws IOException
+ {
+ URL url = getManagementURL(path);
+ HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
+ if(_useSsl)
+ {
+ try
+ {
+ // We have to use a SSLSocketFactory from a new SSLContext so that we don't re-use
+ // the JVM's defaults that may have been initialised in previous tests.
+
+ SSLContext sslContext = SSLContextFactory.buildClientContext(
+ TRUSTSTORE, TRUSTSTORE_PASSWORD,
+ KeyStore.getDefaultType(),
+ TrustManagerFactory.getDefaultAlgorithm(),
+ null, null, null, null, null);
+
+ SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+
+ ((HttpsURLConnection) httpCon).setSSLSocketFactory(sslSocketFactory);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ if(_username != null)
+ {
+ String encoded = new String(new Base64().encode((_username + ":" + _password).getBytes()));
+ httpCon.setRequestProperty("Authorization", "Basic " + encoded);
+ }
+
+ httpCon.setDoOutput(true);
+ httpCon.setRequestMethod(method);
+ return httpCon;
+ }
+
+ public List<Map<String, Object>> readJsonResponseAsList(HttpURLConnection connection) throws IOException,
+ JsonParseException, JsonMappingException
+ {
+ byte[] data = readConnectionInputStream(connection);
+
+ ObjectMapper mapper = new ObjectMapper();
+
+ TypeReference<List<LinkedHashMap<String, Object>>> typeReference = new TypeReference<List<LinkedHashMap<String, Object>>>()
+ {
+ };
+ List<Map<String, Object>> providedObject = mapper.readValue(new ByteArrayInputStream(data), typeReference);
+ return providedObject;
+ }
+
+ public Map<String, Object> readJsonResponseAsMap(HttpURLConnection connection) throws IOException,
+ JsonParseException, JsonMappingException
+ {
+ byte[] data = readConnectionInputStream(connection);
+
+ ObjectMapper mapper = new ObjectMapper();
+
+ TypeReference<LinkedHashMap<String, Object>> typeReference = new TypeReference<LinkedHashMap<String, Object>>()
+ {
+ };
+ Map<String, Object> providedObject = mapper.readValue(new ByteArrayInputStream(data), typeReference);
+ return providedObject;
+ }
+
+ public byte[] readConnectionInputStream(HttpURLConnection connection) throws IOException
+ {
+ InputStream is = connection.getInputStream();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int len = -1;
+ while ((len = is.read(buffer)) != -1)
+ {
+ baos.write(buffer, 0, len);
+ }
+ if (LOGGER.isTraceEnabled())
+ {
+ LOGGER.trace("RESPONSE:" + new String(baos.toByteArray()));
+ }
+ return baos.toByteArray();
+ }
+
+ public void writeJsonRequest(HttpURLConnection connection, Map<String, Object> data) throws JsonGenerationException,
+ JsonMappingException, IOException
+ {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.writeValue(connection.getOutputStream(), data);
+ }
+
+ public Map<String, Object> find(String name, Object value, List<Map<String, Object>> data)
+ {
+ for (Map<String, Object> map : data)
+ {
+ Object mapValue = map.get(name);
+ if (value.equals(mapValue))
+ {
+ return map;
+ }
+ }
+ return null;
+ }
+
+ public Map<String, Object> find(Map<String, Object> searchAttributes, List<Map<String, Object>> data)
+ {
+ for (Map<String, Object> map : data)
+ {
+ boolean equals = true;
+ for (Map.Entry<String, Object> entry : searchAttributes.entrySet())
+ {
+ Object mapValue = map.get(entry.getKey());
+ if (!entry.getValue().equals(mapValue))
+ {
+ equals = false;
+ break;
+ }
+ }
+ if (equals)
+ {
+ return map;
+ }
+ }
+ return null;
+ }
+
+ public Map<String, Object> getJsonAsSingletonList(String path) throws IOException
+ {
+ List<Map<String, Object>> response = getJsonAsList(path);
+
+ Assert.assertNotNull("Response cannot be null", response);
+ Assert.assertEquals("Unexpected response", 1, response.size());
+ return response.get(0);
+ }
+
+ public List<Map<String, Object>> getJsonAsList(String path) throws IOException, JsonParseException,
+ JsonMappingException
+ {
+ HttpURLConnection connection = openManagementConnection(path, "GET");
+ connection.connect();
+ List<Map<String, Object>> response = readJsonResponseAsList(connection);
+ return response;
+ }
+
+ public Map<String, Object> getJsonAsMap(String path) throws IOException
+ {
+ HttpURLConnection connection = openManagementConnection(path, "GET");
+ connection.connect();
+ Map<String, Object> response = readJsonResponseAsMap(connection);
+ return response;
+ }
+
+ public void createNewGroupMember(String groupProviderName, String groupName, String memberName, int responseCode) throws IOException
+ {
+ HttpURLConnection connection = openManagementConnection(
+ "/rest/groupmember/" + URLDecoder.decode(groupProviderName, "UTF-8") + "/"+ URLDecoder.decode(groupName, "UTF-8") + "/" + URLDecoder.decode(memberName, "UTF-8"),
+ "PUT");
+
+ Map<String, Object> groupMemberData = new HashMap<String, Object>();
+ // TODO add type
+ writeJsonRequest(connection, groupMemberData);
+
+ Assert.assertEquals("Unexpected response code", responseCode, connection.getResponseCode());
+
+ connection.disconnect();
+ }
+
+ public void createNewGroupMember(String groupProviderName, String groupName, String memberName) throws IOException
+ {
+ createNewGroupMember(groupProviderName, groupName, memberName, HttpServletResponse.SC_CREATED);
+ }
+
+ public void removeMemberFromGroup(String groupProviderName, String groupName, String memberName, int responseCode) throws IOException
+ {
+ HttpURLConnection connection = openManagementConnection(
+ "/rest/groupmember/" + URLDecoder.decode(groupProviderName, "UTF-8") + "/"+ URLDecoder.decode(groupName, "UTF-8") + "/" + URLDecoder.decode(memberName, "UTF-8"),
+ "DELETE");
+
+ Assert.assertEquals("Unexpected response code", responseCode, connection.getResponseCode());
+
+ connection.disconnect();
+ }
+
+ public void removeMemberFromGroup(String groupProviderName, String groupName, String memberName) throws IOException
+ {
+ removeMemberFromGroup(groupProviderName, groupName, memberName, HttpServletResponse.SC_OK);
+ }
+
+ public void assertNumberOfGroupMembers(Map<String, Object> data, int expectedNumberOfGroupMembers)
+ {
+ List<Map<String, Object>> groups = (List<Map<String, Object>>) data.get("groupmembers");
+ if (groups == null)
+ {
+ groups = Collections.emptyList();
+ }
+
+ Assert.assertEquals("Unexpected number of group members", expectedNumberOfGroupMembers, groups.size());
+ }
+
+ public void createGroup(String groupName, String groupProviderName) throws IOException
+ {
+ createGroup(groupName, groupProviderName, HttpServletResponse.SC_CREATED);
+ }
+
+ public void createGroup(String groupName, String groupProviderName, int responseCode) throws IOException
+ {
+ HttpURLConnection connection = openManagementConnection(
+ "/rest/group/" + URLDecoder.decode(groupProviderName, "UTF-8") + "/"+ URLDecoder.decode(groupName, "UTF-8"),
+ "PUT");
+
+ Map<String, Object> groupData = new HashMap<String, Object>();
+ writeJsonRequest(connection, groupData);
+
+ Assert.assertEquals("Unexpected response code", responseCode, connection.getResponseCode());
+
+ connection.disconnect();
+ }
+
+ public void createOrUpdateUser(String username, String password) throws IOException
+ {
+ createOrUpdateUser(username, password, HttpServletResponse.SC_CREATED);
+ }
+
+ public void createOrUpdateUser(String username, String password, int responseCode) throws IOException
+ {
+ HttpURLConnection connection = openManagementConnection("/rest/user/PrincipalDatabaseAuthenticationManager/" + username, "PUT");
+
+ Map<String, Object> data = new HashMap<String, Object>();
+ data.put("password", password);
+ writeJsonRequest(connection, data);
+
+ Assert.assertEquals("Unexpected response code", responseCode, connection.getResponseCode());
+
+ connection.disconnect();
+ }
+
+ public void removeGroup(String groupName, String groupProviderName, int responseCode) throws IOException
+ {
+ HttpURLConnection connection = openManagementConnection(
+ "/rest/group/" + URLDecoder.decode(groupProviderName, "UTF-8") + "/"+ URLDecoder.decode(groupName, "UTF-8"),
+ "DELETE");
+
+ Assert.assertEquals("Unexpected response code", responseCode, connection.getResponseCode());
+ connection.disconnect();
+ }
+
+ public void removeGroup(String groupName, String groupProviderName) throws IOException
+ {
+ removeGroup(groupName, groupProviderName, HttpServletResponse.SC_OK);
+ }
+
+ public void removeUserById(String id) throws IOException
+ {
+ HttpURLConnection connection = openManagementConnection("/rest/user/PrincipalDatabaseAuthenticationManager?id=" + id, "DELETE");
+ Assert.assertEquals("Unexpected response code", HttpServletResponse.SC_OK, connection.getResponseCode());
+ connection.disconnect();
+ }
+
+ public void removeUser(String username, int responseCode) throws IOException
+ {
+ HttpURLConnection connection = openManagementConnection("/rest/user/PrincipalDatabaseAuthenticationManager/" + username, "DELETE");
+ Assert.assertEquals("Unexpected response code", responseCode, connection.getResponseCode());
+ connection.disconnect();
+ }
+
+ public void removeUser(String username) throws IOException
+ {
+ removeUser(username, HttpServletResponse.SC_OK);
+ }
+
+ public void assertNumberOfGroups(Map<String, Object> data, int expectedNumberOfGroups)
+ {
+ List<Map<String, Object>> groups = (List<Map<String, Object>>) data.get("groups");
+ if (groups == null)
+ {
+ groups = Collections.emptyList();
+ }
+ Assert.assertEquals("Unexpected number of groups", expectedNumberOfGroups, groups.size());
+ }
+
+ public void setUseSsl(boolean useSsl)
+ {
+ _useSsl = useSsl;
+ }
+
+ public void setUsernameAndPassword(String username, String password)
+ {
+ _username = username;
+ _password = password;
+ }
+
+ /**
+ * Create password file that follows the convention username=password, which is deleted by {@link #tearDown()}
+ */
+ public void configureTemporaryPasswordFile(QpidBrokerTestCase testCase, String... users) throws ConfigurationException, IOException
+ {
+ _passwdFile = createTemporaryPasswdFile(users);
+
+ testCase.setConfigurationProperty("security.pd-auth-manager.principal-database.attributes.attribute.name", "passwordFile");
+ testCase.setConfigurationProperty("security.pd-auth-manager.principal-database.attributes.attribute.value", _passwdFile.getAbsolutePath());
+ }
+
+ public void tearDown()
+ {
+ if (_passwdFile != null)
+ {
+ if (_passwdFile.exists())
+ {
+ _passwdFile.delete();
+ }
+ }
+ }
+
+ private File createTemporaryPasswdFile(String[] users) throws IOException
+ {
+ BufferedWriter writer = null;
+ try
+ {
+ File testFile = File.createTempFile(this.getClass().getName(),"tmp");
+ testFile.deleteOnExit();
+
+ writer = new BufferedWriter(new FileWriter(testFile));
+ for (int i = 0; i < users.length; i++)
+ {
+ String username = users[i];
+ writer.write(username + ":" + username);
+ writer.newLine();
+ }
+
+ return testFile;
+
+ }
+ finally
+ {
+ if (writer != null)
+ {
+ writer.close();
+ }
+ }
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/SaslRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/SaslRestTest.java
new file mode 100644
index 0000000000..d321bde2b2
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/SaslRestTest.java
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.rest;
+
+import java.util.List;
+import java.util.Map;
+
+public class SaslRestTest extends QpidRestTestCase
+{
+ public void testGet() throws Exception
+ {
+ Map<String, Object> saslData = getRestTestHelper().getJsonAsMap("/rest/sasl");
+ assertNotNull("mechanisms attribute is not found", saslData.get("mechanisms"));
+
+ @SuppressWarnings("unchecked")
+ List<String> mechanisms = (List<String>) saslData.get("mechanisms");
+ String[] expectedMechanisms = { "AMQPLAIN", "PLAIN", "CRAM-MD5" };
+ for (String mechanism : expectedMechanisms)
+ {
+ assertTrue("Mechanism " + mechanism + " is not found", mechanisms.contains(mechanism));
+ }
+ }
+
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/StructureRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/StructureRestTest.java
new file mode 100644
index 0000000000..30433fb40a
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/StructureRestTest.java
@@ -0,0 +1,115 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.rest;
+
+import java.util.List;
+import java.util.Map;
+
+public class StructureRestTest extends QpidRestTestCase
+{
+
+ public void testGet() throws Exception
+ {
+ Map<String, Object> structure = getRestTestHelper().getJsonAsMap("/rest/structure");
+ assertNotNull("Structure data cannot be null", structure);
+ assertNode(structure, "Broker");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> virtualhosts = (List<Map<String, Object>>) structure.get("virtualhosts");
+ assertEquals("Unexpected number of virtual hosts", 3, virtualhosts.size());
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> ports = (List<Map<String, Object>>) structure.get("ports");
+ assertEquals("Unexpected number of ports", 2, ports.size());
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> providers = (List<Map<String, Object>>) structure.get("authenticationproviders");
+ assertEquals("Unexpected number of authentication providers", 1, providers.size());
+
+ for (String hostName : EXPECTED_VIRTUALHOSTS)
+ {
+ Map<String, Object> host = getRestTestHelper().find("name", hostName, virtualhosts);
+ assertNotNull("Host " + hostName + " is not found ", host);
+ assertNode(host, hostName);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) host.get("queues");
+ assertNotNull("Host " + hostName + " queues are not found ", queues);
+ for (String queueName : EXPECTED_QUEUES)
+ {
+ Map<String, Object> queue = getRestTestHelper().find("name", queueName, queues);
+ assertNotNull(hostName + " queue " + queueName + " is not found ", queue);
+ assertNode(queue, queueName);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> bindings = (List<Map<String, Object>>) queue.get("bindings");
+ assertNotNull(hostName + " queue " + queueName + " bindings are not found ", queues);
+ for (Map<String, Object> binding : bindings)
+ {
+ assertNode(binding, queueName);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> exchanges = (List<Map<String, Object>>) host.get("exchanges");
+ assertNotNull("Host " + hostName + " exchanges are not found ", exchanges);
+ for (String exchangeName : EXPECTED_EXCHANGES)
+ {
+ Map<String, Object> exchange = getRestTestHelper().find("name", exchangeName, exchanges);
+ assertNotNull("Exchange " + exchangeName + " is not found ", exchange);
+ assertNode(exchange, exchangeName);
+ if ("amq.direct".equalsIgnoreCase(exchangeName) || "<<default>>".equalsIgnoreCase(exchangeName))
+ {
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> bindings = (List<Map<String, Object>>) exchange.get("bindings");
+ assertNotNull(hostName + " exchange " + exchangeName + " bindings are not found ", bindings);
+ for (String queueName : EXPECTED_QUEUES)
+ {
+ Map<String, Object> binding = getRestTestHelper().find("name", queueName, bindings);
+ assertNotNull(hostName + " exchange " + exchangeName + " binding " + queueName + " is not found", binding);
+ assertNode(binding, queueName);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> aliases = (List<Map<String, Object>>) host.get("virtualhostaliases");
+ assertNotNull("Host " + hostName + " aliaces are not found ", aliases);
+ assertEquals("Unexpected aliaces size", 1, aliases.size());
+ assertNode(aliases.get(0), hostName);
+ }
+
+ int[] expectedPorts = { getPort(), getRestTestHelper().getHttpPort() };
+ for (int port : expectedPorts)
+ {
+ String portName = "0.0.0.0:" + port;
+ Map<String, Object> portData = getRestTestHelper().find("name", portName, ports);
+ assertNotNull("Port " + portName + " is not found ", portData);
+ assertNode(portData, portName);
+ }
+ }
+
+ private void assertNode(Map<String, Object> node, String name)
+ {
+ assertEquals("Unexpected name", name, node.get("name"));
+ assertNotNull("Unexpected id", node.get("id"));
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/UserRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/UserRestTest.java
new file mode 100644
index 0000000000..159cd8e52d
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/UserRestTest.java
@@ -0,0 +1,97 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.rest;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.model.User;
+
+public class UserRestTest extends QpidRestTestCase
+{
+ @Override
+ public void setUp() throws Exception
+ {
+ getRestTestHelper().configureTemporaryPasswordFile(this, "user1", "user2");
+
+ super.setUp(); // do this last because it starts the broker, using the modified config
+ }
+
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> users = getRestTestHelper().getJsonAsList("/rest/user");
+ assertNotNull("Users cannot be null", users);
+ assertTrue("Unexpected number of users", users.size() > 1);
+ for (Map<String, Object> user : users)
+ {
+ assertUser(user);
+ }
+ }
+
+ public void testGetUserByName() throws Exception
+ {
+ List<Map<String, Object>> users = getRestTestHelper().getJsonAsList("/rest/user");
+ assertNotNull("Users cannot be null", users);
+ assertTrue("Unexpected number of users", users.size() > 1);
+ for (Map<String, Object> user : users)
+ {
+ assertNotNull("Attribute " + User.ID, user.get(User.ID));
+ String userName = (String) user.get(User.NAME);
+ assertNotNull("Attribute " + User.NAME, userName);
+ Map<String, Object> userDetails = getRestTestHelper().getJsonAsSingletonList("/rest/user/PrincipalDatabaseAuthenticationManager/"
+ + userName);
+ assertUser(userDetails);
+ assertEquals("Unexpected user name", userName, userDetails.get(User.NAME));
+ }
+ }
+
+ public void testPut() throws Exception
+ {
+ String userName = getTestName();
+ getRestTestHelper().createOrUpdateUser(userName, "newPassword");
+
+ Map<String, Object> userDetails = getRestTestHelper().getJsonAsSingletonList("/rest/user/PrincipalDatabaseAuthenticationManager/"
+ + userName);
+ assertUser(userDetails);
+ assertEquals("Unexpected user name", userName, userDetails.get(User.NAME));
+ }
+
+ public void testDelete() throws Exception
+ {
+ String userName = getTestName();
+ getRestTestHelper().createOrUpdateUser(userName, "newPassword");
+
+ Map<String, Object> userDetails = getRestTestHelper().getJsonAsSingletonList("/rest/user/PrincipalDatabaseAuthenticationManager/"
+ + userName);
+ String id = (String) userDetails.get(User.ID);
+
+ getRestTestHelper().removeUserById(id);
+
+ List<Map<String, Object>> users = getRestTestHelper().getJsonAsList("/rest/user/PrincipalDatabaseAuthenticationManager/" + userName);
+ assertEquals("User should be deleted", 0, users.size());
+ }
+
+ private void assertUser(Map<String, Object> user)
+ {
+ assertNotNull("Attribute " + User.ID, user.get(User.ID));
+ assertNotNull("Attribute " + User.NAME, user.get(User.NAME));
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java
new file mode 100644
index 0000000000..5b8c3fce33
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/VirtualHostRestTest.java
@@ -0,0 +1,434 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.rest;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jms.Session;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.server.model.Exchange;
+import org.apache.qpid.server.model.Queue;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.queue.AMQQueueFactory;
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.map.JsonMappingException;
+
+public class VirtualHostRestTest extends QpidRestTestCase
+{
+ private static final String VIRTUALHOST_EXCHANGES_ATTRIBUTE = "exchanges";
+ public static final String VIRTUALHOST_QUEUES_ATTRIBUTE = "queues";
+ public static final String VIRTUALHOST_CONNECTIONS_ATTRIBUTE = "connections";
+
+ private AMQConnection _connection;
+
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> hosts = getRestTestHelper().getJsonAsList("/rest/virtualhost/");
+ assertNotNull("Hosts data cannot be null", hosts);
+ assertEquals("Unexpected number of hosts", EXPECTED_VIRTUALHOSTS.length, hosts.size());
+ for (String hostName : EXPECTED_VIRTUALHOSTS)
+ {
+ Map<String, Object> host = getRestTestHelper().find("name", hostName, hosts);
+ Asserts.assertVirtualHost(hostName, host);
+ }
+ }
+
+ public void testGetHost() throws Exception
+ {
+ // create AMQP connection to get connection JSON details
+ _connection = (AMQConnection) getConnection();
+ _connection.createSession(true, Session.SESSION_TRANSACTED);
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
+ Asserts.assertVirtualHost("test", hostDetails);
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> statistics = (Map<String, Object>) hostDetails.get(Asserts.STATISTICS_ATTRIBUTE);
+ assertEquals("Unexpected number of exchanges in statistics", EXPECTED_EXCHANGES.length, statistics.get(VirtualHost.EXCHANGE_COUNT));
+ assertEquals("Unexpected number of queues in statistics", EXPECTED_QUEUES.length, statistics.get(VirtualHost.QUEUE_COUNT));
+ assertEquals("Unexpected number of connections in statistics", 1, statistics.get(VirtualHost.CONNECTION_COUNT));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> exchanges = (List<Map<String, Object>>) hostDetails.get(VIRTUALHOST_EXCHANGES_ATTRIBUTE);
+ assertEquals("Unexpected number of exchanges", EXPECTED_EXCHANGES.length, exchanges.size());
+ Asserts.assertDurableExchange("amq.fanout", "fanout", getRestTestHelper().find(Exchange.NAME, "amq.fanout", exchanges));
+ Asserts.assertDurableExchange("amq.topic", "topic", getRestTestHelper().find(Exchange.NAME, "amq.topic", exchanges));
+ Asserts.assertDurableExchange("amq.direct", "direct", getRestTestHelper().find(Exchange.NAME, "amq.direct", exchanges));
+ Asserts.assertDurableExchange("amq.match", "headers", getRestTestHelper().find(Exchange.NAME, "amq.match", exchanges));
+ Asserts.assertDurableExchange("<<default>>", "direct", getRestTestHelper().find(Exchange.NAME, "<<default>>", exchanges));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VIRTUALHOST_QUEUES_ATTRIBUTE);
+ assertEquals("Unexpected number of queues", EXPECTED_QUEUES.length, queues.size());
+ Map<String, Object> queue = getRestTestHelper().find(Queue.NAME, "queue", queues);
+ Map<String, Object> ping = getRestTestHelper().find(Queue.NAME, "ping", queues);
+ Asserts.assertQueue("queue", "standard", queue);
+ Asserts.assertQueue("ping", "standard", ping);
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.FALSE, queue.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.FALSE, ping.get(Queue.DURABLE));
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> connections = (List<Map<String, Object>>) hostDetails
+ .get(VIRTUALHOST_CONNECTIONS_ATTRIBUTE);
+ assertEquals("Unexpected number of connections", 1, connections.size());
+ Asserts.assertConnection(connections.get(0), _connection);
+ }
+
+ public void testPutCreateQueue() throws Exception
+ {
+ String queueName = getTestQueueName();
+
+ createQueue(queueName + "-standard", "standard", null);
+
+ Map<String, Object> sortedQueueAttributes = new HashMap<String, Object>();
+ sortedQueueAttributes.put(Queue.SORT_KEY, "sortme");
+ createQueue(queueName + "-sorted", "sorted", sortedQueueAttributes);
+
+ Map<String, Object> priorityQueueAttributes = new HashMap<String, Object>();
+ priorityQueueAttributes.put(Queue.PRIORITIES, 10);
+ createQueue(queueName + "-priority", "priority", priorityQueueAttributes);
+
+ Map<String, Object> lvqQueueAttributes = new HashMap<String, Object>();
+ lvqQueueAttributes.put(Queue.LVQ_KEY, "LVQ");
+ createQueue(queueName + "-lvq", "lvq", lvqQueueAttributes);
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> standardQueue = getRestTestHelper().find(Queue.NAME, queueName + "-standard" , queues);
+ Map<String, Object> sortedQueue = getRestTestHelper().find(Queue.NAME, queueName + "-sorted" , queues);
+ Map<String, Object> priorityQueue = getRestTestHelper().find(Queue.NAME, queueName + "-priority" , queues);
+ Map<String, Object> lvqQueue = getRestTestHelper().find(Queue.NAME, queueName + "-lvq" , queues);
+
+ Asserts.assertQueue(queueName + "-standard", "standard", standardQueue);
+ Asserts.assertQueue(queueName + "-sorted", "sorted", sortedQueue);
+ Asserts.assertQueue(queueName + "-priority", "priority", priorityQueue);
+ Asserts.assertQueue(queueName + "-lvq", "lvq", lvqQueue);
+
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, standardQueue.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, sortedQueue.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, priorityQueue.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, lvqQueue.get(Queue.DURABLE));
+
+ assertEquals("Unexpected sorted key attribute", "sortme", sortedQueue.get(Queue.SORT_KEY));
+ assertEquals("Unexpected lvq key attribute", "LVQ", lvqQueue.get(Queue.LVQ_KEY));
+ assertEquals("Unexpected priorities key attribute", 10, priorityQueue.get(Queue.PRIORITIES));
+ }
+
+ public void testPutCreateExchange() throws Exception
+ {
+ String exchangeName = getTestName();
+
+ createExchange(exchangeName + "-direct", "direct");
+ createExchange(exchangeName + "-topic", "topic");
+ createExchange(exchangeName + "-headers", "headers");
+ createExchange(exchangeName + "-fanout", "fanout");
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> exchanges = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_EXCHANGES_ATTRIBUTE);
+ Map<String, Object> directExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-direct" , exchanges);
+ Map<String, Object> topicExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-topic" , exchanges);
+ Map<String, Object> headersExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-headers" , exchanges);
+ Map<String, Object> fanoutExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-fanout" , exchanges);
+
+ Asserts.assertDurableExchange(exchangeName + "-direct", "direct", directExchange);
+ Asserts.assertDurableExchange(exchangeName + "-topic", "topic", topicExchange);
+ Asserts.assertDurableExchange(exchangeName + "-headers", "headers", headersExchange);
+ Asserts.assertDurableExchange(exchangeName + "-fanout", "fanout", fanoutExchange);
+
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, directExchange.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, topicExchange.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, headersExchange.get(Queue.DURABLE));
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, fanoutExchange.get(Queue.DURABLE));
+
+ }
+
+ public void testPutCreateLVQWithoutKey() throws Exception
+ {
+ String queueName = getTestQueueName()+ "-lvq";
+ createQueue(queueName, "lvq", null);
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> lvqQueue = getRestTestHelper().find(Queue.NAME, queueName , queues);
+
+ Asserts.assertQueue(queueName , "lvq", lvqQueue);
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, lvqQueue.get(Queue.DURABLE));
+ assertEquals("Unexpected lvq key attribute", AMQQueueFactory.QPID_LVQ_KEY, lvqQueue.get(Queue.LVQ_KEY));
+ }
+
+ public void testPutCreateSortedQueueWithoutKey() throws Exception
+ {
+ String queueName = getTestQueueName() + "-sorted";
+ int responseCode = tryCreateQueue(queueName, "sorted", null);
+ assertEquals("Unexpected response code", HttpServletResponse.SC_CONFLICT, responseCode);
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> testQueue = getRestTestHelper().find(Queue.NAME, queueName , queues);
+
+ assertNull("Sorted queue without a key was created ", testQueue);
+ }
+
+ public void testPutCreatePriorityQueueWithoutKey() throws Exception
+ {
+ String queueName = getTestQueueName()+ "-priority";
+ createQueue(queueName, "priority", null);
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> priorityQueue = getRestTestHelper().find(Queue.NAME, queueName , queues);
+
+ Asserts.assertQueue(queueName , "priority", priorityQueue);
+ assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, priorityQueue.get(Queue.DURABLE));
+ assertEquals("Unexpected number of priorities", 10, priorityQueue.get(Queue.PRIORITIES));
+ }
+
+ public void testPutCreateStandardQueueWithoutType() throws Exception
+ {
+ String queueName = getTestQueueName();
+ createQueue(queueName, null, null);
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> queue = getRestTestHelper().find(Queue.NAME, queueName , queues);
+
+ Asserts.assertQueue(queueName , "standard", queue);
+ }
+
+ public void testPutCreateQueueOfUnsupportedType() throws Exception
+ {
+ String queueName = getTestQueueName();
+ int responseCode = tryCreateQueue(queueName, "unsupported", null);
+ assertEquals("Unexpected response code", HttpServletResponse.SC_CONFLICT, responseCode);
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> queue = getRestTestHelper().find(Queue.NAME, queueName , queues);
+
+ assertNull("Queue of unsupported type was created", queue);
+ }
+
+ public void testDeleteQueue() throws Exception
+ {
+ String queueName = getTestQueueName();
+ createQueue(queueName, null, null);
+
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/queue/test/" + queueName, "DELETE");
+ connection.connect();
+ assertEquals("Unexpected response code", 200, connection.getResponseCode());
+ List<Map<String, Object>> queues = getRestTestHelper().getJsonAsList("/rest/queue/test/" + queueName);
+ assertEquals("Queue should be deleted", 0, queues.size());
+ }
+
+ public void testDeleteQueueById() throws Exception
+ {
+ String queueName = getTestQueueName();
+ createQueue(queueName, null, null);
+ Map<String, Object> queueDetails = getRestTestHelper().getJsonAsSingletonList("/rest/queue/test/" + queueName);
+
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/queue/test?id=" + queueDetails.get(Queue.ID), "DELETE");
+ connection.connect();
+ assertEquals("Unexpected response code", 200, connection.getResponseCode());
+ List<Map<String, Object>> queues = getRestTestHelper().getJsonAsList("/rest/queue/test/" + queueName);
+ assertEquals("Queue should be deleted", 0, queues.size());
+ }
+
+ public void testDeleteExchange() throws Exception
+ {
+ String exchangeName = getTestName();
+ createExchange(exchangeName, "direct");
+
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/exchange/test/" + exchangeName, "DELETE");
+ connection.connect();
+ assertEquals("Unexpected response code", 200, connection.getResponseCode());
+ List<Map<String, Object>> queues = getRestTestHelper().getJsonAsList("/rest/exchange/test/" + exchangeName);
+ assertEquals("Exchange should be deleted", 0, queues.size());
+ }
+
+ public void testDeleteExchangeById() throws Exception
+ {
+ String exchangeName = getTestName();
+ createExchange(exchangeName, "direct");
+ Map<String, Object> echangeDetails = getRestTestHelper().getJsonAsSingletonList("/rest/exchange/test/" + exchangeName);
+
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/exchange/test?id=" + echangeDetails.get(Exchange.ID), "DELETE");
+ connection.connect();
+ assertEquals("Unexpected response code", 200, connection.getResponseCode());
+ List<Map<String, Object>> queues = getRestTestHelper().getJsonAsList("/rest/exchange/test/" + exchangeName);
+ assertEquals("Exchange should be deleted", 0, queues.size());
+ }
+
+ public void testPutCreateQueueWithAttributes() throws Exception
+ {
+ String queueName = getTestQueueName();
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Queue.ALERT_REPEAT_GAP, 1000);
+ attributes.put(Queue.ALERT_THRESHOLD_MESSAGE_AGE, 3600000);
+ attributes.put(Queue.ALERT_THRESHOLD_MESSAGE_SIZE, 1000000000);
+ attributes.put(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, 800);
+ attributes.put(Queue.MAXIMUM_DELIVERY_ATTEMPTS, 15);
+ attributes.put(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 2000000000);
+ attributes.put(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 1500000000);
+
+ createQueue(queueName + "-standard", "standard", attributes);
+
+ Map<String, Object> sortedQueueAttributes = new HashMap<String, Object>();
+ sortedQueueAttributes.putAll(attributes);
+ sortedQueueAttributes.put(Queue.SORT_KEY, "sortme");
+ createQueue(queueName + "-sorted", "sorted", sortedQueueAttributes);
+
+ Map<String, Object> priorityQueueAttributes = new HashMap<String, Object>();
+ priorityQueueAttributes.putAll(attributes);
+ priorityQueueAttributes.put(Queue.PRIORITIES, 10);
+ createQueue(queueName + "-priority", "priority", priorityQueueAttributes);
+
+ Map<String, Object> lvqQueueAttributes = new HashMap<String, Object>();
+ lvqQueueAttributes.putAll(attributes);
+ lvqQueueAttributes.put(Queue.LVQ_KEY, "LVQ");
+ createQueue(queueName + "-lvq", "lvq", lvqQueueAttributes);
+
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ Map<String, Object> standardQueue = getRestTestHelper().find(Queue.NAME, queueName + "-standard" , queues);
+ Map<String, Object> sortedQueue = getRestTestHelper().find(Queue.NAME, queueName + "-sorted" , queues);
+ Map<String, Object> priorityQueue = getRestTestHelper().find(Queue.NAME, queueName + "-priority" , queues);
+ Map<String, Object> lvqQueue = getRestTestHelper().find(Queue.NAME, queueName + "-lvq" , queues);
+
+ attributes.put(Queue.DURABLE, Boolean.TRUE);
+ Asserts.assertQueue(queueName + "-standard", "standard", standardQueue, attributes);
+ Asserts.assertQueue(queueName + "-sorted", "sorted", sortedQueue, attributes);
+ Asserts.assertQueue(queueName + "-priority", "priority", priorityQueue, attributes);
+ Asserts.assertQueue(queueName + "-lvq", "lvq", lvqQueue, attributes);
+
+ assertEquals("Unexpected sorted key attribute", "sortme", sortedQueue.get(Queue.SORT_KEY));
+ assertEquals("Unexpected lvq key attribute", "LVQ", lvqQueue.get(Queue.LVQ_KEY));
+ assertEquals("Unexpected priorities key attribute", 10, priorityQueue.get(Queue.PRIORITIES));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testCreateQueueWithDLQEnabled() throws Exception
+ {
+ String queueName = getTestQueueName();
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(AMQQueueFactory.X_QPID_DLQ_ENABLED, true);
+
+ //verify the starting state
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
+ List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ List<Map<String, Object>> exchanges = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_EXCHANGES_ATTRIBUTE);
+
+ assertNull("queue should not have already been present", getRestTestHelper().find(Queue.NAME, queueName , queues));
+ assertNull("queue should not have already been present", getRestTestHelper().find(Queue.NAME, queueName + "_DLQ" , queues));
+ assertNull("exchange should not have already been present", getRestTestHelper().find(Exchange.NAME, queueName + "_DLE" , exchanges));
+
+ //create the queue
+ createQueue(queueName, "standard", attributes);
+
+ //verify the new queue, as well as the DLQueue and DLExchange have been created
+ hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
+ queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
+ exchanges = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_EXCHANGES_ATTRIBUTE);
+
+ Map<String, Object> queue = getRestTestHelper().find(Queue.NAME, queueName , queues);
+ Map<String, Object> dlqQueue = getRestTestHelper().find(Queue.NAME, queueName + "_DLQ" , queues);
+ Map<String, Object> dlExchange = getRestTestHelper().find(Exchange.NAME, queueName + "_DLE" , exchanges);
+ assertNotNull("queue should not have been present", queue);
+ assertNotNull("queue should not have been present", dlqQueue);
+ assertNotNull("exchange should not have been present", dlExchange);
+
+ //verify that the alternate exchange is set as expected on the new queue
+ Map<String, Object> queueAttributes = new HashMap<String, Object>();
+ queueAttributes.put(Queue.ALTERNATE_EXCHANGE, queueName + "_DLE");
+
+ Asserts.assertQueue(queueName, "standard", queue, queueAttributes);
+ Asserts.assertQueue(queueName, "standard", queue, null);
+ }
+
+ private void createExchange(String exchangeName, String exchangeType) throws IOException
+ {
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/exchange/test/" + exchangeName, "PUT");
+
+ Map<String, Object> queueData = new HashMap<String, Object>();
+ queueData.put(Exchange.NAME, exchangeName);
+ queueData.put(Exchange.DURABLE, Boolean.TRUE);
+ queueData.put(Exchange.TYPE, exchangeType);
+
+ getRestTestHelper().writeJsonRequest(connection, queueData);
+ assertEquals("Unexpected response code", 201, connection.getResponseCode());
+
+ connection.disconnect();
+ }
+
+ private void createQueue(String queueName, String queueType, Map<String, Object> attributes) throws IOException,
+ JsonGenerationException, JsonMappingException
+ {
+ int responseCode = tryCreateQueue(queueName, queueType, attributes);
+ assertEquals("Unexpected response code", 201, responseCode);
+ }
+
+ private int tryCreateQueue(String queueName, String queueType, Map<String, Object> attributes) throws IOException,
+ JsonGenerationException, JsonMappingException
+ {
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/queue/test/" + queueName, "PUT");
+
+ Map<String, Object> queueData = new HashMap<String, Object>();
+ queueData.put(Queue.NAME, queueName);
+ queueData.put(Queue.DURABLE, Boolean.TRUE);
+ if (queueType != null)
+ {
+ queueData.put(Queue.TYPE, queueType);
+ }
+ if (attributes != null)
+ {
+ queueData.putAll(attributes);
+ }
+
+ getRestTestHelper().writeJsonRequest(connection, queueData);
+ int responseCode = connection.getResponseCode();
+ connection.disconnect();
+ return responseCode;
+ }
+
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java
new file mode 100644
index 0000000000..7b8ad9141c
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java
@@ -0,0 +1,190 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.systest.rest.acl;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.server.security.acl.AbstractACLTestCase;
+import org.apache.qpid.systest.rest.QpidRestTestCase;
+
+public class GroupRestACLTest extends QpidRestTestCase
+{
+ private static final String FILE_GROUP_MANAGER = "FileGroupManager";
+
+ private static final String ALLOWED_GROUP = "allowedGroup";
+ private static final String DENIED_GROUP = "deniedGroup";
+ private static final String OTHER_GROUP = "otherGroup";
+
+ private static final String ALLOWED_USER = "webadmin";
+ private static final String DENIED_USER = "admin";
+ private static final String OTHER_USER = "admin";
+
+ private File _groupFile;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _groupFile = createTemporaryGroupFile();
+
+ setConfigurationProperty("management.http.basic-auth", "true");
+ setConfigurationProperty("security.file-group-manager.attributes.attribute.name", "groupFile");
+ setConfigurationProperty("security.file-group-manager.attributes.attribute.value", _groupFile.getAbsolutePath());
+
+ //DONT call super.setUp(), the tests will start the broker after configuring it
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ super.tearDown();
+
+ if (_groupFile != null)
+ {
+ if (_groupFile.exists())
+ {
+ _groupFile.delete();
+ }
+ }
+ }
+
+ private File createTemporaryGroupFile() throws Exception
+ {
+ File groupFile = File.createTempFile("group", "grp");
+ groupFile.deleteOnExit();
+
+ Properties props = new Properties();
+ props.put(ALLOWED_GROUP + ".users", ALLOWED_USER);
+ props.put(DENIED_GROUP + ".users", DENIED_USER);
+ props.put(OTHER_GROUP + ".users", OTHER_USER);
+
+ props.store(new FileOutputStream(groupFile), "test group file");
+
+ return groupFile;
+ }
+
+ public void testCreateGroup() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, null,
+ "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " CREATE GROUP",
+ "ACL DENY-LOG " + DENIED_GROUP + " CREATE GROUP");
+
+ //Start the broker with the custom config
+ super.setUp();
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ getRestTestHelper().assertNumberOfGroups(data, 3);
+
+ getRestTestHelper().createGroup("newGroup", FILE_GROUP_MANAGER);
+
+ data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ getRestTestHelper().assertNumberOfGroups(data, 4);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ getRestTestHelper().createGroup("anotherNewGroup", FILE_GROUP_MANAGER, HttpServletResponse.SC_FORBIDDEN);
+
+ data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ getRestTestHelper().assertNumberOfGroups(data, 4);
+ }
+
+ public void testDeleteGroup() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, null,
+ "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " DELETE GROUP",
+ "ACL DENY-LOG " + DENIED_GROUP + " DELETE GROUP");
+
+ //Start the broker with the custom config
+ super.setUp();
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ getRestTestHelper().assertNumberOfGroups(data, 3);
+
+ getRestTestHelper().removeGroup(OTHER_GROUP, FILE_GROUP_MANAGER, HttpServletResponse.SC_FORBIDDEN);
+
+ data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ getRestTestHelper().assertNumberOfGroups(data, 3);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ getRestTestHelper().removeGroup(OTHER_GROUP, FILE_GROUP_MANAGER);
+
+ data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ getRestTestHelper().assertNumberOfGroups(data, 2);
+ }
+
+ public void testUpdateGroupAddMember() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, null,
+ "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " UPDATE GROUP",
+ "ACL DENY-LOG " + DENIED_GROUP + " UPDATE GROUP");
+
+ //Start the broker with the custom config
+ super.setUp();
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ assertNumberOfGroupMembers(OTHER_GROUP, 1);
+
+ getRestTestHelper().createNewGroupMember(FILE_GROUP_MANAGER, OTHER_GROUP, "newGroupMember", HttpServletResponse.SC_FORBIDDEN);
+ assertNumberOfGroupMembers(OTHER_GROUP, 1);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ getRestTestHelper().createNewGroupMember(FILE_GROUP_MANAGER, OTHER_GROUP, "newGroupMember");
+ assertNumberOfGroupMembers(OTHER_GROUP, 2);
+ }
+
+ public void testUpdateGroupDeleteMember() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, null,
+ "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " UPDATE GROUP",
+ "ACL DENY-LOG " + DENIED_GROUP + " UPDATE GROUP");
+
+ //Start the broker with the custom config
+ super.setUp();
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ assertNumberOfGroupMembers(OTHER_GROUP, 1);
+
+ getRestTestHelper().removeMemberFromGroup(FILE_GROUP_MANAGER, OTHER_GROUP, OTHER_USER, HttpServletResponse.SC_FORBIDDEN);
+ assertNumberOfGroupMembers(OTHER_GROUP, 1);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ getRestTestHelper().removeMemberFromGroup(FILE_GROUP_MANAGER, OTHER_GROUP, OTHER_USER);
+ assertNumberOfGroupMembers(OTHER_GROUP, 0);
+ }
+
+ private void assertNumberOfGroupMembers(String groupName, int expectedNumberOfMembers) throws IOException
+ {
+ Map<String, Object> group = getRestTestHelper().getJsonAsSingletonList("/rest/group/FileGroupManager/" + groupName);
+ getRestTestHelper().assertNumberOfGroupMembers(group, expectedNumberOfMembers);
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java
new file mode 100644
index 0000000000..c02dc804db
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java
@@ -0,0 +1,192 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.systest.rest.acl;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.server.security.acl.AbstractACLTestCase;
+import org.apache.qpid.systest.rest.QpidRestTestCase;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+
+public class UserRestACLTest extends QpidRestTestCase
+{
+ private static final String ALLOWED_GROUP = "allowedGroup";
+ private static final String DENIED_GROUP = "deniedGroup";
+ private static final String OTHER_GROUP = "otherGroup";
+
+ private static final String ALLOWED_USER = "webadmin";
+ private static final String DENIED_USER = "admin";
+ private static final String OTHER_USER = "other";
+
+ private File _groupFile;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _groupFile = createTemporaryGroupFile();
+
+ setConfigurationProperty("management.http.basic-auth", "true");
+ setConfigurationProperty("security.file-group-manager.attributes.attribute.name", "groupFile");
+ setConfigurationProperty("security.file-group-manager.attributes.attribute.value", _groupFile.getAbsolutePath());
+
+ getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER, OTHER_USER);
+
+ //DONT call super.setUp(), the tests will start the broker after configuring it
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ super.tearDown();
+
+ if (_groupFile != null)
+ {
+ if (_groupFile.exists())
+ {
+ _groupFile.delete();
+ }
+ }
+ }
+
+ private File createTemporaryGroupFile() throws Exception
+ {
+ File groupFile = File.createTempFile("group", "grp");
+ groupFile.deleteOnExit();
+
+ Properties props = new Properties();
+ props.put(ALLOWED_GROUP + ".users", ALLOWED_USER);
+ props.put(DENIED_GROUP + ".users", DENIED_USER);
+ props.put(OTHER_GROUP + ".users", OTHER_USER);
+
+ props.store(new FileOutputStream(groupFile), "test group file");
+
+ return groupFile;
+ }
+
+ public void testAddUser() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, null,
+ "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " CREATE USER",
+ "ACL DENY-LOG " + DENIED_GROUP + " CREATE USER");
+
+ //Start the broker with the custom config
+ super.setUp();
+
+ String newUser = "newUser";
+ String password = "password";
+
+ assertUserDoesNotExist(newUser);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ getRestTestHelper().createOrUpdateUser(newUser, password, HttpServletResponse.SC_FORBIDDEN);
+ assertUserDoesNotExist(newUser);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ getRestTestHelper().createOrUpdateUser(newUser, password);
+ assertUserExists(newUser);
+ }
+
+ public void testDeleteUser() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, null,
+ "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " DELETE USER",
+ "ACL DENY-LOG " + DENIED_GROUP + " DELETE USER");
+
+ //Start the broker with the custom config
+ super.setUp();
+
+ assertUserExists(OTHER_USER);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ getRestTestHelper().removeUser(OTHER_USER, HttpServletResponse.SC_FORBIDDEN);
+ assertUserExists(OTHER_USER);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ getRestTestHelper().removeUser(OTHER_USER);
+ assertUserDoesNotExist(OTHER_USER);
+ }
+
+ public void testUpdateUser() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, null,
+ "ACL ALLOW-LOG ALL ACCESS MANAGEMENT",
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " UPDATE USER",
+ "ACL DENY-LOG " + DENIED_GROUP + " UPDATE USER");
+
+ //Start the broker with the custom config
+ super.setUp();
+
+ String newPassword = "newPassword";
+
+ checkPassword(OTHER_USER, OTHER_USER, true);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ getRestTestHelper().createOrUpdateUser(OTHER_USER, newPassword, HttpServletResponse.SC_FORBIDDEN);
+
+ checkPassword(OTHER_USER, newPassword, false);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ getRestTestHelper().createOrUpdateUser(OTHER_USER, newPassword, HttpServletResponse.SC_OK); // expect SC_OK rather than the default SC_CREATED
+
+ checkPassword(OTHER_USER, newPassword, true);
+ checkPassword(OTHER_USER, OTHER_USER, false);
+ }
+
+ private void checkPassword(String username, String password, boolean passwordExpectedToBeCorrect) throws IOException
+ {
+ getRestTestHelper().setUsernameAndPassword(username, password);
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/user/PrincipalDatabaseAuthenticationManager/", "GET");
+
+ boolean passwordIsCorrect = connection.getResponseCode() == HttpServletResponse.SC_OK;
+
+ connection.disconnect();
+
+ assertEquals(passwordExpectedToBeCorrect, passwordIsCorrect);
+ }
+
+ private void assertUserDoesNotExist(String newUser) throws JsonParseException, JsonMappingException, IOException
+ {
+ String path = "/rest/user/PrincipalDatabaseAuthenticationManager/" + newUser;
+ List<Map<String, Object>> userDetailsList = getRestTestHelper().getJsonAsList(path);
+ assertTrue(userDetailsList.isEmpty());
+ }
+
+ private void assertUserExists(String username) throws IOException
+ {
+ String path = "/rest/user/PrincipalDatabaseAuthenticationManager/" + username;
+ Map<String, Object> userDetails = getRestTestHelper().getJsonAsSingletonList(path);
+
+ assertEquals(
+ "User returned by " + path + " should have name=" + username + ". The returned JSON was: " + userDetails,
+ username,
+ userDetails.get("name"));
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java
index 673fdde97d..1891231f8c 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java
@@ -24,7 +24,6 @@ import junit.framework.TestCase;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.qpid.management.common.JMXConnnectionFactory;
-import org.apache.qpid.management.common.mbeans.ConfigurationManagement;
import org.apache.qpid.management.common.mbeans.LoggingManagement;
import org.apache.qpid.management.common.mbeans.ManagedBroker;
import org.apache.qpid.management.common.mbeans.ManagedConnection;
@@ -384,12 +383,6 @@ public class JMXTestUtils
return getManagedObject(LoggingManagement.class, objectName);
}
- public ConfigurationManagement getConfigurationManagement() throws MalformedObjectNameException
- {
- ObjectName objectName = new ObjectName("org.apache.qpid:type=ConfigurationManagement,name=ConfigurationManagement");
- return getManagedObject(ConfigurationManagement.class, objectName);
- }
-
public UserManagement getUserManagement() throws MalformedObjectNameException
{
ObjectName objectName = new ObjectName("org.apache.qpid:type=UserManagement,name=UserManagement");
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java
index ec2607a621..4da3baaf73 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java
@@ -57,7 +57,6 @@ import org.apache.qpid.client.AMQTopic;
import org.apache.qpid.exchange.ExchangeDefaults;
import org.apache.qpid.jms.BrokerDetails;
import org.apache.qpid.jms.ConnectionURL;
-import org.apache.qpid.management.common.mbeans.ConfigurationManagement;
import org.apache.qpid.server.Broker;
import org.apache.qpid.server.BrokerOptions;
import org.apache.qpid.server.ProtocolExclusion;
@@ -68,7 +67,6 @@ import org.apache.qpid.server.store.MessageStoreConstants;
import org.apache.qpid.server.store.derby.DerbyMessageStore;
import org.apache.qpid.url.URLSyntaxException;
import org.apache.qpid.util.FileUtils;
-import org.apache.qpid.util.LogMonitor;
/**
* Qpid base class for system testing test cases.
@@ -1385,31 +1383,6 @@ public class QpidBrokerTestCase extends QpidTestCase
return null;
}
- /**
- * Reloads the broker security configuration using the ApplicationRegistry (InVM brokers) or the
- * ConfigurationManagementMBean via the JMX interface (Standalone brokers, management must be
- * enabled before calling the method).
- */
- public void reloadBrokerSecurityConfig() throws Exception
- {
- JMXTestUtils jmxu = new JMXTestUtils(this);
- jmxu.open();
-
- try
- {
- ConfigurationManagement configMBean = jmxu.getConfigurationManagement();
- configMBean.reloadSecurityConfiguration();
- }
- finally
- {
- jmxu.close();
- }
-
- LogMonitor _monitor = new LogMonitor(_outputFile);
- assertTrue("The expected server security configuration reload did not occur",
- _monitor.waitForMessage(ServerConfiguration.SECURITY_CONFIG_RELOADED, LOGMONITOR_TIMEOUT));
- }
-
protected int getFailingPort()
{
return FAILING_PORT;
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestSSLConstants.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestSSLConstants.java
new file mode 100644
index 0000000000..19c9b9fb17
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestSSLConstants.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.test.utils;
+
+public interface TestSSLConstants
+{
+ String KEYSTORE = "test-profiles/test_resources/ssl/java_client_keystore.jks";
+ String KEYSTORE_PASSWORD = "password";
+ String TRUSTSTORE = "test-profiles/test_resources/ssl/java_client_truststore.jks";
+ String TRUSTSTORE_PASSWORD = "password";
+}