// // Copyright 2010 Cinch Logic Pty Ltd. // // http://www.chililog.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package org.chililog.server.engine; import static org.junit.Assert.*; import java.util.Date; import java.util.HashMap; import java.util.regex.Pattern; import org.chililog.client.stomp.Client; import org.chililog.client.stomp.TestListener; import org.chililog.server.common.AppProperties; import org.chililog.server.common.Log4JLogger; import org.chililog.server.data.MongoConnection; import org.chililog.server.data.UserBO; import org.chililog.server.data.UserController; import org.chililog.server.engine.MqService; import org.hornetq.api.core.HornetQBuffer; import org.hornetq.api.core.HornetQException; import org.hornetq.api.core.Message; import org.hornetq.api.core.SimpleString; import org.hornetq.api.core.TransportConfiguration; import org.hornetq.api.core.client.ClientConsumer; import org.hornetq.api.core.client.ClientMessage; import org.hornetq.api.core.client.ClientProducer; import org.hornetq.api.core.client.ClientSession; import org.hornetq.api.core.client.ClientSession.QueueQuery; import org.hornetq.api.core.client.ClientSessionFactory; import org.hornetq.api.core.client.HornetQClient; import org.hornetq.api.core.client.ServerLocator; import org.hornetq.api.core.management.HornetQServerControl; import org.hornetq.core.remoting.impl.invm.InVMConnectorFactory; import org.hornetq.core.remoting.impl.netty.NettyConnectorFactory; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import com.mongodb.BasicDBObject; import com.mongodb.DB; import com.mongodb.DBCollection; import com.mongodb.DBObject; /** * Test case for HornetQ integration for different transports * * @author vibul * */ public class MqServiceTransportTest { private static Log4JLogger _logger = Log4JLogger.getLogger(MqServiceTransportTest.class); private static DB _db; private static final String PUBLISHER_USERNAME = "MqManagerTransportTest.publisher"; private static final String PUBLISHER_PASSWORD = "pw4publisher!"; private static final String PUBLISHER_ROLE = "publisher"; private static final String SUBSCRIBER_USERNAME = "MqManagerTransportTest.subscriber"; private static final String SUBSCRIBER_PASSWORD = "pw4subscriber!"; private static final String SUBSCRIBER_ROLE = "subscriber"; private static final String SYSTEM_USERNAME = AppProperties.getInstance().getMqSystemUsername(); private static final String SYSTEM_PASSWORD = AppProperties.getInstance().getMqSystemPassword(); private static final String SYSTEM_ROLE = UserBO.SYSTEM_ADMINISTRATOR_ROLE_NAME; private static ClientSessionFactory _inVmClientSessionFactory; private static ClientSessionFactory _coreClientSessionFactory; @BeforeClass public static void classSetup() throws Exception { _db = MongoConnection.getInstance().getConnection(); // Clean up old test data if any exists DBCollection coll = _db.getCollection(UserController.MONGODB_COLLECTION_NAME); Pattern pattern = Pattern.compile("^MqManagerTransportTest\\.[\\w]*$"); DBObject query = new BasicDBObject(); query.put("username", pattern); coll.remove(query); UserBO user = new UserBO(); user.setUsername(PUBLISHER_USERNAME); user.setPassword(PUBLISHER_PASSWORD, true); user.addRole(PUBLISHER_ROLE); UserController.getInstance().save(_db, user); user = new UserBO(); user.setUsername(SUBSCRIBER_USERNAME); user.setPassword(SUBSCRIBER_PASSWORD, true); user.addRole(SUBSCRIBER_ROLE); UserController.getInstance().save(_db, user); // Start mq MqService.getInstance().start(); // Configure security HornetQServerControl hqControl = MqService.getInstance().getNativeServer().getHornetQServerControl(); hqControl.addSecuritySettings("MqTransportTest#", PUBLISHER_ROLE, SUBSCRIBER_ROLE, SYSTEM_ROLE + "," + SUBSCRIBER_ROLE, SYSTEM_ROLE, SYSTEM_ROLE + "," + SUBSCRIBER_ROLE, SYSTEM_ROLE, SYSTEM_ROLE); MqService.getInstance().getNativeServer().getConfiguration().setSecurityEnabled(true); // IN VM connector ServerLocator sl = HornetQClient.createServerLocatorWithoutHA(new TransportConfiguration( InVMConnectorFactory.class.getName())); _inVmClientSessionFactory = sl.createSessionFactory(); // Remote Core connector for access over TCP/IP ServerLocator sl2 = HornetQClient.createServerLocatorWithoutHA(new TransportConfiguration( NettyConnectorFactory.class.getName())); _coreClientSessionFactory = sl2.createSessionFactory(); } @AfterClass public static void classTeardown() throws Exception { MqService.getInstance().stop(); // Clean up old test data if any exists DBCollection coll = _db.getCollection(UserController.MONGODB_COLLECTION_NAME); Pattern pattern = Pattern.compile("^MqManagerTransportTest\\.[\\w]*$"); DBObject query = new BasicDBObject(); query.put("username", pattern); coll.remove(query); } // TODO Bug in HornetQ means exception not thrown // @Test (expected=LoginException.class) public void testBassPassword_Stomp() throws Exception { new Client("localhost", 61613, "ser", "ser"); } /** * Test reading/writing * * @throws Exception */ public void testOK(ClientSessionFactory csf, String type) throws Exception { // ************************************ // Create queue OK // ************************************ // Create a core queue String queueAddress = "MqTransportTest" + type; String queueName = "MqTransportTest" + type; ClientSession coreSession = null; try { coreSession = csf.createSession(SYSTEM_USERNAME, SYSTEM_PASSWORD, false, false, false, false, csf .getServerLocator().getAckBatchSize()); coreSession.createQueue(queueAddress, queueName, true); // Make sure the queue is there QueueQuery q = coreSession.queueQuery(new SimpleString(queueAddress)); assertNotNull(q); assertEquals(queueAddress, q.getAddress().toString()); } finally { if (coreSession != null) { coreSession.close(); } } // Read/Write to queue ClientSession session = null; try { // ************************************ // Write OK // ************************************ // Create the session, and producer session = csf.createSession(PUBLISHER_USERNAME, PUBLISHER_PASSWORD, false, true, true, true, csf .getServerLocator().getAckBatchSize()); ClientProducer producer = session.createProducer(queueAddress); // Create and send a message ClientMessage message = session.createMessage(false); String msg = "Hello sent at " + new Date(); message.getBodyBuffer().writeNullableSimpleString(SimpleString.toSimpleString(msg)); producer.send(message); _logger.info("Sent TextMessage: " + msg); QueueQuery q = session.queueQuery(new SimpleString(queueAddress)); assertNotNull(q); assertEquals(queueAddress, q.getAddress().toString()); assertEquals(1, q.getMessageCount()); // ************************************ // Read FAIL // ************************************ // Should not be able to consume messages because we in the writer role try { ClientConsumer messageConsumer = session.createConsumer(queueName); messageConsumer.toString(); fail("Exception expected for failed read"); } catch (Exception ex) { // HornetQException[errorCode=105 message=Unable to validate user: MqTransportTestUser_Writer for check // type // CONSUME for address HornetQIntegrationTest] assertEquals(HornetQException.class.getName(), ex.getClass().getName()); assertEquals(105, ((HornetQException) ex).getCode()); } session.close(); // ************************************ // Write FAIL // ************************************ // Create the session, and producer session = csf.createSession(SUBSCRIBER_USERNAME, SUBSCRIBER_PASSWORD, false, false, false, true, csf .getServerLocator().getAckBatchSize()); // HornetQ throws error on server but it never makes it back to the client! // The only way to check is that there should only be 1 message in the queue after this producer = session.createProducer(queueAddress); message.putStringProperty("prop", "should error"); producer.send(message); producer.send(message); producer.send(message); q = session.queueQuery(new SimpleString(queueAddress)); assertNotNull(q); assertEquals(queueAddress, q.getAddress().toString()); assertEquals(1, q.getMessageCount()); // ************************************ // Read OK // ************************************ // Should be able to consume messages because we in the reader role ClientConsumer messageConsumer = session.createConsumer(queueName); session.start(); ClientMessage messageReceived = messageConsumer.receive(1000); String msg2 = messageReceived.getBodyBuffer().readNullableSimpleString().toString(); _logger.info("Received TextMessage: " + msg2); assertEquals(msg, msg2); // Should have no more messages messageReceived = messageConsumer.receive(1000); assertNull(messageReceived); } finally { if (session != null) { session.close(); } } } @Test public void testOK_InVM() throws Exception { testOK(_inVmClientSessionFactory, "invm"); } @Test public void testOK_Core() throws Exception { testOK(_coreClientSessionFactory, "core"); } /** * Write with STOMP and read with STOMP * * @throws Exception */ // Stomp no longer supported because of assumption of jms.topic queue name // @Test public void testOK_Stomp() throws Exception { // ************************************ // Create queue OK // ************************************ // Create a core queue String queueAddress = "MqTransportTestStomp"; String queueName = "MqTransportTestStomp"; ClientSession coreSession = null; try { coreSession = _inVmClientSessionFactory.createSession(SYSTEM_USERNAME, SYSTEM_PASSWORD, false, false, false, false, _inVmClientSessionFactory.getServerLocator().getAckBatchSize()); coreSession.createQueue(queueAddress, queueName, true); // Make sure the queue is there QueueQuery q = coreSession.queueQuery(new SimpleString(queueAddress)); assertNotNull(q); assertEquals(queueAddress, q.getAddress().toString()); } finally { if (coreSession != null) { coreSession.close(); } } // Read/Write to queue ClientSession session = null; try { // ************************************ // Write OK // ************************************ // Create the session, and producer TestListener errorListener = new TestListener(); Client c = new Client("localhost", 61613, PUBLISHER_USERNAME, PUBLISHER_PASSWORD); c.addErrorListener(errorListener); final String propName = "myprop"; String msg = "Hello sent at " + new Date(); HashMap<String, String> m = new HashMap<String, String>(); m.put(propName, msg); c.sendW(queueAddress, msg, m); _logger.info("Sent TextMessage: " + msg); // Create the session to check session = _inVmClientSessionFactory.createSession(PUBLISHER_USERNAME, PUBLISHER_PASSWORD, false, true, true, true, _inVmClientSessionFactory.getServerLocator().getAckBatchSize()); QueueQuery q = session.queueQuery(new SimpleString(queueAddress)); assertNotNull(q); assertEquals(queueAddress, q.getAddress().toString()); assertEquals(1, q.getMessageCount()); // ************************************ // Read FAIL // ************************************ // Should not be able to consume messages because we in the writer role c.subscribe(queueAddress); Thread.sleep(1000); assertTrue(errorListener.getLastMessageBody().contains( PUBLISHER_USERNAME + " doesn't have permission='CONSUME' on address MqTransportTestStomp")); session.close(); c.disconnect(); // ************************************ // Write FAIL // ************************************ // Create the session, and producer session = _inVmClientSessionFactory.createSession(SUBSCRIBER_USERNAME, SUBSCRIBER_PASSWORD, false, false, false, true, _inVmClientSessionFactory.getServerLocator().getAckBatchSize()); c = new Client("localhost", 61613, SUBSCRIBER_USERNAME, SUBSCRIBER_PASSWORD); c.addErrorListener(errorListener); c.send(queueAddress, "should error"); Thread.sleep(1000); assertTrue(errorListener.getLastMessageBody().contains( SUBSCRIBER_USERNAME + " doesn't have permission='SEND' on address MqTransportTestStomp")); q = session.queueQuery(new SimpleString(queueAddress)); assertNotNull(q); assertEquals(queueAddress, q.getAddress().toString()); assertEquals(1, q.getMessageCount()); // ************************************ // Read OK // ************************************ // Should not be able to consume messages because we in the writer role TestListener msgListener = new TestListener(); c.subscribe(queueAddress, msgListener); Thread.sleep(1000); assertEquals(msg, msgListener.getLastMessageBody()); } finally { if (session != null) { session.close(); } } } /** * Write with STOMP and read with CORE * * @throws Exception */ // Stomp no longer supported because of assumption of jms.topic queue name // @Test public void testOK_StompToCore() throws Exception { // ************************************ // Create queue OK // ************************************ // Create a core queue String queueAddress = "MqTransportTestStompToCore"; String queueName = "MqTransportTestStompToCore"; ClientSession coreSession = null; try { coreSession = _inVmClientSessionFactory.createSession(SYSTEM_USERNAME, SYSTEM_PASSWORD, false, false, false, false, _inVmClientSessionFactory.getServerLocator().getAckBatchSize()); coreSession.createQueue(queueAddress, queueName, true); // Make sure the queue is there QueueQuery q = coreSession.queueQuery(new SimpleString(queueAddress)); assertNotNull(q); assertEquals(queueAddress, q.getAddress().toString()); } finally { if (coreSession != null) { coreSession.close(); } } // Read/Write to queue ClientSession session = null; try { // ************************************ // Write OK // ************************************ // Create the session, and producer TestListener errorListener = new TestListener(); Client c = new Client("localhost", 61613, PUBLISHER_USERNAME, PUBLISHER_PASSWORD); c.addErrorListener(errorListener); final String propName = "myprop"; String msg = "Hello sent at " + new Date(); HashMap<String, String> m = new HashMap<String, String>(); m.put(propName, msg); c.sendW(queueAddress, msg, m); _logger.info("Sent TextMessage: " + msg); // Create the session to check session = _inVmClientSessionFactory.createSession(PUBLISHER_USERNAME, PUBLISHER_PASSWORD, false, true, true, true, _inVmClientSessionFactory.getServerLocator().getAckBatchSize()); QueueQuery q = session.queueQuery(new SimpleString(queueAddress)); assertNotNull(q); assertEquals(queueAddress, q.getAddress().toString()); assertEquals(1, q.getMessageCount()); // ************************************ // Write FAIL // ************************************ // Create the session, and producer session = _inVmClientSessionFactory.createSession(SUBSCRIBER_USERNAME, SUBSCRIBER_PASSWORD, false, false, false, true, _inVmClientSessionFactory.getServerLocator().getAckBatchSize()); // ************************************ // Read OK // ************************************ // Should be able to consume messages because we in the reader role ClientConsumer messageConsumer = session.createConsumer(queueName); session.start(); ClientMessage messageReceived = messageConsumer.receive(1000); HornetQBuffer buffer = messageReceived.getBodyBuffer(); // *** Fixed this error by correctly terminating stomp message with UTF8 null and not ASCII null *** // See Hornetq/trunk/src/main/org/hornetq/core/protocol/stomp/StompSession.java sendMessage() // This is used to send a stomp packet back to a stomp client // buffer.readerIndex(MessageImpl.BUFFER_HEADER_SPACE + DataConstants.SIZE_INT); SimpleString text = buffer.readNullableSimpleString(); String msg2 = text.toString(); _logger.info("Received TextMessage: " + msg2); assertEquals(msg, msg2); msg2 = messageReceived.getStringProperty(propName); assertEquals(msg, msg2); // Should have no more messages messageReceived = messageConsumer.receive(1000); assertNull(messageReceived); } finally { if (session != null) { session.close(); } } } /** * Write with CORE and read with STOMP. Must use NullalbeSimpleString to read/write messages * * @throws Exception */ // Stomp no longer supported because of assumption of jms.topic queue name // @Test public void testOK_CoreToStomp() throws Exception { // ************************************ // Create queue OK // ************************************ // Create a core queue String queueAddress = "MqTransportTestCoreToStomp"; String queueName = "MqTransportTestCoreToStomp"; ClientSession coreSession = null; try { coreSession = _inVmClientSessionFactory.createSession(SYSTEM_USERNAME, SYSTEM_PASSWORD, false, false, false, false, _inVmClientSessionFactory.getServerLocator().getAckBatchSize()); coreSession.createQueue(queueAddress, queueName, true); // Make sure the queue is there QueueQuery q = coreSession.queueQuery(new SimpleString(queueAddress)); assertNotNull(q); assertEquals(queueAddress, q.getAddress().toString()); } finally { if (coreSession != null) { coreSession.close(); } } // Read/Write to queue ClientSession session = null; try { // ************************************ // Write OK // ************************************ // Create the session, and producer session = _inVmClientSessionFactory.createSession(PUBLISHER_USERNAME, PUBLISHER_PASSWORD, false, true, true, true, _inVmClientSessionFactory.getServerLocator().getAckBatchSize()); ClientProducer producer = session.createProducer(queueAddress); // Create and send a message ClientMessage message = session.createMessage(Message.TEXT_TYPE, false); String msg = "Hello sent at " + new Date(); // *** This is the trick for interop - use NullableSimpleString *** // Stomp uses this for sending and subscribing to messages message.getBodyBuffer().writeNullableSimpleString(SimpleString.toSimpleString(msg)); producer.send(message); _logger.info("Sent TextMessage: " + msg); QueueQuery q = session.queueQuery(new SimpleString(queueAddress)); assertNotNull(q); assertEquals(queueAddress, q.getAddress().toString()); assertEquals(1, q.getMessageCount()); session.close(); // ************************************ // Read OK // ************************************ TestListener errorListener = new TestListener(); Client c = new Client("localhost", 61613, SUBSCRIBER_USERNAME, SUBSCRIBER_PASSWORD); c.addErrorListener(errorListener); // Should be able to read the message TestListener msgListener = new TestListener(); c.subscribe(queueAddress, msgListener); Thread.sleep(1000); assertEquals(msg, msgListener.getLastMessageBody()); } finally { if (session != null) { session.close(); } } } }