Switched from Moquette's MQTT codec to Netty's MQTT codec ones

This commit is contained in:
andsel
2017-01-28 15:59:44 +01:00
parent 07093ab0cb
commit 1c64186a00
53 changed files with 1571 additions and 1048 deletions
+204
View File
@@ -0,0 +1,204 @@
/*
* Copyright (c) 2012-2017 The original author or authorsgetRockQuestions()
* ------------------------------------------------------
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/
package io.moquette;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.CorruptedFrameException;
import io.netty.handler.codec.mqtt.MqttMessage;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.AttributeMap;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
/**
*
* @author andrea
*/
public class Utils {
public static final int MAX_LENGTH_LIMIT = 268435455;
public static final byte VERSION_3_1 = 3;
public static final byte VERSION_3_1_1 = 4;
static byte readMessageType(ByteBuf in) {
byte h1 = in.readByte();
byte messageType = (byte) ((h1 & 0x00F0) >> 4);
return messageType;
}
static boolean checkHeaderAvailability(ByteBuf in) {
if (in.readableBytes() < 1) {
return false;
}
//byte h1 = in.get();
//byte messageType = (byte) ((h1 & 0x00F0) >> 4);
in.skipBytes(1); //skip the messageType byte
int remainingLength = Utils.decodeRemainingLenght(in);
if (remainingLength == -1) {
return false;
}
//check remaining length
if (in.readableBytes() < remainingLength) {
return false;
}
//return messageType == type ? MessageDecoderResult.OK : MessageDecoderResult.NOT_OK;
return true;
}
/**
* Decode the variable remaining length as defined in MQTT v3.1 specification
* (section 2.1).
*
* @return the decoded length or -1 if needed more data to decode the length field.
*/
static int decodeRemainingLenght(ByteBuf in) {
int multiplier = 1;
int value = 0;
byte digit;
do {
if (in.readableBytes() < 1) {
return -1;
}
digit = in.readByte();
value += (digit & 0x7F) * multiplier;
multiplier *= 128;
} while ((digit & 0x80) != 0);
return value;
}
/**
* Encode the value in the format defined in specification as variable length
* array.
*
* @throws IllegalArgumentException if the value is not in the specification bounds
* [0..268435455].
*/
static ByteBuf encodeRemainingLength(int value) throws CorruptedFrameException {
if (value > MAX_LENGTH_LIMIT || value < 0) {
throw new CorruptedFrameException("Value should in range 0.." + MAX_LENGTH_LIMIT + " found " + value);
}
ByteBuf encoded = Unpooled.buffer(4);
byte digit;
do {
digit = (byte) (value % 128);
value = value / 128;
// if there are more digits to encode, set the top bit of this digit
if (value > 0) {
digit = (byte) (digit | 0x80);
}
encoded.writeByte(digit);
} while (value > 0);
return encoded;
}
/**
* Load a string from the given buffer, reading first the two bytes of len
* and then the UTF-8 bytes of the string.
*
* @return the decoded string or null if NEED_DATA
*/
static String decodeString(ByteBuf in) throws UnsupportedEncodingException {
return new String(readFixedLengthContent(in), "UTF-8");
}
/**
* Read a byte array from the buffer, use two bytes as length information followed by length bytes.
* */
static byte[] readFixedLengthContent(ByteBuf in) throws UnsupportedEncodingException {
if (in.readableBytes() < 2) {
return null;
}
int strLen = in.readUnsignedShort();
if (in.readableBytes() < strLen) {
return null;
}
byte[] strRaw = new byte[strLen];
in.readBytes(strRaw);
return strRaw;
}
/**
* Return the IoBuffer with string encoded as MSB, LSB and UTF-8 encoded
* string content.
*/
public static ByteBuf encodeString(String str) {
byte[] raw;
try {
raw = str.getBytes("UTF-8");
//NB every Java platform has got UTF-8 encoding by default, so this
//exception are never raised.
} catch (UnsupportedEncodingException ex) {
LoggerFactory.getLogger(Utils.class).error(null, ex);
return null;
}
return encodeFixedLengthContent(raw);
}
/**
* Return the IoBuffer with string encoded as MSB, LSB and bytes array content.
*/
public static ByteBuf encodeFixedLengthContent(byte[] content) {
ByteBuf out = Unpooled.buffer(2);
out.writeShort(content.length);
out.writeBytes(content);
return out;
}
/**
* Return the number of bytes to encode the given remaining length value
*/
static int numBytesToEncode(int len) {
if (0 <= len && len <= 127) return 1;
if (128 <= len && len <= 16383) return 2;
if (16384 <= len && len <= 2097151) return 3;
if (2097152 <= len && len <= 268435455) return 4;
throw new IllegalArgumentException("value shoul be in the range [0..268435455]");
}
static byte encodeFlags(MqttMessage message) {
byte flags = 0;
if (message.fixedHeader().isDup()) {
flags |= 0x08;
}
if (message.fixedHeader().isRetain()) {
flags |= 0x01;
}
flags |= ((message.fixedHeader().qosLevel().value() & 0x03) << 1);
return flags;
}
//3 = 3.1, 4 = 3.1.1
// static final AttributeKey<Integer> PROTOCOL_VERSION = AttributeKey.valueOf("version");
//
// static boolean isMQTT3_1_1(AttributeMap attrsMap) {
// Attribute<Integer> versionAttr = attrsMap.attr(PROTOCOL_VERSION);
// Integer protocolVersion = versionAttr.get();
// if (protocolVersion == null) {
// return true;
// }
// return protocolVersion == VERSION_3_1_1;
// }
}
@@ -39,14 +39,21 @@ public class MessageCollector implements MqttCallback {
private BlockingQueue<ReceivedMessage> m_messages = new LinkedBlockingQueue<>();
private boolean m_connectionLost = false;
public MqttMessage getMessage(boolean checkElapsed) {
if (!checkElapsed && m_messages.isEmpty()) {
/**
* Return the message from the queue if not empty, else return null with wait period.
* */
public MqttMessage getMessageImmediate() {
if (m_messages.isEmpty()) {
return null;
}
try {
return m_messages.take().message;
} catch (InterruptedException e) {
return null;
}
return getMessage(1);
}
public MqttMessage getMessage(int delay) {
public MqttMessage waitMessage(int delay) {
try {
ReceivedMessage msg = m_messages.poll(delay, TimeUnit.SECONDS);
if (msg == null) {
@@ -91,7 +98,7 @@ public class MessageCollector implements MqttCallback {
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
// try {
// m_messages.offer(new ReceivedMessage(token.getMessage(), token.getTopics()[0]));
// m_messages.offer(new ReceivedMessage(token.waitMessage(), token.getTopics()[0]));
// } catch (MqttException e) {
// e.printStackTrace();
// }
@@ -15,10 +15,11 @@
*/
package io.moquette.server;
import io.moquette.parser.proto.messages.AbstractMessage.QOSType;
import io.moquette.parser.proto.messages.PublishMessage;
import io.moquette.server.netty.MessageBuilder;
import io.moquette.server.config.IConfig;
import io.moquette.server.config.MemoryConfig;
import io.netty.handler.codec.mqtt.MqttPublishMessage;
import io.netty.handler.codec.mqtt.MqttQoS;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;
import org.junit.After;
@@ -30,7 +31,6 @@ import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Properties;
import static org.junit.Assert.*;
@@ -88,13 +88,14 @@ public class ServerIntegrationEmbeddedPublishTest {
m_subscriber.subscribe(topic, qos);
}
private void internalPublishToWithQosAndRetained(String topic, QOSType qos, boolean retained) {
PublishMessage message = new PublishMessage();
message.setTopicName(topic);
message.setRetainFlag(retained);
message.setQos(qos);
message.setPayload(ByteBuffer.wrap("Hello world MQTT!!".getBytes()));
m_server.internalPublish(message);
private void internalPublishToWithQosAndRetained(String topic, MqttQoS qos, boolean retained) {
MqttPublishMessage message = MessageBuilder.publish()
.topicName(topic)
.retained(retained)
.qos(qos)
.payload("Hello world MQTT!!".getBytes())
.build();
m_server.internalPublish(message, "INTRPUBL");
}
private void connectNoCleanSession() throws Exception {
@@ -109,13 +110,13 @@ public class ServerIntegrationEmbeddedPublishTest {
}
private void verifyNoMessageIsReceived() throws Exception {
MqttMessage msg = m_callback.getMessage(false);
MqttMessage msg = m_callback.getMessageImmediate();
assertNull(msg);
}
private void verifyMessageIsReceivedSuccessfully() throws Exception {
//check in 2 seconds
MqttMessage msg = m_callback.getMessage(2);
MqttMessage msg = m_callback.waitMessage(2);
assertNotNull(msg);
assertEquals("Hello world MQTT!!", new String(msg.getPayload()));
}
@@ -125,7 +126,7 @@ public class ServerIntegrationEmbeddedPublishTest {
LOG.info("*** testClientSubscribeAfterNotRetainedQoS0IsSent ***");
//Exercise
internalPublishToWithQosAndRetained("/topic", QOSType.MOST_ONE, false);
internalPublishToWithQosAndRetained("/topic", MqttQoS.AT_MOST_ONCE, false);
subscribeToWithQos("/topic", 0);
//Verify
@@ -139,7 +140,7 @@ public class ServerIntegrationEmbeddedPublishTest {
subscribeToWithQos("/topic", 0);
//Exercise
internalPublishToWithQosAndRetained("/topic", QOSType.MOST_ONE, false);
internalPublishToWithQosAndRetained("/topic", MqttQoS.AT_MOST_ONCE, false);
//Verify
verifyMessageIsReceivedSuccessfully();
@@ -152,7 +153,7 @@ public class ServerIntegrationEmbeddedPublishTest {
subscribeToWithQos("/topic", 0);
//Exercise
internalPublishToWithQosAndRetained("/topic", QOSType.MOST_ONE, true);
internalPublishToWithQosAndRetained("/topic", MqttQoS.AT_MOST_ONCE, true);
//Verify
verifyMessageIsReceivedSuccessfully();
@@ -163,7 +164,7 @@ public class ServerIntegrationEmbeddedPublishTest {
LOG.info("*** testClientSubscribeAfterRetainedQoS0IsSent ***");
//Exercise
internalPublishToWithQosAndRetained("/topic", QOSType.MOST_ONE, true);
internalPublishToWithQosAndRetained("/topic", MqttQoS.AT_MOST_ONCE, true);
//LOG.info("** post internalPublish **");
subscribeToWithQos("/topic", 0);
@@ -178,7 +179,7 @@ public class ServerIntegrationEmbeddedPublishTest {
subscribeToWithQos("/topic", 1);
//Exercise
internalPublishToWithQosAndRetained("/topic", QOSType.LEAST_ONE, false);
internalPublishToWithQosAndRetained("/topic", MqttQoS.AT_LEAST_ONCE, false);
//Verify
verifyMessageIsReceivedSuccessfully();
@@ -189,7 +190,7 @@ public class ServerIntegrationEmbeddedPublishTest {
LOG.info("*** testClientSubscribeAfterNotRetainedQoS1IsSent ***");
//Exercise
internalPublishToWithQosAndRetained("/topic", QOSType.LEAST_ONE, false);
internalPublishToWithQosAndRetained("/topic", MqttQoS.AT_LEAST_ONCE, false);
subscribeToWithQos("/topic", 1);
//Verify
@@ -203,7 +204,7 @@ public class ServerIntegrationEmbeddedPublishTest {
subscribeToWithQos("/topic", 1);
//Exercise
internalPublishToWithQosAndRetained("/topic", QOSType.LEAST_ONE, true);
internalPublishToWithQosAndRetained("/topic", MqttQoS.AT_LEAST_ONCE, true);
//Verify
verifyMessageIsReceivedSuccessfully();
@@ -214,8 +215,8 @@ public class ServerIntegrationEmbeddedPublishTest {
LOG.info("*** testClientSubscribeAfterRetainedQoS0IsSent ***");
//Exercise
internalPublishToWithQosAndRetained("/topic", QOSType.LEAST_ONE, true);
subscribeToWithQos("/topic", 1);
internalPublishToWithQosAndRetained("/topic", MqttQoS.AT_LEAST_ONCE, true);
subscribeToWithQos("/topic", MqttQoS.AT_LEAST_ONCE.value());
LOG.info("** After subscribe **");
//Verify
@@ -230,7 +231,7 @@ public class ServerIntegrationEmbeddedPublishTest {
subscribeToWithQos("/topic", 2);
//Exercise
internalPublishToWithQosAndRetained("/topic", QOSType.EXACTLY_ONCE, false);
internalPublishToWithQosAndRetained("/topic", MqttQoS.EXACTLY_ONCE, false);
//Verify
verifyMessageIsReceivedSuccessfully();
@@ -241,7 +242,7 @@ public class ServerIntegrationEmbeddedPublishTest {
LOG.info("*** testClientSubscribeAfterNotRetainedQoS2IsSent ***");
//Exercise
internalPublishToWithQosAndRetained("/topic", QOSType.EXACTLY_ONCE, false);
internalPublishToWithQosAndRetained("/topic", MqttQoS.EXACTLY_ONCE, false);
subscribeToWithQos("/topic", 2);
//Verify
@@ -255,7 +256,7 @@ public class ServerIntegrationEmbeddedPublishTest {
subscribeToWithQos("/topic", 2);
//Exercise
internalPublishToWithQosAndRetained("/topic", QOSType.EXACTLY_ONCE, true);
internalPublishToWithQosAndRetained("/topic", MqttQoS.EXACTLY_ONCE, true);
//Verify
verifyMessageIsReceivedSuccessfully();
@@ -266,7 +267,7 @@ public class ServerIntegrationEmbeddedPublishTest {
LOG.info("*** testClientSubscribeAfterRetainedQoS2IsSent ***");
//Exercise
internalPublishToWithQosAndRetained("/topic", QOSType.EXACTLY_ONCE, true);
internalPublishToWithQosAndRetained("/topic", MqttQoS.EXACTLY_ONCE, true);
subscribeToWithQos("/topic", 2);
//Verify
@@ -280,11 +281,11 @@ public class ServerIntegrationEmbeddedPublishTest {
subscribeToWithQos("foo", 0);
m_subscriber.disconnect();
internalPublishToWithQosAndRetained("foo", QOSType.MOST_ONE, false);
internalPublishToWithQosAndRetained("foo", MqttQoS.AT_MOST_ONCE, false);
//verifyMessageIsReceivedSuccessfully();
//m_subscriber.receive(2, TimeUnit.MILLISECONDS);
MqttMessage message = m_callback.getMessage(true);
MqttMessage message = m_callback.waitMessage(1);
assertTrue(message == null);
}
@@ -296,7 +297,7 @@ public class ServerIntegrationEmbeddedPublishTest {
assertTrue(m_server.getSubscriptions().size() == 1);
connectNoCleanSession();
assertTrue(m_server.getSubscriptions().size() == 1);
internalPublishToWithQosAndRetained("foo", QOSType.MOST_ONE, false);
internalPublishToWithQosAndRetained("foo", MqttQoS.AT_MOST_ONCE, false);
verifyMessageIsReceivedSuccessfully();
}
}
@@ -105,21 +105,21 @@ public class ServerIntegrationHazelcastHandlerInterceptorTest{
m_listener.subscribe("/topic", 1);
m_publisher.publish("/topic", "Hello world MQTT QoS0".getBytes(), 0, false);
MqttMessage messageQos0 = m_messagesCollector.getMessage(true);
MqttMessage messageQos0 = m_messagesCollector.waitMessage(1);
assertEquals("Hello world MQTT QoS0", messageQos0.toString());
assertEquals(0, messageQos0.getQos());
m_listener.subscribe("/topic", 1);
m_publisher.publish("/topic", "Hello world MQTT QoS1".getBytes(), 1, false);
MqttMessage messageQos1 = m_messagesCollector.getMessage(true);
MqttMessage messageQos1 = m_messagesCollector.waitMessage(1);
assertEquals("Hello world MQTT QoS1", messageQos1.toString());
assertEquals(1, messageQos1.getQos());
m_listener.subscribe("/topic", 2);
m_publisher.publish("/topic", "Hello world MQTT QoS2".getBytes(), 2, false);
MqttMessage messageQos2 = m_messagesCollector.getMessage(true);
MqttMessage messageQos2 = m_messagesCollector.waitMessage(1);
assertEquals("Hello world MQTT QoS2", messageQos2.toString());
assertEquals(2, messageQos2.getQos());
}
@@ -19,10 +19,7 @@ import io.moquette.server.config.IConfig;
import io.moquette.server.config.MemoryConfig;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -176,7 +173,7 @@ public class ServerIntegrationPahoTest {
m_client.connect(options);
m_client.publish("/topic", "Test my payload".getBytes(), 0, false);
//Ugly, we need to get self notified after the publish
assertEquals("Test my payload", new String(subListener.getMessage(1).getPayload()));
assertEquals("Test my payload", new String(subListener.waitMessage(1).getPayload()));
//close
m_client.disconnect();
@@ -231,7 +228,7 @@ public class ServerIntegrationPahoTest {
m_messagesCollector.reinit();
m_client.publish("/topic", "Test my payload".getBytes(), 0, false);
assertNull(m_messagesCollector.getMessage(false));
assertNull(m_messagesCollector.getMessageImmediate());
}
@Test
@@ -252,7 +249,7 @@ public class ServerIntegrationPahoTest {
m_client.connect(options);
m_client.publish("/topic", "Test my payload".getBytes(), 0, false);
assertNull(m_messagesCollector.getMessage(false));
assertNull(m_messagesCollector.getMessageImmediate());
}
@Test
@@ -264,7 +261,7 @@ public class ServerIntegrationPahoTest {
m_client.disconnect();
//reconnect and publish
MqttMessage message = m_messagesCollector.getMessage(true);
MqttMessage message = m_messagesCollector.waitMessage(1);
assertEquals("Hello MQTT", message.toString());
assertEquals(1, message.getQos());
}
@@ -283,7 +280,7 @@ public class ServerIntegrationPahoTest {
m_client.connect(options);
assertEquals("Hello MQTT", m_messagesCollector.getMessage(true).toString());
assertEquals("Hello MQTT", m_messagesCollector.waitMessage(1).toString());
}
@@ -303,7 +300,7 @@ public class ServerIntegrationPahoTest {
publishFromAnotherClient("/topic", "Hello MQTT".getBytes(), 1);
//Verify that after a reconnection the client receive the message
MqttMessage message = m_messagesCollector.getMessage(true);
MqttMessage message = m_messagesCollector.waitMessage(1);
assertNotNull(message);
assertEquals("Hello MQTT", message.toString());
}
@@ -329,7 +326,7 @@ public class ServerIntegrationPahoTest {
m_messagesCollector.reinit();
m_client.connect(options);
MqttMessage message = m_messagesCollector.getMessage(true);
MqttMessage message = m_messagesCollector.waitMessage(1);
assertEquals("Hello MQTT", message.toString());
assertEquals(2, message.getQos());
}
@@ -349,7 +346,7 @@ public class ServerIntegrationPahoTest {
m_client.connect(options);
assertNotNull(m_messagesCollector);
MqttMessage message = m_messagesCollector.getMessage(true);
MqttMessage message = m_messagesCollector.waitMessage(1);
assertNotNull(message);
assertEquals("Hello MQTT", message.toString());
}
@@ -368,7 +365,7 @@ public class ServerIntegrationPahoTest {
m_client.connect(options);
assertNotNull(m_messagesCollector);
MqttMessage message = m_messagesCollector.getMessage(true);
MqttMessage message = m_messagesCollector.waitMessage(1);
assertNotNull(message);
assertEquals("Hello MQTT 1", message.toString());
m_client.disconnect();
@@ -380,7 +377,7 @@ public class ServerIntegrationPahoTest {
m_messagesCollector.reinit();
m_client.connect(options);
assertNotNull(m_messagesCollector);
message = m_messagesCollector.getMessage(true);
message = m_messagesCollector.waitMessage(1);
assertNotNull(message);
assertEquals("Hello MQTT 2", message.toString());
}
@@ -417,12 +414,12 @@ public class ServerIntegrationPahoTest {
m_client.connect();
m_client.publish("a/b", "Hello world MQTT!!".getBytes(), 2, false);
MqttMessage messageOnA = cbSubscriberA.getMessage(true);
MqttMessage messageOnA = cbSubscriberA.waitMessage(1);
assertEquals("Hello world MQTT!!", new String(messageOnA.getPayload()));
assertEquals(1, messageOnA.getQos());
subscriberA.disconnect();
MqttMessage messageOnB = cbSubscriberB.getMessage(true);
MqttMessage messageOnB = cbSubscriberB.waitMessage(1);
assertEquals("Hello world MQTT!!", new String(messageOnB.getPayload()));
assertEquals(2, messageOnB.getQos());
subscriberB.disconnect();
@@ -466,7 +463,7 @@ public class ServerIntegrationPahoTest {
assertFalse(clientForSubscribe1.isConnected());
assertTrue(clientForSubscribe2.isConnected());
LOG.info("Waiting to receive 1 sec from " + clientForSubscribe2.getClientId());
MqttMessage messageOnB = cbSubscriber2.getMessage(true);
MqttMessage messageOnB = cbSubscriber2.waitMessage(1);
assertEquals("Hello", new String(messageOnB.getPayload()));
}
@@ -495,7 +492,7 @@ public class ServerIntegrationPahoTest {
//Verify that the second subscriber client get notified and not the first.
assertTrue(cbSubscriber1.connectionLost());
assertEquals("Hello 2", new String(cbSubscriber2.getMessage(true).getPayload()));
assertEquals("Hello 2", new String(cbSubscriber2.waitMessage(1).getPayload()));
}
@Test
@@ -533,7 +530,7 @@ public class ServerIntegrationPahoTest {
m_publisher.publish("/topic", "Hello world MQTT!!-1".getBytes(), 1, false);
//read the first message and drop the connection
MqttMessage msg = m_messagesCollector.getMessage(true);
MqttMessage msg = m_messagesCollector.waitMessage(1);
assertEquals("Hello world MQTT!!-1", new String(msg.getPayload()));
m_client.disconnect();
@@ -542,10 +539,10 @@ public class ServerIntegrationPahoTest {
//reconnect and expect to receive the hello 2 message
m_client.connect(options);
msg = m_messagesCollector.getMessage(true);
msg = m_messagesCollector.waitMessage(1);
assertEquals("Hello world MQTT!!-2", new String(msg.getPayload()));
msg = m_messagesCollector.getMessage(true);
msg = m_messagesCollector.waitMessage(1);
assertEquals("Hello world MQTT!!-3", new String(msg.getPayload()));
m_client.disconnect();
}
@@ -569,7 +566,7 @@ public class ServerIntegrationPahoTest {
//reconnect and expect to receive the hello 2 message
m_client.connect(options);
m_client.subscribe("/topic", 1);
MqttMessage msg = messagesCollector.getMessage(true);
MqttMessage msg = messagesCollector.waitMessage(1);
assertNotNull(msg);
assertEquals("Hello world MQTT!!-1", new String(msg.getPayload()));
}
@@ -599,10 +596,10 @@ public class ServerIntegrationPahoTest {
//subscriber reconnects
m_client.connect(options);
//subscriber should receive the 2 messages missed
MqttMessage msg = messagesCollector.getMessage(1);
MqttMessage msg = messagesCollector.waitMessage(1);
assertNotNull(msg);
assertEquals("Hello1", new String(msg.getPayload()));
msg = messagesCollector.getMessage(1);
msg = messagesCollector.waitMessage(1);
assertNotNull(msg);
assertEquals("Hello2", new String(msg.getPayload()));
}
@@ -629,11 +626,11 @@ public class ServerIntegrationPahoTest {
m_publisher.publish("a/b", "Hello world MQTT!!".getBytes(), 1, false);
//reconnect and expect to receive the hello 2 message
MqttMessage msg = messagesCollector.getMessage(1);
MqttMessage msg = messagesCollector.waitMessage(1);
assertEquals("Hello world MQTT!!", new String(msg.getPayload()));
//try to listen a second publish
msg = messagesCollector.getMessage(1);
msg = messagesCollector.waitMessage(1);
assertNull(msg);
}
@@ -100,7 +100,7 @@ public class ServerIntegrationQoSValidationTest {
m_subscriber.subscribe("/topic", 0);
m_publisher.publish("/topic", "Hello world MQTT QoS0".getBytes(), 0, false);
MqttMessage message = m_callback.getMessage(true);
MqttMessage message = m_callback.waitMessage(1);
assertEquals("Hello world MQTT QoS0", message.toString());
assertEquals(0, message.getQos());
}
@@ -111,7 +111,7 @@ public class ServerIntegrationQoSValidationTest {
m_subscriber.subscribe("/topic", 0);
m_publisher.publish("/topic", "Hello world MQTT QoS1".getBytes(), 1, false);
MqttMessage message = m_callback.getMessage(true);
MqttMessage message = m_callback.waitMessage(1);
assertEquals("Hello world MQTT QoS1", message.toString());
assertEquals(0, message.getQos());
}
@@ -122,7 +122,7 @@ public class ServerIntegrationQoSValidationTest {
m_subscriber.subscribe("/topic", 0);
m_publisher.publish("/topic", "Hello world MQTT QoS2".getBytes(), 2, false);
MqttMessage message = m_callback.getMessage(true);
MqttMessage message = m_callback.waitMessage(1);
assertEquals("Hello world MQTT QoS2", message.toString());
assertEquals(0, message.getQos());
}
@@ -133,7 +133,7 @@ public class ServerIntegrationQoSValidationTest {
m_subscriber.subscribe("/topic", 1);
m_publisher.publish("/topic", "Hello world MQTT QoS0".getBytes(), 0, false);
MqttMessage message = m_callback.getMessage(true);
MqttMessage message = m_callback.waitMessage(1);
assertEquals("Hello world MQTT QoS0", message.toString());
assertEquals(0, message.getQos());
}
@@ -144,7 +144,7 @@ public class ServerIntegrationQoSValidationTest {
m_subscriber.subscribe("/topic", 1);
m_publisher.publish("/topic", "Hello world MQTT QoS1".getBytes(), 1, false);
MqttMessage message = m_callback.getMessage(true);
MqttMessage message = m_callback.waitMessage(1);
assertEquals("Hello world MQTT QoS1", message.toString());
assertEquals(1, message.getQos());
}
@@ -155,7 +155,7 @@ public class ServerIntegrationQoSValidationTest {
m_subscriber.subscribe("/topic", 1);
m_publisher.publish("/topic", "Hello world MQTT QoS2".getBytes(), 2, false);
MqttMessage message = m_callback.getMessage(true);
MqttMessage message = m_callback.waitMessage(1);
assertEquals("Hello world MQTT QoS2", message.toString());
assertEquals(1, message.getQos());
}
@@ -166,7 +166,7 @@ public class ServerIntegrationQoSValidationTest {
m_subscriber.subscribe("/topic", 2);
m_publisher.publish("/topic", "Hello world MQTT QoS2".getBytes(), 0, false);
MqttMessage message = m_callback.getMessage(true);
MqttMessage message = m_callback.waitMessage(1);
assertEquals("Hello world MQTT QoS2", message.toString());
assertEquals(0, message.getQos());
}
@@ -177,7 +177,7 @@ public class ServerIntegrationQoSValidationTest {
m_subscriber.subscribe("/topic", 2);
m_publisher.publish("/topic", "Hello world MQTT QoS2".getBytes(), 1, false);
MqttMessage message = m_callback.getMessage(true);
MqttMessage message = m_callback.waitMessage(1);
assertEquals("Hello world MQTT QoS2", message.toString());
assertEquals(1, message.getQos());
}
@@ -188,7 +188,7 @@ public class ServerIntegrationQoSValidationTest {
m_subscriber.subscribe("/topic", 2);
m_publisher.publish("/topic", "Hello world MQTT QoS2".getBytes(), 2, false);
MqttMessage message = m_callback.getMessage(true);
MqttMessage message = m_callback.waitMessage(1);
assertEquals("Hello world MQTT QoS2", message.toString());
assertEquals(2, message.getQos());
}
@@ -15,12 +15,11 @@
*/
package io.moquette.server;
import io.moquette.parser.proto.messages.ConnectMessage;
import io.moquette.parser.proto.messages.AbstractMessage;
import io.moquette.parser.proto.messages.ConnAckMessage;
import io.moquette.server.config.IConfig;
import io.moquette.server.config.MemoryConfig;
import io.moquette.testclient.Client;
import io.netty.handler.codec.mqtt.*;
import io.netty.handler.codec.mqtt.MqttMessage;
import org.eclipse.paho.client.mqttv3.*;
import org.junit.After;
import org.junit.Before;
@@ -30,7 +29,7 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Properties;
import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.*;
import static org.junit.Assert.*;
/**
@@ -45,7 +44,7 @@ public class ServerLowlevelMessagesIntegrationTests {
IMqttClient m_willSubscriber;
MessageCollector m_messageCollector;
IConfig m_config;
AbstractMessage receivedMsg;
MqttMessage receivedMsg;
protected void startServer() throws IOException {
m_server = new Server();
@@ -72,14 +71,17 @@ public class ServerLowlevelMessagesIntegrationTests {
LOG.debug("After asked server to stop");
IntegrationUtils.cleanPersistenceFile(m_config);
}
@Test
public void elapseKeepAliveTime() throws InterruptedException {
int keepAlive = 2; //secs
ConnectMessage connectMessage = new ConnectMessage();
MqttConnectMessage connectMessage = createConnectMessage("FAKECLNT", keepAlive);
/*ConnectMessage connectMessage = new ConnectMessage();
connectMessage.setProtocolVersion((byte) 3);
connectMessage.setClientID("FAKECLNT");
connectMessage.setKeepAlive(keepAlive);
connectMessage.setKeepAlive(keepAlive);*/
m_client.sendMessage(connectMessage);
//wait 2 times the keepAlive
@@ -87,6 +89,23 @@ public class ServerLowlevelMessagesIntegrationTests {
assertTrue(m_client.isConnectionLost());
}
private static MqttConnectMessage createConnectMessage(String clientID, int keepAlive) {
MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(MqttMessageType.CONNECT, false, MqttQoS.AT_MOST_ONCE, false, 0);
MqttConnectVariableHeader mqttConnectVariableHeader =
new MqttConnectVariableHeader(
MqttVersion.MQTT_3_1.protocolName(),
MqttVersion.MQTT_3_1.protocolLevel(),
false,
false,
false,
1,
false,
true,
keepAlive);
MqttConnectPayload mqttConnectPayload = new MqttConnectPayload(clientID, null, null, null, null);
return new MqttConnectMessage(mqttFixedHeader, mqttConnectVariableHeader, mqttConnectPayload);
}
@Test
public void testWillMessageIsWiredOnClientKeepAliveExpiry() throws Exception {
@@ -102,7 +121,7 @@ public class ServerLowlevelMessagesIntegrationTests {
//but after the 2 KEEP ALIVE timeout expires it gets fired,
//NB it's 1,5 * KEEP_ALIVE so 3 secs and some millis to propagate the message
MqttMessage msg = m_messageCollector.getMessage(5);
org.eclipse.paho.client.mqttv3.MqttMessage msg = m_messageCollector.waitMessage(5);
assertNotNull("the will message should be fired after keep alive!", msg);
//the will message hasn't to be received before the elapsing of Keep Alive timeout
assertTrue(System.currentTimeMillis() - connectTime > 3000);
@@ -118,9 +137,9 @@ public class ServerLowlevelMessagesIntegrationTests {
this.receivedMsg = this.m_client.lastReceivedMessage();
assertTrue(receivedMsg instanceof ConnAckMessage);
ConnAckMessage connAck = (ConnAckMessage) receivedMsg;
assertEquals(ConnAckMessage.IDENTIFIER_REJECTED, connAck.getReturnCode());
assertTrue(receivedMsg instanceof MqttConnAckMessage);
MqttConnAckMessage connAck = (MqttConnAckMessage) receivedMsg;
assertEquals(CONNECTION_REFUSED_IDENTIFIER_REJECTED, connAck.variableHeader().connectReturnCode());
}
@Test
@@ -136,7 +155,7 @@ public class ServerLowlevelMessagesIntegrationTests {
m_client.close();
//Verify will testament is published
MqttMessage receivedTestament = m_messageCollector.getMessage(1);
org.eclipse.paho.client.mqttv3.MqttMessage receivedTestament = m_messageCollector.waitMessage(1);
assertEquals(willTestamentMsg, new String(receivedTestament.getPayload()));
m_willSubscriber.disconnect();
}
@@ -112,10 +112,10 @@ public class ServerRestartIntegrationTest {
m_publisher.publish("/topic", "Hello world MQTT!!".getBytes(), 1, false);
//read the messages
MqttMessage msg = m_messageCollector.getMessage(true);
MqttMessage msg = m_messageCollector.waitMessage(1);
assertEquals("Hello world MQTT!!", new String(msg.getPayload()));
//no more messages on the same topic will be received
assertNull(m_messageCollector.getMessage(1));
assertNull(m_messageCollector.waitMessage(1));
}
@@ -161,7 +161,7 @@ public class ServerRestartIntegrationTest {
//Expected
//the subscriber doesn't get notified (it's fully unsubscribed)
assertNull(m_messageCollector.getMessage(1));
assertNull(m_messageCollector.waitMessage(1));
}
/**
@@ -174,7 +174,7 @@ public class ServerRestartIntegrationTest {
client.connect();
client.subscribe(topic, 1);
client.publish(topic, "Hello world MQTT!!".getBytes(), 0, false);
MqttMessage msg = collector.getMessage(true);
MqttMessage msg = collector.waitMessage(1);
assertEquals("Hello world MQTT!!", new String(msg.getPayload()));
return client;
}
@@ -1,9 +1,9 @@
package io.moquette.spi;
import io.moquette.parser.proto.messages.AbstractMessage;
import io.moquette.spi.impl.MemoryStorageService;
import io.moquette.spi.impl.subscriptions.Subscription;
import io.moquette.spi.impl.subscriptions.SubscriptionsStore;
import static io.netty.handler.codec.mqtt.MqttQoS.*;
import org.junit.Before;
import org.junit.Test;
@@ -11,9 +11,6 @@ import java.util.List;
import static org.junit.Assert.assertEquals;
/**
* Created by nedermail on 17/07/16.
*/
public class ClientSessionTest {
ClientSession session1;
@@ -36,12 +33,12 @@ public class ClientSessionTest {
@Test
public void overridingSubscriptions() {
// Subscribe on /topic with QOSType.MOST_ONE
Subscription oldSubscription = new Subscription(session1.clientID, "/topic", AbstractMessage.QOSType.MOST_ONE);
Subscription oldSubscription = new Subscription(session1.clientID, "/topic", AT_MOST_ONCE);
session1.subscribe(oldSubscription);
store.add(oldSubscription.asClientTopicCouple());
// Subscribe on /topic again that overrides the previous subscription.
Subscription overrindingSubscription = new Subscription(session1.clientID, "/topic", AbstractMessage.QOSType.EXACTLY_ONCE);
Subscription overrindingSubscription = new Subscription(session1.clientID, "/topic", EXACTLY_ONCE);
session1.subscribe(overrindingSubscription);
store.add(overrindingSubscription.asClientTopicCouple());
@@ -15,12 +15,11 @@
*/
package io.moquette.spi.impl;
import io.moquette.interception.messages.*;
import io.moquette.parser.proto.messages.ConnectMessage;
import io.moquette.interception.InterceptHandler;
import io.moquette.parser.proto.messages.AbstractMessage;
import io.moquette.parser.proto.messages.PublishMessage;
import io.moquette.interception.messages.*;
import io.moquette.server.netty.MessageBuilder;
import io.moquette.spi.impl.subscriptions.Subscription;
import io.netty.handler.codec.mqtt.MqttQoS;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -28,9 +27,10 @@ import org.junit.Test;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.Assert.*;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.refEq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* @author Wagner Macedo
@@ -105,7 +105,7 @@ public class BrokerInterceptorTest {
@Test
public void testNotifyClientConnected() throws Exception {
interceptor.notifyClientConnected(new ConnectMessage());
interceptor.notifyClientConnected(MessageBuilder.connect().build());
interval();
assertEquals(40, n.get());
}
@@ -119,14 +119,17 @@ public class BrokerInterceptorTest {
@Test
public void testNotifyTopicPublished() throws Exception {
interceptor.notifyTopicPublished(new PublishMessage(), "cli1234", "cli1234");
interceptor.notifyTopicPublished(MessageBuilder.publish()
.qos(MqttQoS.AT_MOST_ONCE)
.payload("Hello".getBytes())
.build(), "cli1234", "cli1234");
interval();
assertEquals(60, n.get());
}
@Test
public void testNotifyTopicSubscribed() throws Exception {
interceptor.notifyTopicSubscribed(new Subscription("cli1", "o2", AbstractMessage.QOSType.MOST_ONE), "cli1234");
interceptor.notifyTopicSubscribed(new Subscription("cli1", "o2", MqttQoS.AT_MOST_ONCE), "cli1234");
interval();
assertEquals(70, n.get());
}
@@ -146,7 +149,7 @@ public class BrokerInterceptorTest {
interceptor.addInterceptHandler(interceptHandlerMock1);
interceptor.addInterceptHandler(interceptHandlerMock2);
Subscription subscription = new Subscription("cli1", "o2", AbstractMessage.QOSType.MOST_ONE);
Subscription subscription = new Subscription("cli1", "o2", MqttQoS.AT_MOST_ONCE);
interceptor.notifyTopicSubscribed(subscription, "cli1234");
interval();
@@ -28,9 +28,9 @@ import io.moquette.spi.security.IAuthenticator;
class MockAuthenticator implements IAuthenticator {
private Set<String> m_clientIds;
private Map<String, byte[]> m_userPwds;
private Map<String, String> m_userPwds;
MockAuthenticator(Set<String> clientIds, Map<String, byte[]> userPwds) {
MockAuthenticator(Set<String> clientIds, Map<String, String> userPwds) {
m_clientIds = clientIds;
m_userPwds = userPwds;
}
@@ -42,7 +42,10 @@ class MockAuthenticator implements IAuthenticator {
if (!m_userPwds.containsKey(username)) {
return false;
}
return m_userPwds.get(username).equals(password);
if (password == null) {
return false;
}
return m_userPwds.get(username).equals(new String(password));
}
}
@@ -12,10 +12,11 @@
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/package io.moquette.spi.impl;
*/
package io.moquette.spi.impl;
import io.netty.handler.codec.mqtt.MqttMessage;
import io.netty.util.AttributeKey;
import io.moquette.parser.proto.messages.AbstractMessage;
import java.util.HashMap;
import java.util.Map;
@@ -23,9 +24,8 @@ import java.util.Map;
/**
* This a synchronous channel that avoid output ring buffer from Processor
*/
class MockReceiverChannel /*implements ServerChannel*/ {
// byte m_returnCode;
AbstractMessage m_receivedMessage;
class MockReceiverChannel {
MqttMessage m_receivedMessage;
private Map<Object, Object> m_attributes = new HashMap<>();
public Object getAttribute(AttributeKey<Object> key) {
@@ -42,20 +42,13 @@ class MockReceiverChannel /*implements ServerChannel*/ {
public void close(boolean immediately) {
}
public AbstractMessage getMessage() {
public MqttMessage getMessage() {
return this.m_receivedMessage;
}
// public byte getReturnCode() {
// return this.m_returnCode;
// }
public void write(Object value) {
try {
this.m_receivedMessage = (AbstractMessage) value;
// if (this.m_receivedMessage instanceof PublishMessage) {
// T buf = (T) this.m_receivedMessage;
// }
this.m_receivedMessage = (MqttMessage) value;
} catch (Exception ex) {
throw new AssertionError("Wrong return code");
}
@@ -15,12 +15,12 @@
*/
package io.moquette.spi.impl;
import io.moquette.parser.proto.messages.ConnAckMessage;
import io.moquette.parser.proto.messages.SubAckMessage;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.mqtt.MqttConnAckMessage;
import io.netty.handler.codec.mqtt.MqttConnectReturnCode;
import io.netty.handler.codec.mqtt.MqttSubAckMessage;
import static io.moquette.parser.proto.messages.ConnAckMessage.CONNECTION_ACCEPTED;
import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_ACCEPTED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -29,18 +29,18 @@ import static org.junit.Assert.assertTrue;
*/
class NettyChannelAssertions {
static void assertEqualsConnAck(byte expectedCode, Object connAck) {
static void assertEqualsConnAck(MqttConnectReturnCode expectedCode, Object connAck) {
assertEqualsConnAck(null, expectedCode, connAck);
}
static void assertEqualsConnAck(String msg, byte expectedCode, Object connAck) {
assertTrue("connAck is not an instance of ConnAckMessage", connAck instanceof ConnAckMessage);
ConnAckMessage connAckMsg = (ConnAckMessage) connAck;
static void assertEqualsConnAck(String msg, MqttConnectReturnCode expectedCode, Object connAck) {
assertTrue("connAck is not an instance of ConnAckMessage", connAck instanceof MqttConnAckMessage);
MqttConnAckMessage connAckMsg = (MqttConnAckMessage) connAck;
if(msg == null)
assertEquals(expectedCode, connAckMsg.getReturnCode());
if (msg == null)
assertEquals(expectedCode, connAckMsg.variableHeader().connectReturnCode());
else
assertEquals(msg, expectedCode, connAckMsg.getReturnCode());
assertEquals(msg, expectedCode, connAckMsg.variableHeader().connectReturnCode());
}
static void assertConnAckAccepted(EmbeddedChannel channel) {
@@ -49,7 +49,7 @@ class NettyChannelAssertions {
}
static void assertEqualsSubAck(/*byte expectedCode,*/ Object subAck) {
assertTrue(subAck instanceof SubAckMessage);
assertTrue(subAck instanceof MqttSubAckMessage);
//SubAckMessage connAckMsg = (SubAckMessage) connAck;
//assertEquals(expectedCode, connAckMsg.getReturnCode());
}
@@ -15,28 +15,28 @@
*/
package io.moquette.spi.impl;
import io.moquette.parser.proto.messages.*;
import io.moquette.interception.InterceptHandler;
import io.moquette.parser.proto.messages.AbstractMessage.QOSType;
import io.moquette.server.netty.MessageBuilder;
import io.moquette.server.netty.NettyUtils;
import io.moquette.spi.*;
import io.moquette.spi.IMatchingCondition;
import io.moquette.spi.IMessagesStore;
import io.moquette.spi.IMessagesStore.StoredMessage;
import io.moquette.spi.ISessionsStore;
import io.moquette.spi.impl.security.PermitAllAuthorizator;
import io.moquette.spi.impl.subscriptions.Subscription;
import io.moquette.spi.impl.subscriptions.SubscriptionsStore;
import io.moquette.spi.security.IAuthorizator;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.mqtt.*;
import org.junit.Before;
import org.junit.Test;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import static io.moquette.spi.impl.NettyChannelAssertions.assertConnAckAccepted;
import static io.moquette.spi.impl.ProtocolProcessor.lowerQosToTheSubscriptionDesired;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;
/**
@@ -49,29 +49,35 @@ public class ProtocolProcessorTest {
final static String FAKE_PUBLISHER_ID = "Publisher";
final static String FAKE_TOPIC = "/news";
final static String BAD_FORMATTED_TOPIC = "#MQTTClient";
final static String TEST_USER = "fakeuser";
final static byte[] TEST_PWD = "fakepwd".getBytes();
final static String TEST_PWD = "fakepwd";
final static String EVIL_TEST_USER = "eviluser";
final static byte[] EVIL_TEST_PWD = "unsecret".getBytes();
final static String EVIL_TEST_PWD = "unsecret";
final static List<InterceptHandler> EMPTY_OBSERVERS = Collections.emptyList();
final static BrokerInterceptor NO_OBSERVERS_INTERCEPTOR = new BrokerInterceptor(EMPTY_OBSERVERS);
EmbeddedChannel m_channel;
ConnectMessage connMsg;
MqttConnectMessage connMsg;
ProtocolProcessor m_processor;
IMessagesStore m_messagesStore;
ISessionsStore m_sessionStore;
SubscriptionsStore subscriptions;
MockAuthenticator m_mockAuthenticator;
@Before
public void setUp() throws InterruptedException {
connMsg = new ConnectMessage();
/*connMsg = new ConnectMessage();
connMsg.setProtocolVersion((byte) 0x03);
connMsg = MessageBuilder.connect()
.protocolVersion(MqttVersion.MQTT_3_1)
.clientId(FAKE_CLIENT_ID)
.cleanSession(true)
.build();*/
m_channel = new EmbeddedChannel();
NettyUtils.clientID(m_channel, FAKE_CLIENT_ID);
NettyUtils.cleanSession(m_channel, false);
@@ -87,7 +93,7 @@ public class ProtocolProcessorTest {
Set<String> clientIds = new HashSet<>();
clientIds.add(FAKE_CLIENT_ID);
clientIds.add(FAKE_CLIENT_ID2);
Map<String, byte[]> users = new HashMap<>();
Map<String, String> users = new HashMap<>();
users.put(TEST_USER, TEST_PWD);
m_mockAuthenticator = new MockAuthenticator(clientIds, users);
@@ -102,7 +108,7 @@ public class ProtocolProcessorTest {
@Test
public void testPublishToItself() throws InterruptedException {
final Subscription subscription = new Subscription(FAKE_CLIENT_ID,
FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE);
FAKE_TOPIC, MqttQoS.AT_MOST_ONCE);
//subscriptions.matches(topic) redefine the method to return true
SubscriptionsStore subs = new SubscriptionsStore() {
@@ -121,21 +127,22 @@ public class ProtocolProcessorTest {
storageService.initStore();
subs.init(storageService.sessionsStore());
m_processor.init(subs, m_messagesStore, m_sessionStore, null, true, new PermitAllAuthorizator(), NO_OBSERVERS_INTERCEPTOR);
ConnectMessage connectMessage = new ConnectMessage();
connectMessage.setProtocolVersion((byte) 3);
connectMessage.setClientID(FAKE_CLIENT_ID);
m_sessionStore.createNewSession(FAKE_CLIENT_ID, false);
connectMessage.setCleanSession(true);
MqttConnectMessage connectMessage = MessageBuilder.connect()
.protocolVersion(MqttVersion.MQTT_3_1)
.clientId(FAKE_CLIENT_ID)
.cleanSession(true)
.build();
m_processor.processConnect(m_channel, connectMessage);
//Exercise
ByteBuffer buffer = ByteBuffer.allocate(5).put("Hello".getBytes());
PublishMessage msg = new PublishMessage();
msg.setTopicName(FAKE_TOPIC);
msg.setQos(QOSType.MOST_ONE);
msg.setPayload(buffer);
msg.setRetainFlag(false);
MqttPublishMessage msg = MessageBuilder.publish()
.topicName(FAKE_TOPIC)
.qos(MqttQoS.AT_MOST_ONCE)
.retained(false)
.payload("Hello".getBytes())
.build();
NettyUtils.userName(m_channel, "FakeCLI");
m_processor.processPublish(m_channel, msg);
@@ -147,9 +154,9 @@ public class ProtocolProcessorTest {
@Test
public void testPublishToMultipleSubscribers() throws InterruptedException {
final Subscription subscription = new Subscription(FAKE_CLIENT_ID,
FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE);
FAKE_TOPIC, MqttQoS.AT_MOST_ONCE);
final Subscription subscriptionClient2 = new Subscription(FAKE_CLIENT_ID2,
FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE);
FAKE_TOPIC, MqttQoS.AT_MOST_ONCE);
//subscriptions.matches(topic) redefine the method to return true
SubscriptionsStore subs = new SubscriptionsStore() {
@@ -170,61 +177,62 @@ public class ProtocolProcessorTest {
m_processor.init(subs, m_messagesStore, m_sessionStore, null, true, new PermitAllAuthorizator(), NO_OBSERVERS_INTERCEPTOR);
EmbeddedChannel firstReceiverChannel = new EmbeddedChannel();
ConnectMessage connectMessage = new ConnectMessage();
connectMessage.setProtocolVersion((byte) 3);
connectMessage.setClientID(FAKE_CLIENT_ID);
connectMessage.setCleanSession(true);
MqttConnectMessage connectMessage = MessageBuilder.connect()
.protocolVersion(MqttVersion.MQTT_3_1)
.clientId(FAKE_CLIENT_ID)
.cleanSession(true)
.build();
m_processor.processConnect(firstReceiverChannel, connectMessage);
assertConnAckAccepted(firstReceiverChannel);
//connect the second fake subscriber
EmbeddedChannel secondReceiverChannel = new EmbeddedChannel();
ConnectMessage connectMessage2 = new ConnectMessage();
connectMessage2.setProtocolVersion((byte) 3);
connectMessage2.setClientID(FAKE_CLIENT_ID2);
connectMessage2.setCleanSession(true);
connectMessage2.setCleanSession(true);
MqttConnectMessage connectMessage2 = MessageBuilder.connect()
.protocolVersion(MqttVersion.MQTT_3_1)
.clientId(FAKE_CLIENT_ID2)
.cleanSession(true)
.build();
m_processor.processConnect(secondReceiverChannel, connectMessage2);
assertConnAckAccepted(secondReceiverChannel);
//Exercise
ByteBuffer buffer = ByteBuffer.allocate(5).put("Hello".getBytes());
buffer.rewind();
PublishMessage msg = new PublishMessage();
msg.setTopicName(FAKE_TOPIC);
msg.setQos(QOSType.MOST_ONE);
msg.setPayload(buffer);
msg.setRetainFlag(false);
MqttPublishMessage msg = MessageBuilder.publish()
.topicName(FAKE_TOPIC)
.qos(MqttQoS.AT_MOST_ONCE)
.retained(false)
.payload("Hello".getBytes())
.build();
NettyUtils.userName(m_channel, "FakeCLI");
m_processor.processPublish(m_channel, msg);
//Verify
firstReceiverChannel.flush();
PublishMessage pub2FirstSubscriber = (PublishMessage) firstReceiverChannel.readOutbound();
MqttPublishMessage pub2FirstSubscriber = firstReceiverChannel.readOutbound();
assertNotNull(pub2FirstSubscriber);
String firstMessageContent = DebugUtils.payload2Str(pub2FirstSubscriber.getPayload());
String firstMessageContent = DebugUtils.payload2Str(pub2FirstSubscriber.payload());
assertEquals("Hello", firstMessageContent);
secondReceiverChannel.flush();
PublishMessage pub2SecondSubscriber = (PublishMessage) secondReceiverChannel.readOutbound();
MqttPublishMessage pub2SecondSubscriber = secondReceiverChannel.readOutbound();
assertNotNull(pub2SecondSubscriber);
String secondMessageContent = DebugUtils.payload2Str(pub2SecondSubscriber.getPayload());
String secondMessageContent = DebugUtils.payload2Str(pub2SecondSubscriber.payload());
assertEquals("Hello", secondMessageContent);
}
@Test
public void testSubscribe() {
MqttSubscribeMessage msg = MessageBuilder.subscribe()
.addSubscription(MqttQoS.AT_MOST_ONCE, FAKE_TOPIC)
.messageId(10)
.build();
//Exercise
SubscribeMessage msg = new SubscribeMessage();
msg.addSubscription(new SubscribeMessage.Couple(AbstractMessage.QOSType.MOST_ONE.byteValue(), FAKE_TOPIC));
msg.setMessageID(10);
m_sessionStore.createNewSession(FAKE_CLIENT_ID, false);
m_processor.processSubscribe(m_channel, msg);
//Verify
assertTrue(m_channel.readOutbound() instanceof SubAckMessage);
Subscription expectedSubscription = new Subscription(FAKE_CLIENT_ID, FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE);
assertTrue(m_channel.readOutbound() instanceof MqttSubAckMessage);
Subscription expectedSubscription = new Subscription(FAKE_CLIENT_ID, FAKE_TOPIC, MqttQoS.AT_MOST_ONCE);
assertTrue(subscriptions.contains(expectedSubscription));
}
@@ -239,25 +247,33 @@ public class ProtocolProcessorTest {
mockAuthorizator, NO_OBSERVERS_INTERCEPTOR);
//Exercise
SubscribeMessage msg = new SubscribeMessage();
msg.setMessageID(10);
msg.addSubscription(new SubscribeMessage.Couple(AbstractMessage.QOSType.MOST_ONE.byteValue(), FAKE_TOPIC));
MqttSubscribeMessage msg = MessageBuilder.subscribe()
.addSubscription(MqttQoS.AT_MOST_ONCE, FAKE_TOPIC)
.messageId(10)
.build();
m_sessionStore.createNewSession(FAKE_CLIENT_ID, false);
m_processor.processSubscribe(m_channel, msg);
//Verify
Object ackMsg = m_channel.readOutbound();
assertTrue(ackMsg instanceof SubAckMessage);
SubAckMessage subAckMsg = (SubAckMessage) ackMsg;
assertEquals(1, subAckMsg.types().size());
assertTrue(subAckMsg.types().contains(AbstractMessage.QOSType.FAILURE));
assertTrue(ackMsg instanceof MqttSubAckMessage);
MqttSubAckMessage subAckMsg = (MqttSubAckMessage) ackMsg;
verifyFailureQos(subAckMsg);
}
private void verifyFailureQos(MqttSubAckMessage subAckMsg) {
List<Integer> grantedQoSes = subAckMsg.payload().grantedQoSLevels();
assertEquals(1, grantedQoSes.size());
assertTrue(grantedQoSes.contains(MqttQoS.FAILURE.value()));
}
@Test
public void testDoubleSubscribe() {
SubscribeMessage msg = new SubscribeMessage();
msg.setMessageID(10);
msg.addSubscription(new SubscribeMessage.Couple(AbstractMessage.QOSType.MOST_ONE.byteValue(), FAKE_TOPIC));
MqttSubscribeMessage msg = MessageBuilder.subscribe()
.addSubscription(MqttQoS.AT_MOST_ONCE, FAKE_TOPIC)
.messageId(10)
.build();
m_sessionStore.createNewSession(FAKE_CLIENT_ID, false);
assertEquals(0, subscriptions.size());
@@ -268,16 +284,18 @@ public class ProtocolProcessorTest {
//Verify
assertEquals(1, subscriptions.size());
Subscription expectedSubscription = new Subscription(FAKE_CLIENT_ID, FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE);
Subscription expectedSubscription = new Subscription(FAKE_CLIENT_ID, FAKE_TOPIC, MqttQoS.AT_MOST_ONCE);
assertTrue(subscriptions.contains(expectedSubscription));
}
@Test
public void testSubscribeWithBadFormattedTopic() {
SubscribeMessage msg = new SubscribeMessage();
msg.setMessageID(10);
msg.addSubscription(new SubscribeMessage.Couple(AbstractMessage.QOSType.MOST_ONE.byteValue(), BAD_FORMATTED_TOPIC));
MqttSubscribeMessage msg = MessageBuilder.subscribe()
.addSubscription(MqttQoS.AT_MOST_ONCE, BAD_FORMATTED_TOPIC)
.messageId(10)
.build();
m_sessionStore.createNewSession(FAKE_CLIENT_ID, false);
assertEquals(0, subscriptions.size());
@@ -287,10 +305,8 @@ public class ProtocolProcessorTest {
//Verify
assertEquals(0, subscriptions.size());
Object recvSubAckMessage = m_channel.readOutbound();
assertTrue(recvSubAckMessage instanceof SubAckMessage);
List<QOSType> qosSubAcked = ((SubAckMessage)recvSubAckMessage).types();
assertEquals(1, qosSubAcked.size());
assertEquals(QOSType.FAILURE, qosSubAcked.get(0));
assertTrue(recvSubAckMessage instanceof MqttSubAckMessage);
verifyFailureQos((MqttSubAckMessage) recvSubAckMessage);
}
/*
@@ -298,9 +314,10 @@ public class ProtocolProcessorTest {
* */
@Test
public void testUnsubscribeWithBadFormattedTopic() {
UnsubscribeMessage msg = new UnsubscribeMessage();
msg.setMessageID(1);
msg.addTopicFilter(BAD_FORMATTED_TOPIC);
MqttUnsubscribeMessage msg = MessageBuilder.unsubscribe()
.addTopicFilter(BAD_FORMATTED_TOPIC)
.messageId(1)
.build();
//Exercise
m_processor.processUnsubscribe(m_channel, msg);
@@ -314,7 +331,7 @@ public class ProtocolProcessorTest {
public void testPublishOfRetainedMessage_afterNewSubscription() throws Exception {
//simulate a connect that register a clientID to an IoSession
final Subscription subscription = new Subscription(FAKE_PUBLISHER_ID,
FAKE_TOPIC, AbstractMessage.QOSType.MOST_ONE);
FAKE_TOPIC, MqttQoS.AT_MOST_ONCE);
//subscriptions.matches(topic) redefine the method to return true
SubscriptionsStore subs = new SubscriptionsStore() {
@@ -333,34 +350,38 @@ public class ProtocolProcessorTest {
//simulate a connect that register a clientID to an IoSession
m_processor.init(subs, m_messagesStore, m_sessionStore, null, true, new PermitAllAuthorizator(), NO_OBSERVERS_INTERCEPTOR);
ConnectMessage connectMessage = new ConnectMessage();
connectMessage.setClientID(FAKE_PUBLISHER_ID);
connectMessage.setProtocolVersion((byte) 3);
connectMessage.setCleanSession(true);
MqttConnectMessage connectMessage = MessageBuilder.connect()
.clientId(FAKE_PUBLISHER_ID)
.protocolVersion(MqttVersion.MQTT_3_1)
.cleanSession(true)
.build();
m_processor.processConnect(m_channel, connectMessage);
assertConnAckAccepted(m_channel);
ByteBuffer buffer = ByteBuffer.allocate(5).put("Hello".getBytes());
PublishMessage pubmsg = new PublishMessage();
pubmsg.setTopicName(FAKE_TOPIC);
pubmsg.setQos(QOSType.MOST_ONE);
pubmsg.setPayload(buffer);
pubmsg.setRetainFlag(true);
MqttPublishMessage pubmsg = MessageBuilder.publish()
.topicName(FAKE_TOPIC)
.qos(MqttQoS.AT_MOST_ONCE)
.payload("Hello".getBytes())
.retained(true)
.build();
NettyUtils.clientID(m_channel, FAKE_PUBLISHER_ID);
m_processor.processPublish(m_channel, pubmsg);
NettyUtils.cleanSession(m_channel, false);
//Exercise
SubscribeMessage msg = new SubscribeMessage();
msg.setMessageID(10);
msg.addSubscription(new SubscribeMessage.Couple(QOSType.MOST_ONE.byteValue(), "#"));
MqttSubscribeMessage msg = MessageBuilder.subscribe()
.messageId(10)
.addSubscription(MqttQoS.AT_MOST_ONCE, "#")
.build();
m_processor.processSubscribe(m_channel, msg);
//Verify
//wait the latch
Object pubMessage = m_channel.readOutbound();
assertNotNull(pubMessage);
assertTrue(pubMessage instanceof PublishMessage);
assertEquals(FAKE_TOPIC, ((PublishMessage) pubMessage).getTopicName());
assertTrue(pubMessage instanceof MqttPublishMessage);
assertEquals(FAKE_TOPIC, ((MqttPublishMessage) pubMessage).variableHeader().topicName());
}
@Test
@@ -369,17 +390,19 @@ public class ProtocolProcessorTest {
List<Subscription> emptySubs = Collections.emptyList();
when(subs.matches(anyString())).thenReturn(emptySubs);
StoredMessage retainedMessage = new StoredMessage("Hello".getBytes(), QOSType.EXACTLY_ONCE, "/topic");
StoredMessage retainedMessage = new StoredMessage("Hello".getBytes(), MqttQoS.EXACTLY_ONCE, "/topic");
retainedMessage.setRetained(true);
retainedMessage.setMessageID(120);
retainedMessage.setClientID(FAKE_PUBLISHER_ID);
m_messagesStore.storePublishForFuture(retainedMessage);
m_processor.init(subs, m_messagesStore, m_sessionStore, null, true, new PermitAllAuthorizator(), NO_OBSERVERS_INTERCEPTOR);
ConnectMessage connectMessage = new ConnectMessage();
connectMessage.setClientID(FAKE_PUBLISHER_ID);
connectMessage.setProtocolVersion((byte) 3);
connectMessage.setCleanSession(false);
MqttConnectMessage connectMessage = MessageBuilder.connect()
.clientId(FAKE_PUBLISHER_ID)
.protocolVersion(MqttVersion.MQTT_3_1)
.build();
m_processor.processConnect(m_channel, connectMessage);
//Verify no messages are still stored
@@ -393,7 +416,7 @@ public class ProtocolProcessorTest {
m_sessionStore.createNewSession("Subscriber", false);
SubscriptionsStore mockedSubscriptions = mock(SubscriptionsStore.class);
Subscription inactiveSub = new Subscription("Subscriber", "/topic", QOSType.LEAST_ONE);
Subscription inactiveSub = new Subscription("Subscriber", "/topic", MqttQoS.AT_LEAST_ONCE);
List<Subscription> inactiveSubscriptions = Collections.singletonList(inactiveSub);
when(mockedSubscriptions.matches(eq("/topic"))).thenReturn(inactiveSubscriptions);
m_processor = new ProtocolProcessor();
@@ -401,12 +424,13 @@ public class ProtocolProcessorTest {
NO_OBSERVERS_INTERCEPTOR);
//Exercise
ByteBuffer buffer = ByteBuffer.allocate(5).put("Hello".getBytes());
PublishMessage msg = new PublishMessage();
msg.setTopicName("/topic");
msg.setQos(QOSType.MOST_ONE);
msg.setPayload(buffer);
msg.setRetainFlag(true);
MqttPublishMessage msg = MessageBuilder.publish()
.topicName("/topic")
.qos(MqttQoS.AT_MOST_ONCE)
.payload("Hello".getBytes())
.retained(true)
.build();
NettyUtils.clientID(m_channel, "Publisher");
m_processor.processPublish(m_channel, msg);
@@ -421,25 +445,31 @@ public class ProtocolProcessorTest {
@Test
public void testCleanRetainedStoreAfterAQoS0AndRetainedTrue() {
//force a connect
connMsg.setClientID("Publisher");
connMsg = MessageBuilder.connect()
.protocolVersion(MqttVersion.MQTT_3_1)
.clientId("Publisher")
.cleanSession(true)
.build();
m_processor.processConnect(m_channel, connMsg);
//prepare and existing retained store
NettyUtils.clientID(m_channel, "Publisher");
ByteBuffer payload = ByteBuffer.allocate(5).put("Hello".getBytes());
PublishMessage msg = new PublishMessage();
msg.setTopicName(FAKE_TOPIC);
msg.setQos(QOSType.LEAST_ONE);
msg.setPayload(payload);
msg.setRetainFlag(true);
msg.setMessageID(100);
MqttPublishMessage msg = MessageBuilder.publish()
.topicName(FAKE_TOPIC)
.qos(MqttQoS.AT_LEAST_ONCE)
.payload("Hello".getBytes())
.retained(true)
.messageId(100)
.build();
m_processor.processPublish(m_channel, msg);
//Exercise
PublishMessage cleanPubMsg = new PublishMessage();
cleanPubMsg.setTopicName(FAKE_TOPIC);
cleanPubMsg.setPayload(payload);
cleanPubMsg.setQos(QOSType.MOST_ONE);
cleanPubMsg.setRetainFlag(true);
MqttPublishMessage cleanPubMsg = MessageBuilder.publish()
.topicName(FAKE_TOPIC)
.qos(MqttQoS.AT_MOST_ONCE)
.payload("Hello".getBytes())
.retained(true)
.build();
m_processor.processPublish(m_channel, cleanPubMsg);
//Verify
@@ -453,10 +483,10 @@ public class ProtocolProcessorTest {
@Test
public void testLowerTheQosToTheRequestedBySubscription() {
Subscription subQos1 = new Subscription("Sub A", "a/b", QOSType.LEAST_ONE);
assertEquals(QOSType.LEAST_ONE, lowerQosToTheSubscriptionDesired(subQos1, QOSType.EXACTLY_ONCE));
Subscription subQos1 = new Subscription("Sub A", "a/b", MqttQoS.AT_LEAST_ONCE);
assertEquals(MqttQoS.AT_LEAST_ONCE, lowerQosToTheSubscriptionDesired(subQos1, MqttQoS.EXACTLY_ONCE));
Subscription subQos2 = new Subscription("Sub B", "a/+", QOSType.EXACTLY_ONCE);
assertEquals(QOSType.EXACTLY_ONCE, lowerQosToTheSubscriptionDesired(subQos2, QOSType.EXACTLY_ONCE));
Subscription subQos2 = new Subscription("Sub B", "a/+", MqttQoS.EXACTLY_ONCE);
assertEquals(MqttQoS.EXACTLY_ONCE, lowerQosToTheSubscriptionDesired(subQos2, MqttQoS.EXACTLY_ONCE));
}
}
@@ -15,17 +15,19 @@
*/
package io.moquette.spi.impl;
import io.moquette.parser.proto.messages.AbstractMessage;
import io.moquette.parser.proto.messages.ConnectMessage;
import io.moquette.parser.proto.messages.SubscribeMessage;
import io.moquette.server.netty.MessageBuilder;
import io.moquette.server.netty.NettyUtils;
import io.moquette.spi.ClientSession;
import io.moquette.spi.IMessagesStore;
import io.moquette.spi.ISessionsStore;
import io.moquette.spi.impl.subscriptions.SubscriptionsStore;
import io.moquette.spi.impl.security.PermitAllAuthorizator;
import io.moquette.spi.impl.subscriptions.Subscription;
import io.moquette.spi.impl.subscriptions.SubscriptionsStore;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.mqtt.MqttConnectMessage;
import io.netty.handler.codec.mqtt.MqttQoS;
import io.netty.handler.codec.mqtt.MqttSubscribeMessage;
import io.netty.handler.codec.mqtt.MqttVersion;
import org.junit.Before;
import org.junit.Test;
@@ -34,10 +36,9 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static io.moquette.parser.netty.Utils.VERSION_3_1_1;
import static io.moquette.parser.proto.messages.ConnAckMessage.*;
import static io.moquette.spi.impl.NettyChannelAssertions.assertEqualsConnAck;
import static io.moquette.spi.impl.NettyChannelAssertions.assertEqualsSubAck;
import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.*;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -48,7 +49,7 @@ import static org.junit.Assert.assertTrue;
public class ProtocolProcessor_CONNECT_Test {
EmbeddedChannel m_session;
ConnectMessage connMsg;
MessageBuilder.ConnectBuilder connMsg;
ProtocolProcessor m_processor;
IMessagesStore m_messagesStore;
@@ -58,8 +59,9 @@ public class ProtocolProcessor_CONNECT_Test {
@Before
public void setUp() throws InterruptedException {
connMsg = new ConnectMessage();
connMsg.setProtocolVersion((byte) 0x03);
connMsg = MessageBuilder.connect()
.protocolVersion(MqttVersion.MQTT_3_1)
.cleanSession(true);
m_session = new EmbeddedChannel();
@@ -73,7 +75,7 @@ public class ProtocolProcessor_CONNECT_Test {
Set<String> clientIds = new HashSet<>();
clientIds.add(ProtocolProcessorTest.FAKE_CLIENT_ID);
Map<String, byte[]> users = new HashMap<>();
Map<String, String> users = new HashMap<>();
users.put(ProtocolProcessorTest.TEST_USER, ProtocolProcessorTest.TEST_PWD);
m_mockAuthenticator = new MockAuthenticator(clientIds, users);
@@ -84,24 +86,24 @@ public class ProtocolProcessor_CONNECT_Test {
new PermitAllAuthorizator(), ProtocolProcessorTest.NO_OBSERVERS_INTERCEPTOR);
}
@Test
public void testHandleConnect_BadProtocol() {
connMsg.setProtocolVersion((byte) 0x02);
//Exercise
m_processor.processConnect(m_session, connMsg);
//Verify
assertEqualsConnAck(UNNACEPTABLE_PROTOCOL_VERSION, m_session.readOutbound());
assertFalse("Connection should be closed by the broker.", m_session.isOpen());
}
// @Test
// public void testHandleConnect_BadProtocol() {
// connMsg.setProtocolVersion((byte) 0x02);
//
// //Exercise
// m_processor.processConnect(m_session, connMsg);
//
// //Verify
// assertEqualsConnAck(UNNACEPTABLE_PROTOCOL_VERSION, m_session.readOutbound());
// assertFalse("Connection should be closed by the broker.", m_session.isOpen());
// }
@Test
public void testConnect_badClientID() {
connMsg.setClientID("extremely_long_clientID_greater_than_23");
connMsg.clientId("extremely_long_clientID_greater_than_23").build();
//Exercise
m_processor.processConnect(m_session, connMsg);
m_processor.processConnect(m_session, connMsg.clientId("extremely_long_clientID_greater_than_23").build());
//Verify
assertEqualsConnAck(CONNECTION_ACCEPTED, m_session.readOutbound());
@@ -109,15 +111,16 @@ public class ProtocolProcessor_CONNECT_Test {
@Test
public void testWill() {
connMsg.setClientID(ProtocolProcessorTest.FAKE_CLIENT_ID);
connMsg.setWillFlag(true);
connMsg.setWillTopic("topic");
connMsg.setWillMessage("Topic message".getBytes());
MqttConnectMessage msg = connMsg
.clientId(ProtocolProcessorTest.FAKE_CLIENT_ID)
.willFlag(true)
.willTopic("topic")
.willMessage("Topic message")
.build();
//Exercise
//m_handler.setMessaging(mockedMessaging);
m_processor.processConnect(m_session, connMsg);
m_processor.processConnect(m_session, msg);
//Verify
assertEqualsConnAck(CONNECTION_ACCEPTED, m_session.readOutbound());
@@ -129,14 +132,16 @@ public class ProtocolProcessor_CONNECT_Test {
@Test
public void validAuthentication() {
connMsg.setClientID(ProtocolProcessorTest.FAKE_CLIENT_ID);
connMsg.setUserFlag(true);
connMsg.setPasswordFlag(true);
connMsg.setUsername(ProtocolProcessorTest.TEST_USER);
connMsg.setPassword(ProtocolProcessorTest.TEST_PWD);
MqttConnectMessage msg = connMsg
.clientId(ProtocolProcessorTest.FAKE_CLIENT_ID)
.hasUser()
.hasPassword()
.username(ProtocolProcessorTest.TEST_USER)
.password(ProtocolProcessorTest.TEST_PWD)
.build();
//Exercise
m_processor.processConnect(m_session, connMsg);
m_processor.processConnect(m_session, msg);
//Verify
assertEqualsConnAck(CONNECTION_ACCEPTED, m_session.readOutbound());
@@ -145,73 +150,82 @@ public class ProtocolProcessor_CONNECT_Test {
@Test
public void noPasswdAuthentication() {
connMsg.setClientID(ProtocolProcessorTest.FAKE_CLIENT_ID);
connMsg.setUserFlag(true);
connMsg.setPasswordFlag(false);
connMsg.setUsername(ProtocolProcessorTest.TEST_USER);
MqttConnectMessage msg = connMsg
.clientId(ProtocolProcessorTest.FAKE_CLIENT_ID)
.hasUser()
.username(ProtocolProcessorTest.TEST_USER)
.build();
//Exercise
m_processor.processConnect(m_session, connMsg);
m_processor.processConnect(m_session, msg);
//Verify
assertEqualsConnAck(BAD_USERNAME_OR_PASSWORD, m_session.readOutbound());
assertEqualsConnAck(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD, m_session.readOutbound());
assertFalse("Connection should be closed by the broker.", m_session.isOpen());
}
@Test
public void invalidAuthentication() {
connMsg.setClientID(ProtocolProcessorTest.FAKE_CLIENT_ID);
connMsg.setUserFlag(true);
connMsg.setPasswordFlag(true);
connMsg.setUsername(ProtocolProcessorTest.TEST_USER + "_fake");
connMsg.setPassword(ProtocolProcessorTest.TEST_PWD);
MqttConnectMessage msg = connMsg
.clientId(ProtocolProcessorTest.FAKE_CLIENT_ID)
.hasUser()
.hasPassword()
.username(ProtocolProcessorTest.TEST_USER + "_fake")
.password(ProtocolProcessorTest.TEST_PWD)
.build();
//Exercise
m_processor.processConnect(m_session, connMsg);
m_processor.processConnect(m_session, msg);
//Verify
assertEqualsConnAck(BAD_USERNAME_OR_PASSWORD, m_session.readOutbound());
assertEqualsConnAck(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD, m_session.readOutbound());
assertFalse("Connection should be closed by the broker.", m_session.isOpen());
}
@Test
public void prohibitAnonymousClient() {
connMsg.setClientID(ProtocolProcessorTest.FAKE_CLIENT_ID);
MqttConnectMessage msg = connMsg
.clientId(ProtocolProcessorTest.FAKE_CLIENT_ID)
.build();
m_processor.init(subscriptions, m_messagesStore, m_sessionStore, m_mockAuthenticator, false,
new PermitAllAuthorizator(), ProtocolProcessorTest.NO_OBSERVERS_INTERCEPTOR);
//Exercise
m_processor.processConnect(m_session, connMsg);
m_processor.processConnect(m_session, msg);
//Verify
assertEqualsConnAck(BAD_USERNAME_OR_PASSWORD, m_session.readOutbound());
assertEqualsConnAck(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD, m_session.readOutbound());
assertFalse("Connection should be closed by the broker.", m_session.isOpen());
}
@Test
public void prohibitAnonymousClient_providingUsername() {
connMsg.setClientID(ProtocolProcessorTest.FAKE_CLIENT_ID);
connMsg.setUserFlag(true);
connMsg.setUsername(ProtocolProcessorTest.TEST_USER + "_fake");
MqttConnectMessage msg = connMsg
.clientId(ProtocolProcessorTest.FAKE_CLIENT_ID)
.hasUser()
.username(ProtocolProcessorTest.TEST_USER + "_fake")
.build();
m_processor.init(subscriptions, m_messagesStore, m_sessionStore, m_mockAuthenticator, false,
new PermitAllAuthorizator(), ProtocolProcessorTest.NO_OBSERVERS_INTERCEPTOR);
//Exercise
m_processor.processConnect(m_session, connMsg);
m_processor.processConnect(m_session, msg);
//Verify
assertEqualsConnAck(BAD_USERNAME_OR_PASSWORD, m_session.readOutbound());
assertEqualsConnAck(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD, m_session.readOutbound());
assertFalse("Connection should be closed by the broker.", m_session.isOpen());
}
@Test
public void acceptAnonymousClient() {
connMsg.setClientID(ProtocolProcessorTest.FAKE_CLIENT_ID);
MqttConnectMessage msg = connMsg
.clientId(ProtocolProcessorTest.FAKE_CLIENT_ID)
.build();
m_processor.init(subscriptions, m_messagesStore, m_sessionStore, m_mockAuthenticator, true,
new PermitAllAuthorizator(), ProtocolProcessorTest.NO_OBSERVERS_INTERCEPTOR);
//Exercise
m_processor.processConnect(m_session, connMsg);
m_processor.processConnect(m_session, msg);
//Verify
assertEqualsConnAck(CONNECTION_ACCEPTED, m_session.readOutbound());
@@ -224,18 +238,22 @@ public class ProtocolProcessor_CONNECT_Test {
new PermitAllAuthorizator(), ProtocolProcessorTest.NO_OBSERVERS_INTERCEPTOR);
//first connect with clean session true
connMsg.setClientID(ProtocolProcessorTest.FAKE_CLIENT_ID);
connMsg.setCleanSession(true);
m_processor.processConnect(m_session, connMsg);
MqttConnectMessage msg = connMsg
.clientId(ProtocolProcessorTest.FAKE_CLIENT_ID)
.cleanSession(true)
.build();
m_processor.processConnect(m_session, msg);
assertEqualsConnAck(CONNECTION_ACCEPTED, m_session.readOutbound());
m_processor.processDisconnect(m_session);
assertFalse(m_session.isOpen());
//second connect with clean session false
m_session = new EmbeddedChannel();
ConnectMessage secondConnMsg = new ConnectMessage();
secondConnMsg.setProtocolVersion((byte) 0x03);
secondConnMsg.setClientID(ProtocolProcessorTest.FAKE_CLIENT_ID);
MqttConnectMessage secondConnMsg = MessageBuilder.connect()
.clientId(ProtocolProcessorTest.FAKE_CLIENT_ID)
.protocolVersion(MqttVersion.MQTT_3_1)
.build();
m_processor.processConnect(m_session, secondConnMsg);
assertEqualsConnAck(CONNECTION_ACCEPTED, m_session.readOutbound());
@@ -250,22 +268,24 @@ public class ProtocolProcessor_CONNECT_Test {
@Test
public void connectWithSameClientIDBadCredentialsDoesntDropExistingClient() {
//Connect a client1
connMsg.setClientID(ProtocolProcessorTest.FAKE_CLIENT_ID);
connMsg.setUserFlag(true);
connMsg.setPasswordFlag(true);
connMsg.setUsername(ProtocolProcessorTest.TEST_USER);
connMsg.setPassword(ProtocolProcessorTest.TEST_PWD);
m_processor.processConnect(m_session, connMsg);
MqttConnectMessage msg = connMsg
.clientId(ProtocolProcessorTest.FAKE_CLIENT_ID)
.hasUser()
.hasPassword()
.username(ProtocolProcessorTest.TEST_USER)
.password(ProtocolProcessorTest.TEST_PWD)
.build();
m_processor.processConnect(m_session, msg);
assertEqualsConnAck(CONNECTION_ACCEPTED, m_session.readOutbound());
//create another connect same clientID but with bad credentials
ConnectMessage evilClientConnMsg = new ConnectMessage();
evilClientConnMsg.setProtocolVersion((byte) 0x03);
evilClientConnMsg.setClientID(ProtocolProcessorTest.FAKE_CLIENT_ID);
evilClientConnMsg.setUserFlag(true);
evilClientConnMsg.setPasswordFlag(true);
evilClientConnMsg.setUsername(ProtocolProcessorTest.EVIL_TEST_USER);
evilClientConnMsg.setPassword(ProtocolProcessorTest.EVIL_TEST_PWD);
MqttConnectMessage evilClientConnMsg = MessageBuilder.connect().
protocolVersion(MqttVersion.MQTT_3_1)
.clientId(ProtocolProcessorTest.FAKE_CLIENT_ID)
.hasUser().username(ProtocolProcessorTest.EVIL_TEST_USER)
.hasPassword().password(ProtocolProcessorTest.EVIL_TEST_PWD)
.build();
EmbeddedChannel evilSession = new EmbeddedChannel();
//Exercise
@@ -273,7 +293,7 @@ public class ProtocolProcessor_CONNECT_Test {
//Verify
//the evil client gets a not auth notification
assertEqualsConnAck(BAD_USERNAME_OR_PASSWORD, evilSession.readOutbound());
assertEqualsConnAck(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD, evilSession.readOutbound());
//the good client remains connected
assertTrue(m_session.isOpen());
assertFalse(evilSession.isOpen());
@@ -282,21 +302,21 @@ public class ProtocolProcessor_CONNECT_Test {
@Test
public void testConnAckContainsSessionPresentFlag() throws InterruptedException {
connMsg = new ConnectMessage();
connMsg.setProtocolVersion(VERSION_3_1_1);
connMsg.setClientID(ProtocolProcessorTest.FAKE_CLIENT_ID);
connMsg.setCleanSession(false);
MqttConnectMessage msg = connMsg
.clientId(ProtocolProcessorTest.FAKE_CLIENT_ID)
.protocolVersion(MqttVersion.MQTT_3_1_1)
.build();
NettyUtils.clientID(m_session, ProtocolProcessorTest.FAKE_CLIENT_ID);
NettyUtils.cleanSession(m_session, false);
//Connect a first time
m_processor.processConnect(m_session, connMsg);
m_processor.processConnect(m_session, msg);
//disconnect
m_processor.processDisconnect(m_session);
//Exercise, reconnect
EmbeddedChannel firstReceiverSession = new EmbeddedChannel();
m_processor.processConnect(firstReceiverSession, connMsg);
m_processor.processConnect(firstReceiverSession, msg);
//Verify
assertEqualsConnAck(CONNECTION_ACCEPTED, firstReceiverSession.readOutbound());
@@ -307,24 +327,25 @@ public class ProtocolProcessor_CONNECT_Test {
@Test
public void testMultipleReconnection() throws InterruptedException {
//connect with clean a false and subscribe to a topic
connMsg = new ConnectMessage();
connMsg.setProtocolVersion(VERSION_3_1_1);
connMsg.setClientID(ProtocolProcessorTest.FAKE_CLIENT_ID);
connMsg.setCleanSession(false);
m_processor.processConnect(m_session, connMsg);
MqttConnectMessage msg = MessageBuilder.connect()
.clientId(ProtocolProcessorTest.FAKE_CLIENT_ID)
.protocolVersion(MqttVersion.MQTT_3_1_1)
.build();
m_processor.processConnect(m_session, msg);
assertEqualsConnAck(CONNECTION_ACCEPTED, m_session.readOutbound());
assertTrue("Connection is accepted and therefore should remain open.", m_session.isOpen());
//subscribe
SubscribeMessage subscribeMsg = new SubscribeMessage();
subscribeMsg.setMessageID(10);
subscribeMsg.addSubscription(new SubscribeMessage.Couple((byte) AbstractMessage.QOSType.MOST_ONE.ordinal(),
ProtocolProcessorTest.FAKE_TOPIC));
MqttSubscribeMessage subscribeMsg = MessageBuilder.subscribe()
.addSubscription(MqttQoS.AT_MOST_ONCE, ProtocolProcessorTest.FAKE_TOPIC)
.messageId(10)
.build();
NettyUtils.clientID(m_session, ProtocolProcessorTest.FAKE_CLIENT_ID);
NettyUtils.cleanSession(m_session, false);
m_processor.processSubscribe(m_session, subscribeMsg);
Subscription expectedSubscription = new Subscription(ProtocolProcessorTest.FAKE_CLIENT_ID, ProtocolProcessorTest.FAKE_TOPIC,
AbstractMessage.QOSType.MOST_ONE);
MqttQoS.AT_MOST_ONCE);
assertTrue(subscriptions.contains(expectedSubscription));
assertEqualsSubAck(m_session.readOutbound());
@@ -334,7 +355,7 @@ public class ProtocolProcessor_CONNECT_Test {
//reconnect clean session a false
m_session = new EmbeddedChannel();
m_processor.processConnect(m_session, connMsg);
m_processor.processConnect(m_session, msg);
assertEqualsConnAck(CONNECTION_ACCEPTED, m_session.readOutbound());
assertTrue("Connection is accepted and therefore should remain open.", m_session.isOpen());
@@ -350,14 +371,14 @@ public class ProtocolProcessor_CONNECT_Test {
new PermitAllAuthorizator(), ProtocolProcessorTest.NO_OBSERVERS_INTERCEPTOR);
// Connect message without clean session set to true but client id is still null
connMsg = new ConnectMessage();
connMsg.setProtocolVersion(VERSION_3_1_1);
connMsg.setClientID(null);
connMsg.setCleanSession(false);
MqttConnectMessage msg = MessageBuilder.connect()
.clientId(null)
.protocolVersion(MqttVersion.MQTT_3_1_1)
.build();
m_processor.processConnect(m_session, connMsg);
m_processor.processConnect(m_session, msg);
assertEqualsConnAck("Identifier should be rejected due to having clean session set to false.",
IDENTIFIER_REJECTED, m_session.readOutbound());
CONNECTION_REFUSED_IDENTIFIER_REJECTED, m_session.readOutbound());
assertFalse("Connection should be closed by the broker.", m_session.isOpen());
}
@@ -370,12 +391,13 @@ public class ProtocolProcessor_CONNECT_Test {
new PermitAllAuthorizator(), ProtocolProcessorTest.NO_OBSERVERS_INTERCEPTOR);
// Connect message with clean session set to true and client id is null.
connMsg = new ConnectMessage();
connMsg.setProtocolVersion(VERSION_3_1_1);
connMsg.setClientID(null);
connMsg.setCleanSession(true);
MqttConnectMessage msg = connMsg
.clientId(null)
.protocolVersion(MqttVersion.MQTT_3_1_1)
.cleanSession(true)
.build();
m_processor.processConnect(m_session, connMsg);
m_processor.processConnect(m_session, msg);
assertEqualsConnAck("Connection should be accepted. A unique clientid should be generated" +
" and clean session set to true.", CONNECTION_ACCEPTED, m_session.readOutbound());
@@ -385,14 +407,15 @@ public class ProtocolProcessor_CONNECT_Test {
@Test
public void testZeroByteClientIdNotAllowed() {
// Connect message with clean session set to true and client id is null.
connMsg = new ConnectMessage();
connMsg.setProtocolVersion(VERSION_3_1_1);
connMsg.setClientID(null);
connMsg.setCleanSession(true);
MqttConnectMessage msg = connMsg
.clientId(null)
.protocolVersion(MqttVersion.MQTT_3_1_1)
.cleanSession(true)
.build();
m_processor.processConnect(m_session, connMsg);
m_processor.processConnect(m_session, msg);
assertEqualsConnAck("Zero byte client identifiers are not allowed.",
IDENTIFIER_REJECTED, m_session.readOutbound());
CONNECTION_REFUSED_IDENTIFIER_REJECTED, m_session.readOutbound());
assertFalse("Connection should closed.", m_session.isOpen());
}
@@ -15,20 +15,20 @@
*/
package io.moquette.spi.impl.subscriptions;
import io.moquette.spi.ClientSession;
import io.moquette.spi.ISessionsStore;
import io.moquette.spi.ISessionsStore.ClientTopicCouple;
import io.moquette.spi.impl.MemoryStorageService;
import io.netty.handler.codec.mqtt.MqttQoS;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.text.ParseException;
import java.util.Arrays;
import java.util.List;
import io.moquette.spi.ClientSession;
import io.moquette.spi.ISessionsStore;
import io.moquette.spi.ISessionsStore.ClientTopicCouple;
import io.moquette.spi.impl.MemoryStorageService;
import io.moquette.parser.proto.messages.AbstractMessage;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
/**
*
@@ -106,12 +106,12 @@ public class SubscriptionsStoreTest {
@Test
public void testMatchSimple() {
Subscription slashSub = new Subscription("FAKE_CLI_ID_1", "/", AbstractMessage.QOSType.MOST_ONE);
Subscription slashSub = new Subscription("FAKE_CLI_ID_1", "/", MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(slashSub);
store.add(slashSub.asClientTopicCouple());
assertTrue(store.matches("finance").isEmpty());
Subscription slashFinanceSub = new Subscription("FAKE_CLI_ID_1", "/finance", AbstractMessage.QOSType.MOST_ONE);
Subscription slashFinanceSub = new Subscription("FAKE_CLI_ID_1", "/finance", MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(slashFinanceSub);
store.add(slashFinanceSub.asClientTopicCouple());
assertTrue(store.matches("finance").isEmpty());
@@ -122,12 +122,12 @@ public class SubscriptionsStoreTest {
@Test
public void testMatchSimpleMulti() {
Subscription anySub = new Subscription("FAKE_CLI_ID_1", "#", AbstractMessage.QOSType.MOST_ONE);
Subscription anySub = new Subscription("FAKE_CLI_ID_1", "#", MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(anySub);
store.add(anySub.asClientTopicCouple());
assertTrue(store.matches("finance").contains(anySub));
Subscription financeAnySub = new Subscription("FAKE_CLI_ID_2", "finance/#", AbstractMessage.QOSType.MOST_ONE);
Subscription financeAnySub = new Subscription("FAKE_CLI_ID_2", "finance/#", MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(financeAnySub);
store.add(financeAnySub.asClientTopicCouple());
assertTrue(store.matches("finance").containsAll(Arrays.asList(financeAnySub, anySub)));
@@ -135,8 +135,8 @@ public class SubscriptionsStoreTest {
@Test
public void testMatchingDeepMulti_one_layer() {
Subscription anySub = new Subscription("FAKE_CLI_ID_1", "#", AbstractMessage.QOSType.MOST_ONE);
Subscription financeAnySub = new Subscription("FAKE_CLI_ID_2", "finance/#", AbstractMessage.QOSType.MOST_ONE);
Subscription anySub = new Subscription("FAKE_CLI_ID_1", "#", MqttQoS.AT_MOST_ONCE);
Subscription financeAnySub = new Subscription("FAKE_CLI_ID_2", "finance/#", MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(anySub);
sessionsStore.addNewSubscription(financeAnySub);
store.add(anySub.asClientTopicCouple());
@@ -150,7 +150,7 @@ public class SubscriptionsStoreTest {
@Test
public void testMatchingDeepMulti_two_layer() {
Subscription financeAnySub = new Subscription("FAKE_CLI_ID_1", "finance/stock/#", AbstractMessage.QOSType.MOST_ONE);
Subscription financeAnySub = new Subscription("FAKE_CLI_ID_1", "finance/stock/#", MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(financeAnySub);
store.add(financeAnySub.asClientTopicCouple());
@@ -160,12 +160,12 @@ public class SubscriptionsStoreTest {
@Test
public void testMatchSimpleSingle() {
Subscription anySub = new Subscription("FAKE_CLI_ID_1", "+", AbstractMessage.QOSType.MOST_ONE);
Subscription anySub = new Subscription("FAKE_CLI_ID_1", "+", MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(anySub);
store.add(anySub.asClientTopicCouple());
assertTrue(store.matches("finance").contains(anySub));
Subscription financeOne = new Subscription("FAKE_CLI_ID_1", "finance/+", AbstractMessage.QOSType.MOST_ONE);
Subscription financeOne = new Subscription("FAKE_CLI_ID_1", "finance/+", MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(financeOne);
store.add(financeOne.asClientTopicCouple());
assertTrue(store.matches("finance/stock").contains(financeOne));
@@ -173,7 +173,7 @@ public class SubscriptionsStoreTest {
@Test
public void testMatchManySingle() {
Subscription manySub = new Subscription("FAKE_CLI_ID_1", "+/+", AbstractMessage.QOSType.MOST_ONE);
Subscription manySub = new Subscription("FAKE_CLI_ID_1", "+/+", MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(manySub);
store.add(manySub.asClientTopicCouple());
@@ -184,10 +184,10 @@ public class SubscriptionsStoreTest {
@Test
public void testMatchSlashSingle() {
Subscription slashPlusSub = new Subscription("FAKE_CLI_ID_1", "/+", AbstractMessage.QOSType.MOST_ONE);
Subscription slashPlusSub = new Subscription("FAKE_CLI_ID_1", "/+", MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(slashPlusSub);
store.add(slashPlusSub.asClientTopicCouple());
Subscription anySub = new Subscription("FAKE_CLI_ID_1", "+", AbstractMessage.QOSType.MOST_ONE);
Subscription anySub = new Subscription("FAKE_CLI_ID_1", "+", MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(anySub);
store.add(anySub.asClientTopicCouple());
@@ -200,11 +200,11 @@ public class SubscriptionsStoreTest {
@Test
public void testMatchManyDeepSingle() {
Subscription slashPlusSub = new Subscription("FAKE_CLI_ID_1", "/finance/+/ibm", AbstractMessage.QOSType.MOST_ONE);
Subscription slashPlusSub = new Subscription("FAKE_CLI_ID_1", "/finance/+/ibm", MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(slashPlusSub);
store.add(slashPlusSub.asClientTopicCouple());
Subscription slashPlusDeepSub = new Subscription("FAKE_CLI_ID_2", "/+/stock/+", AbstractMessage.QOSType.MOST_ONE);
Subscription slashPlusDeepSub = new Subscription("FAKE_CLI_ID_2", "/+/stock/+", MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(slashPlusDeepSub);
store.add(slashPlusDeepSub.asClientTopicCouple());
@@ -214,7 +214,7 @@ public class SubscriptionsStoreTest {
@Test
public void testMatchSimpleMulti_allTheTree() {
Subscription sub = new Subscription("FAKE_CLI_ID_1", "#", AbstractMessage.QOSType.MOST_ONE);
Subscription sub = new Subscription("FAKE_CLI_ID_1", "#", MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(sub);
store.add(sub.asClientTopicCouple());
assertFalse(store.matches("finance").isEmpty());
@@ -224,7 +224,7 @@ public class SubscriptionsStoreTest {
@Test
public void testMatchSimpleMulti_zeroLevel() {
//check MULTI in case of zero level match
Subscription sub = new Subscription("FAKE_CLI_ID_1", "finance/#", AbstractMessage.QOSType.MOST_ONE);
Subscription sub = new Subscription("FAKE_CLI_ID_1", "finance/#", MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(sub);
store.add(sub.asClientTopicCouple());
assertFalse(store.matches("finance").isEmpty());
@@ -260,7 +260,7 @@ public class SubscriptionsStoreTest {
memStore.initStore();
ISessionsStore aSessionsStore = memStore.sessionsStore();
store.init(aSessionsStore);
Subscription sub = new Subscription("FAKE_CLI_ID_1", subscription, AbstractMessage.QOSType.MOST_ONE);
Subscription sub = new Subscription("FAKE_CLI_ID_1", subscription, MqttQoS.AT_MOST_ONCE);
aSessionsStore.addNewSubscription(sub);
store.add(sub.asClientTopicCouple());
assertFalse(store.matches(topic).isEmpty());
@@ -271,7 +271,7 @@ public class SubscriptionsStoreTest {
MemoryStorageService memStore = new MemoryStorageService();
memStore.initStore();
store.init(memStore.sessionsStore());
Subscription sub = new Subscription("FAKE_CLI_ID_1", subscription, AbstractMessage.QOSType.MOST_ONE);
Subscription sub = new Subscription("FAKE_CLI_ID_1", subscription, MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(sub);
store.add(sub.asClientTopicCouple());
assertTrue(store.matches(topic).isEmpty());
@@ -281,7 +281,7 @@ public class SubscriptionsStoreTest {
@Test
public void testRemoveClientSubscriptions_existingClientID() {
String cliendID = "FAKE_CLID_1";
Subscription sub = new Subscription(cliendID, "finance/#", AbstractMessage.QOSType.MOST_ONE);
Subscription sub = new Subscription(cliendID, "finance/#", MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(sub);
store.add(sub.asClientTopicCouple());
@@ -295,7 +295,7 @@ public class SubscriptionsStoreTest {
@Test
public void testRemoveClientSubscriptions_notexistingClientID() {
String clientID = "FAKE_CLID_1";
Subscription s = new Subscription(clientID, "finance/#", AbstractMessage.QOSType.MOST_ONE);
Subscription s = new Subscription(clientID, "finance/#", MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(s);
store.add(s.asClientTopicCouple());
@@ -308,10 +308,10 @@ public class SubscriptionsStoreTest {
@Test
public void testOverlappingSubscriptions() {
Subscription genericSub = new Subscription("FAKE_CLI_ID_1", "a/+", AbstractMessage.QOSType.EXACTLY_ONCE);
Subscription genericSub = new Subscription("FAKE_CLI_ID_1", "a/+", MqttQoS.EXACTLY_ONCE);
sessionsStore.addNewSubscription(genericSub);
store.add(genericSub.asClientTopicCouple());
Subscription specificSub = new Subscription("FAKE_CLI_ID_1", "a/b", AbstractMessage.QOSType.LEAST_ONE);
Subscription specificSub = new Subscription("FAKE_CLI_ID_1", "a/b", MqttQoS.AT_LEAST_ONCE);
sessionsStore.addNewSubscription(specificSub);
store.add(specificSub.asClientTopicCouple());
@@ -380,12 +380,12 @@ public class SubscriptionsStoreTest {
aStore.init(sessionsStore);
//subscribe a not active clientID1 to /topic
sessionsStore.createNewSession("FAKE_CLI_ID_1", true);
Subscription slashSub = new Subscription("FAKE_CLI_ID_1", "/topic", AbstractMessage.QOSType.MOST_ONE);
Subscription slashSub = new Subscription("FAKE_CLI_ID_1", "/topic", MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(slashSub);
aStore.add(slashSub.asClientTopicCouple());
//subscribe an active clientID2 to /topic
Subscription slashSub2 = new Subscription("FAKE_CLI_ID_2", "/topic", AbstractMessage.QOSType.MOST_ONE);
Subscription slashSub2 = new Subscription("FAKE_CLI_ID_2", "/topic", MqttQoS.AT_MOST_ONCE);
sessionsStore.addNewSubscription(slashSub2);
aStore.add(new ClientTopicCouple("FAKE_CLI_ID_2", "/topic"));
@@ -403,15 +403,15 @@ public class SubscriptionsStoreTest {
@Test
public void duplicatedSubscriptionsWithDifferentQos() {
ClientSession session2 = sessionsStore.createNewSession("client2", true);
Subscription client2Sub = new Subscription("client2", "client/test/b", AbstractMessage.QOSType.MOST_ONE);
Subscription client2Sub = new Subscription("client2", "client/test/b", MqttQoS.AT_MOST_ONCE);
session2.subscribe(client2Sub);
store.add(client2Sub.asClientTopicCouple());
ClientSession session1 = sessionsStore.createNewSession("client1", true);
Subscription client1SubQoS0 = new Subscription("client1", "client/test/b", AbstractMessage.QOSType.MOST_ONE);
Subscription client1SubQoS0 = new Subscription("client1", "client/test/b", MqttQoS.AT_MOST_ONCE);
session1.subscribe(client1SubQoS0);
store.add(client1SubQoS0.asClientTopicCouple());
Subscription client1SubQoS2 = new Subscription("client1", "client/test/b", AbstractMessage.QOSType.EXACTLY_ONCE);
Subscription client1SubQoS2 = new Subscription("client1", "client/test/b", MqttQoS.EXACTLY_ONCE);
session1.subscribe(client1SubQoS2);
store.add(client1SubQoS2.asClientTopicCouple());
@@ -23,9 +23,9 @@ import io.moquette.spi.ClientSession;
import io.moquette.spi.IMessagesStore;
import io.moquette.spi.ISessionsStore;
import io.moquette.spi.ISessionsStore.ClientTopicCouple;
import io.moquette.parser.proto.messages.AbstractMessage;
import io.moquette.spi.MessageGUID;
import io.moquette.spi.impl.subscriptions.Subscription;
import io.netty.handler.codec.mqtt.MqttQoS;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -73,11 +73,11 @@ public class MapDBPersistentStoreTest {
ClientSession session1 = m_sessionsStore.createNewSession("SESSION_ID_1", true);
// Subscribe on /topic with QOSType.MOST_ONE
Subscription oldSubscription = new Subscription(session1.clientID, "/topic", AbstractMessage.QOSType.MOST_ONE);
Subscription oldSubscription = new Subscription(session1.clientID, "/topic", MqttQoS.AT_MOST_ONCE);
session1.subscribe(oldSubscription);
// Subscribe on /topic again that overrides the previous subscription.
Subscription overridingSubscription = new Subscription(session1.clientID, "/topic", AbstractMessage.QOSType.EXACTLY_ONCE);
Subscription overridingSubscription = new Subscription(session1.clientID, "/topic", MqttQoS.EXACTLY_ONCE);
session1.subscribe(overridingSubscription);
//Verify
@@ -134,7 +134,7 @@ public class MapDBPersistentStoreTest {
public void testDropMessagesInSessionCleanAllNotRetainedStoredMessages() {
m_sessionsStore.createNewSession("TestClient", true);
IMessagesStore.StoredMessage publishToStore = new IMessagesStore.StoredMessage("Hello".getBytes(),
AbstractMessage.QOSType.EXACTLY_ONCE, "/topic");
MqttQoS.EXACTLY_ONCE, "/topic");
publishToStore.setClientID(TEST_CLIENT);
publishToStore.setMessageID(1);
publishToStore.setRetained(false);
@@ -152,7 +152,7 @@ public class MapDBPersistentStoreTest {
public void testDropMessagesInSessionDoesntCleanAnyRetainedStoredMessages() {
m_sessionsStore.createNewSession("TestClient", true);
IMessagesStore.StoredMessage publishToStore = new IMessagesStore.StoredMessage("Hello".getBytes(),
AbstractMessage.QOSType.EXACTLY_ONCE, "/topic");
MqttQoS.EXACTLY_ONCE, "/topic");
publishToStore.setClientID(TEST_CLIENT);
publishToStore.setMessageID(1);
publishToStore.setRetained(true);
@@ -16,28 +16,19 @@
package io.moquette.testclient;
import io.moquette.BrokerConstants;
import io.moquette.parser.netty.MQTTDecoder;
import io.moquette.parser.netty.MQTTEncoder;
import io.moquette.parser.proto.messages.ConnAckMessage;
import io.moquette.parser.proto.messages.ConnectMessage;
import io.moquette.server.netty.MessageBuilder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.moquette.parser.proto.messages.AbstractMessage;
import io.netty.handler.codec.mqtt.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertTrue;
/**
* Class used just to send and receive MQTT messages without any protocol login
* in action, just use the encoder/decoder part.
@@ -47,7 +38,7 @@ import static org.junit.Assert.assertTrue;
public class Client {
public interface ICallback {
void call(AbstractMessage msg);
void call(MqttMessage msg);
}
private static final Logger LOG = LoggerFactory.getLogger(Client.class);
@@ -57,7 +48,7 @@ public class Client {
private boolean m_connectionLost = false;
private ICallback callback;
private String clientId;
private AbstractMessage receivedMsg;
private MqttMessage receivedMsg;
public Client(String host) {
this(host, BrokerConstants.PORT);
@@ -75,8 +66,8 @@ public class Client {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder", new MQTTDecoder());
pipeline.addLast("encoder", new MQTTEncoder());
pipeline.addLast("decoder", new MqttDecoder());
pipeline.addLast("encoder", MqttEncoder.INSTANCE);
pipeline.addLast("handler", handler);
}
});
@@ -95,34 +86,53 @@ public class Client {
}
public void connect(String willTestamentTopic, String willTestamentMsg) {
ConnectMessage connectMessage = new ConnectMessage();
MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(MqttMessageType.CONNECT, false, MqttQoS.AT_MOST_ONCE, false, 0);
MqttConnectVariableHeader mqttConnectVariableHeader =
new MqttConnectVariableHeader(
MqttVersion.MQTT_3_1.protocolName(),
MqttVersion.MQTT_3_1.protocolLevel(),
false,
false,
false,
MqttQoS.AT_MOST_ONCE.value(),
true,
true,
2);
MqttConnectPayload mqttConnectPayload = new MqttConnectPayload(this.clientId, willTestamentTopic, willTestamentMsg,
null, null);
MqttConnectMessage connectMessage = new MqttConnectMessage(mqttFixedHeader, mqttConnectVariableHeader,
mqttConnectPayload);
/*ConnectMessage connectMessage = new ConnectMessage();
connectMessage.setProtocolVersion((byte) 3);
connectMessage.setClientID(this.clientId);
connectMessage.setKeepAlive(2); //secs
connectMessage.setWillFlag(true);
connectMessage.setWillMessage(willTestamentMsg.getBytes());
connectMessage.setWillTopic(willTestamentTopic);
connectMessage.setWillQos(AbstractMessage.QOSType.MOST_ONE.byteValue());
connectMessage.setWillQos(MqttQoS.AT_MOST_ONCE.byteValue());*/
doConnect(connectMessage);
}
public void connect() {
ConnectMessage connectMessage = new ConnectMessage();
connectMessage.setProtocolVersion((byte) 4);
connectMessage.setClientID("");
connectMessage.setKeepAlive(2); //secs
connectMessage.setWillFlag(false);
connectMessage.setWillQos(AbstractMessage.QOSType.MOST_ONE.byteValue());
MqttConnectMessage connectMessage = MessageBuilder.connect()
.protocolVersion(MqttVersion.MQTT_3_1_1)
.clientId("")
.keepAlive(2) //secs
.willFlag(false)
.willQoS(MqttQoS.AT_MOST_ONCE)
.build();
doConnect(connectMessage);
}
private void doConnect(ConnectMessage connectMessage) {
private void doConnect(MqttConnectMessage connectMessage) {
final CountDownLatch latch = new CountDownLatch(1);
this.setCallback(new Client.ICallback() {
public void call(AbstractMessage msg) {
public void call(MqttMessage msg) {
receivedMsg = msg;
latch.countDown();
}
@@ -135,8 +145,9 @@ public class Client {
} catch (InterruptedException e) {
throw new RuntimeException("Cannot receive message in 200 ms", e);
}
if (!(this.receivedMsg instanceof ConnAckMessage)) {
throw new RuntimeException("Expected a CONN_ACK message but received " + this.receivedMsg.getMessageType());
if (!(this.receivedMsg instanceof MqttConnAckMessage)) {
MqttMessageType messageType = this.receivedMsg.fixedHeader().messageType();
throw new RuntimeException("Expected a CONN_ACK message but received " + messageType);
}
}
@@ -144,15 +155,15 @@ public class Client {
this.callback = callback;
}
public void sendMessage(AbstractMessage msg) {
public void sendMessage(MqttMessage msg) {
m_channel.writeAndFlush(msg);
}
public AbstractMessage lastReceivedMessage() {
public MqttMessage lastReceivedMessage() {
return this.receivedMsg;
}
void messageReceived(AbstractMessage msg) {
void messageReceived(MqttMessage msg) {
LOG.info("Received message {}", msg);
if (this.callback != null) {
this.callback.call(msg);
@@ -15,12 +15,11 @@
*/
package io.moquette.testclient;
import io.moquette.parser.proto.Utils;
import io.moquette.server.netty.NettyMQTTHandler;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.moquette.parser.proto.messages.AbstractMessage;
import io.moquette.server.netty.NettyMQTTHandler;
import io.netty.handler.codec.mqtt.MqttMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,8 +35,8 @@ class ClientNettyMQTTHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object message) {
AbstractMessage msg = (AbstractMessage) message;
LOG.info("Received a message of type {}", Utils.msgType2String(msg.getMessageType()));
MqttMessage msg = (MqttMessage) message;
LOG.info("Received a message of type {}", msg.fixedHeader().messageType());
m_client.messageReceived(msg);
}
@@ -8,7 +8,7 @@ import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.ReferenceCountUtil;
import io.moquette.parser.netty.Utils;
import io.moquette.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;