/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.transport.stomp;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.net.Socket;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import javax.jms.Connection;
import org.apache.activemq.broker.jmx.BrokerViewMBean;
import org.apache.activemq.util.Wait;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Stomp12Test extends StompTestSupport {
private static final Logger LOG = LoggerFactory.getLogger(Stomp12Test.class);
private Connection connection;
@Override
public void setUp() throws Exception {
super.setUp();
stompConnect();
connection = cf.createConnection("system", "manager");
connection.start();
}
@Override
public void tearDown() throws Exception {
try {
connection.close();
} catch (Exception ex) {}
super.tearDown();
}
@Override
protected Socket createSocket() throws IOException {
return new Socket("127.0.0.1", this.port);
}
@Override
protected String getQueueName() {
return getClass().getName() + "." + getName();
}
@Test(timeout = 60000)
public void testTelnetStyleSends() throws Exception {
stompConnection.setVersion(Stomp.V1_2);
String connect = "CONNECT\r\n" +
"accept-version:1.2\r\n" +
"login:system\r\n" +
"passcode:manager\r\n" +
"\r\n" +
"\u0000\r\n";
stompConnection.sendFrame(connect);
String f = stompConnection.receiveFrame();
LOG.info("Broker sent: " + f);
assertTrue(f.startsWith("CONNECTED"));
assertTrue(f.indexOf("version:1.2") >= 0);
assertTrue(f.indexOf("session:") >= 0);
String send = "SUBSCRIBE\r\n" +
"id:1\r\n" +
"destination:/queue/" + getQueueName() + "\r\n" +
"receipt:1\r\n" +
"\r\n"+
"\u0000\r\n";
stompConnection.sendFrame(send);
StompFrame receipt = stompConnection.receive();
LOG.info("Broker sent: " + receipt);
assertTrue(receipt.getAction().startsWith("RECEIPT"));
String receiptId = receipt.getHeaders().get("receipt-id");
assertEquals("1", receiptId);
}
@Test(timeout = 60000)
public void testClientAckWithoutAckId() throws Exception {
stompConnection.setVersion(Stomp.V1_2);
String connect = "STOMP\r\n" +
"accept-version:1.2\r\n" +
"login:system\r\n" +
"passcode:manager\r\n" +
"\r\n" +
"\u0000\r\n";
stompConnection.sendFrame(connect);
String f = stompConnection.receiveFrame();
LOG.info("Broker sent: " + f);
assertTrue(f.startsWith("CONNECTED"));
assertTrue(f.indexOf("version:1.2") >= 0);
assertTrue(f.indexOf("session:") >= 0);
String subscribe = "SUBSCRIBE\n" +
"id:1\n" +
"activemq.prefetchSize=1\n" +
"ack:client\n" +
"destination:/queue/" + getQueueName() + "\n" +
"receipt:1\n" +
"\n" + Stomp.NULL;
stompConnection.sendFrame(subscribe);
StompFrame receipt = stompConnection.receive();
LOG.info("Broker sent: " + receipt);
assertTrue(receipt.getAction().startsWith("RECEIPT"));
String receiptId = receipt.getHeaders().get("receipt-id");
assertEquals("1", receiptId);
String message = "SEND\n" + "destination:/queue/" + getQueueName() + "\n\n" + "1" + Stomp.NULL;
stompConnection.sendFrame(message);
StompFrame received = stompConnection.receive();
assertTrue(received.getAction().equals("MESSAGE"));
assertTrue(received.getHeaders().containsKey(Stomp.Headers.Message.ACK_ID));
assertEquals("1", received.getBody());
String frame = "ACK\n" + "message-id:" +
received.getHeaders().get(Stomp.Headers.Message.ACK_ID) + "\n\n" + Stomp.NULL;
stompConnection.sendFrame(frame);
received = stompConnection.receive();
assertTrue(received.getAction().equals("ERROR"));
LOG.info("Broker sent: " + received);
}
@Test(timeout = 60000)
public void testClientAck() throws Exception {
stompConnection.setVersion(Stomp.V1_2);
String connect = "STOMP\r\n" +
"accept-version:1.2\r\n" +
"login:system\r\n" +
"passcode:manager\r\n" +
"\r\n" +
"\u0000\r\n";
stompConnection.sendFrame(connect);
String f = stompConnection.receiveFrame();
LOG.info("Broker sent: " + f);
assertTrue(f.startsWith("CONNECTED"));
assertTrue(f.indexOf("version:1.2") >= 0);
assertTrue(f.indexOf("session:") >= 0);
String subscribe = "SUBSCRIBE\n" +
"id:1\n" +
"ack:client\n" +
"destination:/queue/" + getQueueName() + "\n" +
"receipt:1\n" +
"\n" + Stomp.NULL;
stompConnection.sendFrame(subscribe);
StompFrame receipt = stompConnection.receive();
LOG.info("Broker sent: " + receipt);
assertTrue(receipt.getAction().startsWith("RECEIPT"));
String receiptId = receipt.getHeaders().get("receipt-id");
assertEquals("1", receiptId);
String message = "SEND\n" + "destination:/queue/" + getQueueName() + "\n\n" + "1" + Stomp.NULL;
stompConnection.sendFrame(message);
message = "SEND\n" + "destination:/queue/" + getQueueName() + "\n\n" + "2" + Stomp.NULL;
stompConnection.sendFrame(message);
StompFrame received = stompConnection.receive();
LOG.info("Stomp Message: {}", received);
assertTrue(received.getAction().equals("MESSAGE"));
assertTrue(received.getHeaders().containsKey(Stomp.Headers.Message.ACK_ID));
assertEquals("1", received.getBody());
received = stompConnection.receive();
LOG.info("Stomp Message: {}", received);
assertTrue(received.getAction().equals("MESSAGE"));
assertTrue(received.getHeaders().containsKey(Stomp.Headers.Message.ACK_ID));
assertEquals("2", received.getBody());
String frame = "ACK\n" + "id:" +
received.getHeaders().get(Stomp.Headers.Message.ACK_ID) + "\n\n" + Stomp.NULL;
stompConnection.sendFrame(frame);
frame = "DISCONNECT\n\n" + Stomp.NULL;
stompConnection.sendFrame(frame);
assertTrue(Wait.waitFor(new Wait.Condition() {
@Override
public boolean isSatisified() throws Exception {
return getProxyToBroker().getCurrentConnectionsCount() == 1;
}
}, TimeUnit.SECONDS.toMillis(5), TimeUnit.MILLISECONDS.toMillis(25)));
// reconnect and send some messages to the offline subscribers and then try to get
// them after subscribing again.
stompConnect();
stompConnection.sendFrame(connect);
frame = stompConnection.receiveFrame();
LOG.debug("Broker sent: " + frame);
assertTrue(frame.startsWith("CONNECTED"));
stompConnection.sendFrame(subscribe);
receipt = stompConnection.receive();
LOG.info("Broker sent: " + receipt);
assertTrue(receipt.getAction().startsWith("RECEIPT"));
receiptId = receipt.getHeaders().get("receipt-id");
assertEquals("1", receiptId);
message = "SEND\n" + "destination:/queue/" + getQueueName() + "\n\n" + "3" + Stomp.NULL;
stompConnection.sendFrame(message);
received = stompConnection.receive();
LOG.info("Stomp Message: {}", received);
assertTrue(received.getAction().equals("MESSAGE"));
assertTrue(received.getHeaders().containsKey(Stomp.Headers.Message.ACK_ID));
assertEquals("3", received.getBody());
frame = "ACK\n" + "id:" +
received.getHeaders().get(Stomp.Headers.Message.ACK_ID) + "\n\n" + Stomp.NULL;
stompConnection.sendFrame(frame);
}
@Test(timeout = 60000)
public void testClientIndividualAck() throws Exception {
stompConnection.setVersion(Stomp.V1_2);
String connect = "STOMP\r\n" +
"accept-version:1.2\r\n" +
"login:system\r\n" +
"passcode:manager\r\n" +
"\r\n" +
"\u0000\r\n";
stompConnection.sendFrame(connect);
String f = stompConnection.receiveFrame();
LOG.info("Broker sent: " + f);
assertTrue(f.startsWith("CONNECTED"));
assertTrue(f.indexOf("version:1.2") >= 0);
assertTrue(f.indexOf("session:") >= 0);
String subscribe = "SUBSCRIBE\n" +
"id:1\n" +
"ack:client-individual\n" +
"destination:/queue/" + getQueueName() + "\n" +
"receipt:1\n" +
"\n" + Stomp.NULL;
stompConnection.sendFrame(subscribe);
StompFrame receipt = stompConnection.receive();
LOG.info("Broker sent: " + receipt);
assertTrue(receipt.getAction().startsWith("RECEIPT"));
String receiptId = receipt.getHeaders().get("receipt-id");
assertEquals("1", receiptId);
String message = "SEND\n" + "destination:/queue/" + getQueueName() + "\n\n" + "1" + Stomp.NULL;
stompConnection.sendFrame(message);
message = "SEND\n" + "destination:/queue/" + getQueueName() + "\n\n" + "2" + Stomp.NULL;
stompConnection.sendFrame(message);
StompFrame received = stompConnection.receive();
assertTrue(received.getAction().equals("MESSAGE"));
assertTrue(received.getHeaders().containsKey(Stomp.Headers.Message.ACK_ID));
assertEquals("1", received.getBody());
received = stompConnection.receive();
assertTrue(received.getAction().equals("MESSAGE"));
assertTrue(received.getHeaders().containsKey(Stomp.Headers.Message.ACK_ID));
assertEquals("2", received.getBody());
String frame = "ACK\n" + "id:" +
received.getHeaders().get(Stomp.Headers.Message.ACK_ID) + "\n\n" + Stomp.NULL;
stompConnection.sendFrame(frame);
frame = "DISCONNECT\n" + "\n\n" + Stomp.NULL;
stompConnection.sendFrame(frame);
Wait.waitFor(new Wait.Condition() {
@Override
public boolean isSatisified() throws Exception {
return getProxyToBroker().getCurrentConnectionsCount() <= 1;
}
}, TimeUnit.SECONDS.toMillis(5), TimeUnit.MILLISECONDS.toMillis(25));
// reconnect and send some messages to the offline subscribers and then try to get
// them after subscribing again.
stompConnect();
stompConnection.sendFrame(connect);
frame = stompConnection.receiveFrame();
LOG.debug("Broker sent: " + frame);
assertTrue(frame.startsWith("CONNECTED"));
stompConnection.sendFrame(subscribe);
receipt = stompConnection.receive();
LOG.info("Broker sent: " + receipt);
assertTrue(receipt.getAction().startsWith("RECEIPT"));
receiptId = receipt.getHeaders().get("receipt-id");
assertEquals("1", receiptId);
message = "SEND\n" + "destination:/queue/" + getQueueName() + "\n\n" + "3" + Stomp.NULL;
stompConnection.sendFrame(message);
received = stompConnection.receive();
assertTrue(received.getAction().equals("MESSAGE"));
assertTrue(received.getHeaders().containsKey(Stomp.Headers.Message.ACK_ID));
assertEquals("1", received.getBody());
frame = "ACK\n" + "id:" +
received.getHeaders().get(Stomp.Headers.Message.ACK_ID) + "\n\n" + Stomp.NULL;
stompConnection.sendFrame(frame);
received = stompConnection.receive();
assertTrue(received.getAction().equals("MESSAGE"));
assertTrue(received.getHeaders().containsKey(Stomp.Headers.Message.ACK_ID));
assertEquals("3", received.getBody());
frame = "ACK\n" + "id:" +
received.getHeaders().get(Stomp.Headers.Message.ACK_ID) + "\n\n" + Stomp.NULL;
stompConnection.sendFrame(frame);
}
@Test(timeout = 60000)
public void testQueueBrowerSubscription() throws Exception {
final int MSG_COUNT = 10;
String connectFrame = "STOMP\n" +
"login:system\n" +
"passcode:manager\n" +
"accept-version:1.2\n" +
"host:localhost\n" +
"\n" + Stomp.NULL;
stompConnection.sendFrame(connectFrame);
String f = stompConnection.receiveFrame();
LOG.debug("Broker sent: " + f);
assertTrue(f.startsWith("CONNECTED"));
for(int i = 0; i < MSG_COUNT; ++i) {
String message = "SEND\n" + "destination:/queue/" + getQueueName() + "\n" +
"receipt:0\n" +
"\n" + "Hello World {" + i + "}" + Stomp.NULL;
stompConnection.sendFrame(message);
StompFrame repsonse = stompConnection.receive();
assertEquals("0", repsonse.getHeaders().get(Stomp.Headers.Response.RECEIPT_ID));
}
String subscribe = "SUBSCRIBE\n" + "destination:/queue/" + getQueueName() + "\n" +
"id:12345\n" + "browser:true\n\n" + Stomp.NULL;
stompConnection.sendFrame(subscribe);
for(int i = 0; i < MSG_COUNT; ++i) {
StompFrame message = stompConnection.receive();
assertEquals(Stomp.Responses.MESSAGE, message.getAction());
assertEquals("12345", message.getHeaders().get(Stomp.Headers.Message.SUBSCRIPTION));
}
// We should now get a browse done message
StompFrame browseDone = stompConnection.receive();
LOG.debug("Browse Done: " + browseDone.toString());
assertEquals(Stomp.Responses.MESSAGE, browseDone.getAction());
assertEquals("12345", browseDone.getHeaders().get(Stomp.Headers.Message.SUBSCRIPTION));
assertEquals("end", browseDone.getHeaders().get(Stomp.Headers.Message.BROWSER));
assertTrue(browseDone.getHeaders().get(Stomp.Headers.Message.DESTINATION) != null);
String unsub = "UNSUBSCRIBE\n" + "destination:/queue/" + getQueueName() + "\n" +
"receipt:1\n" + "id:12345\n\n" + Stomp.NULL;
stompConnection.sendFrame(unsub);
StompFrame stompFrame = stompConnection.receive();
assertTrue(stompFrame.getAction().equals("RECEIPT"));
subscribe = "SUBSCRIBE\n" + "destination:/queue/" + getQueueName() + "\n" + "id:12345\n\n" + Stomp.NULL;
stompConnection.sendFrame(subscribe);
for(int i = 0; i < MSG_COUNT; ++i) {
StompFrame message = stompConnection.receive();
assertEquals(Stomp.Responses.MESSAGE, message.getAction());
assertEquals("12345", message.getHeaders().get(Stomp.Headers.Message.SUBSCRIPTION));
}
stompConnection.sendFrame(unsub);
}
@Test(timeout = 60000)
public void testQueueBrowerNotInAutoAckMode() throws Exception {
String connectFrame = "STOMP\n" +
"login:system\n" +
"passcode:manager\n" +
"accept-version:1.2\n" +
"host:localhost\n" +
"\n" + Stomp.NULL;
stompConnection.sendFrame(connectFrame);
String f = stompConnection.receiveFrame();
LOG.debug("Broker sent: " + f);
assertTrue(f.startsWith("CONNECTED"));
String subscribe = "SUBSCRIBE\n" + "destination:/queue/" + getQueueName() + "\n" +
"ack:client\n" + "id:12345\n" + "browser:true\n\n" + Stomp.NULL;
stompConnection.sendFrame(subscribe);
// We should now get a browse done message
StompFrame browseDone = stompConnection.receive();
LOG.debug("Browse Done: " + browseDone.toString());
assertEquals(Stomp.Responses.MESSAGE, browseDone.getAction());
assertEquals("12345", browseDone.getHeaders().get(Stomp.Headers.Message.SUBSCRIPTION));
assertEquals("end", browseDone.getHeaders().get(Stomp.Headers.Message.BROWSER));
assertTrue(browseDone.getHeaders().get(Stomp.Headers.Message.DESTINATION) != null);
String unsub = "UNSUBSCRIBE\n" + "destination:/queue/" + getQueueName() + "\n" +
"id:12345\n\n" + Stomp.NULL;
stompConnection.sendFrame(unsub);
}
@Test(timeout = 60000)
public void testDurableSubAndUnSub() throws Exception {
BrokerViewMBean view = getProxyToBroker();
String connectFrame = "STOMP\n" +
"login:system\n" +
"passcode:manager\n" +
"accept-version:1.2\n" +
"host:localhost\n" +
"client-id:durableSubTest\n" +
"\n" + Stomp.NULL;
stompConnection.sendFrame(connectFrame);
String frame = stompConnection.receiveFrame();
LOG.debug("Broker sent: " + frame);
assertTrue(frame.startsWith("CONNECTED"));
assertEquals(view.getDurableTopicSubscribers().length, 0);
// subscribe to destination durably
frame = "SUBSCRIBE\n" +
"destination:/topic/" + getQueueName() + "1" + "\n" +
"ack:auto\n" + "receipt:1\n" + "id:durablesub-1\n" +
"activemq.subscriptionName:test1\n\n" + Stomp.NULL;
stompConnection.sendFrame(frame);
StompFrame receipt = stompConnection.receive();
LOG.debug("Broker sent: " + receipt);
assertTrue(receipt.getAction().startsWith("RECEIPT"));
assertEquals("1", receipt.getHeaders().get("receipt-id"));
assertEquals(view.getDurableTopicSubscribers().length, 1);
frame = "DISCONNECT\nclient-id:test\n\n" + Stomp.NULL;
stompConnection.sendFrame(frame);
stompConnection.close();
Wait.waitFor(new Wait.Condition() {
@Override
public boolean isSatisified() throws Exception {
return getProxyToBroker().getCurrentConnectionsCount() <= 1;
}
}, TimeUnit.SECONDS.toMillis(5), TimeUnit.MILLISECONDS.toMillis(25));
stompConnect();
stompConnection.sendFrame(connectFrame);
frame = stompConnection.receiveFrame();
LOG.debug("Broker sent: " + frame);
assertTrue(frame.startsWith("CONNECTED"));
assertEquals(view.getDurableTopicSubscribers().length, 0);
assertEquals(view.getInactiveDurableTopicSubscribers().length, 1);
// unsubscribe from topic
frame = "UNSUBSCRIBE\n" + "destination:/topic/" + getQueueName() + "1\n" +
"id:durablesub-1\n" + "receipt:3\n" +
"activemq.subscriptionName:test1\n\n" + Stomp.NULL;
stompConnection.sendFrame(frame);
receipt = stompConnection.receive();
LOG.debug("Broker sent: " + frame);
assertTrue(receipt.getAction().startsWith("RECEIPT"));
assertEquals("3", receipt.getHeaders().get("receipt-id"));
assertEquals(view.getInactiveDurableTopicSubscribers().length, 0);
}
@Test(timeout = 60000)
public void testSubscribeWithNoId() throws Exception {
String connectFrame = "STOMP\n" +
"login:system\n" +
"passcode:manager\n" +
"accept-version:1.2\n" +
"host:localhost\n" +
"\n" + Stomp.NULL;
stompConnection.sendFrame(connectFrame);
String f = stompConnection.receiveFrame();
LOG.debug("Broker sent: " + f);
assertTrue(f.startsWith("CONNECTED"));
String frame = "SUBSCRIBE\n" + "destination:/queue/" + getQueueName() + "\n" +
"ack:auto\n\n" + Stomp.NULL;
stompConnection.sendFrame(frame);
frame = stompConnection.receiveFrame();
assertTrue(frame.startsWith("ERROR"));
}
@Test(timeout = 60000)
public void testSizeAndBrokerUsage() throws Exception {
final int MSG_COUNT = 10;
final int numK = 4;
final byte[] bigPropContent = new byte[numK*1024];
// fill so we don't fall foul to trimming in v<earlier than 1.2>
Arrays.fill(bigPropContent, Byte.MAX_VALUE);
final String bigProp = new String(bigPropContent);
String connectFrame = "STOMP\n" +
"login:system\n" +
"passcode:manager\n" +
"accept-version:1.2\n" +
"host:localhost\n" +
"\n" + Stomp.NULL;
stompConnection.sendFrame(connectFrame);
String f = stompConnection.receiveFrame();
LOG.debug("Broker sent: " + f);
assertTrue(f.startsWith("CONNECTED"));
long usageStart = brokerService.getSystemUsage().getMemoryUsage().getUsage();
for(int i = 0; i < MSG_COUNT; ++i) {
String message = "SEND\n" + "destination:/queue/" + getQueueName() + "\n" +
"receipt:0\n" +
"myXkProp:" + bigProp + "\n"+
"\n" + "Hello World {" + i + "}" + Stomp.NULL;
stompConnection.sendFrame(message);
StompFrame repsonse = stompConnection.receive();
LOG.info("response:" + repsonse);
assertEquals("0", repsonse.getHeaders().get(Stomp.Headers.Response.RECEIPT_ID));
}
// verify usage accounts for our numK
long usageEnd = brokerService.getSystemUsage().getMemoryUsage().getUsage();
long usageDiff = usageEnd - usageStart;
LOG.info("usageDiff:" + usageDiff);
assertTrue(usageDiff > MSG_COUNT * numK * 1024);
String subscribe = "SUBSCRIBE\n" + "destination:/queue/" + getQueueName() + "\n" +
"id:12345\n" + "browser:true\n\n" + Stomp.NULL;
stompConnection.sendFrame(subscribe);
for(int i = 0; i < MSG_COUNT; ++i) {
StompFrame message = stompConnection.receive();
assertEquals(Stomp.Responses.MESSAGE, message.getAction());
assertEquals("12345", message.getHeaders().get(Stomp.Headers.Message.SUBSCRIPTION));
}
}
}