Moved project package from org.eclipse.moquette to io.moquette
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2015 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* 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.server;
|
||||
|
||||
import io.moquette.commons.Constants;
|
||||
import io.moquette.server.config.IConfig;
|
||||
import io.moquette.server.config.MemoryConfig;
|
||||
import io.moquette.spi.impl.security.IAuthenticator;
|
||||
import io.moquette.spi.impl.security.IAuthorizator;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author luca <[email protected]>
|
||||
*/
|
||||
public class ConfigurationClassLoaderTest implements IAuthenticator, IAuthorizator {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ConfigurationClassLoaderTest.class);
|
||||
|
||||
Server m_server;
|
||||
IConfig m_config;
|
||||
|
||||
protected void startServer(Properties props) throws IOException {
|
||||
m_server = new Server();
|
||||
m_config = new MemoryConfig(props);
|
||||
m_server.startServer(m_config);
|
||||
}
|
||||
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
m_server.stopServer();
|
||||
File dbFile = new File(m_config.getProperty(io.moquette.commons.Constants.PERSISTENT_STORE_PROPERTY_NAME));
|
||||
if (dbFile.exists()) {
|
||||
dbFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadAuthenticator() throws Exception {
|
||||
Properties props = new Properties(IntegrationUtils.prepareTestPropeties());
|
||||
props.setProperty(Constants.AUTHENTICATOR_CLASS_NAME, "io.moquette.server.ConfigurationClassLoaderTest");
|
||||
startServer(props);
|
||||
assertTrue(true);
|
||||
m_server.stopServer();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadAuthorizator() throws Exception {
|
||||
Properties props = new Properties(IntegrationUtils.prepareTestPropeties());
|
||||
props.setProperty(Constants.AUTHORIZATOR_CLASS_NAME, "io.moquette.server.ConfigurationClassLoaderTest");
|
||||
startServer(props);
|
||||
assertTrue(true);
|
||||
m_server.stopServer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkValid(String username, byte[] password) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite(String topic, String user, String client) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRead(String topic, String user, String client) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2015 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* 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.server;
|
||||
|
||||
import io.moquette.server.config.IConfig;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Properties;
|
||||
|
||||
import static io.moquette.commons.Constants.DEFAULT_MOQUETTE_STORE_MAP_DB_FILENAME;
|
||||
import static io.moquette.commons.Constants.PERSISTENT_STORE_PROPERTY_NAME;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
/**
|
||||
* Used to carry integration configurations.
|
||||
*
|
||||
* Created by andrea on 4/7/15.
|
||||
*/
|
||||
public class IntegrationUtils {
|
||||
static String localMapDBPath() {
|
||||
String currentDir = System.getProperty("user.dir");
|
||||
return currentDir + File.separator + DEFAULT_MOQUETTE_STORE_MAP_DB_FILENAME;
|
||||
}
|
||||
|
||||
public static Properties prepareTestPropeties() {
|
||||
Properties testProperties = new Properties();
|
||||
testProperties.put(PERSISTENT_STORE_PROPERTY_NAME, IntegrationUtils.localMapDBPath());
|
||||
return testProperties;
|
||||
}
|
||||
|
||||
public static void cleanPersistenceFile(IConfig config) {
|
||||
String fileName = config.getProperty(PERSISTENT_STORE_PROPERTY_NAME);
|
||||
cleanPersistenceFile(fileName);
|
||||
}
|
||||
|
||||
public static void cleanPersistenceFile(String fileName) {
|
||||
File dbFile = new File(fileName);
|
||||
if (dbFile.exists()) {
|
||||
dbFile.delete();
|
||||
new File(fileName + ".p").delete();
|
||||
new File(fileName + ".t").delete();
|
||||
}
|
||||
assertFalse(dbFile.exists());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2015 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* 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.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
@WebSocket
|
||||
public class MQTTWebSocket {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MQTTWebSocket.class);
|
||||
|
||||
private Session session;
|
||||
|
||||
private final CountDownLatch connectSentLatch;
|
||||
|
||||
public MQTTWebSocket() {
|
||||
this.connectSentLatch = new CountDownLatch(1);
|
||||
}
|
||||
|
||||
@OnWebSocketClose
|
||||
public void onClose(int statusCode, String reason) {
|
||||
System.out.printf("Connection closed: %d - %s%n", statusCode, reason);
|
||||
this.session = null;
|
||||
}
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onConnect(Session session) throws IOException {
|
||||
System.out.printf("Got connect: %s%n", session);
|
||||
LOG.info("Got connect: %s%n", session);
|
||||
this.session = session;
|
||||
|
||||
//Trivial MQTT Connect message
|
||||
// assertEquals(12, out.readByte()); //remaining length
|
||||
// verifyString("MQIsdp", out);
|
||||
// assertEquals(0x03, out.readByte()); //protocol version
|
||||
// assertEquals(0x32, out.readByte()); //flags
|
||||
// assertEquals(2, out.readByte()); //keepAliveTimer msb
|
||||
// assertEquals(0, out.readByte()); //keepAliveTimer lsb
|
||||
|
||||
ByteBuffer msg = ByteBuffer.wrap(new byte[] { 0x10, //message type
|
||||
0x0C, //remaining lenght 12 bytes
|
||||
'M', 'Q','I','s','d','p',
|
||||
0x03, //protocol version
|
||||
0x32, //flags
|
||||
0x02, 0x00// keepAlive Timer, 2 seconds
|
||||
});
|
||||
// try {
|
||||
session.getRemote().sendBytes(msg);
|
||||
this.connectSentLatch.countDown();
|
||||
session.close(StatusCode.NORMAL, "I'm done");
|
||||
// } catch (IOException t) {
|
||||
// LOG.error(null, t);
|
||||
// }
|
||||
}
|
||||
|
||||
public boolean awaitConnected(int duration, TimeUnit unit) throws InterruptedException {
|
||||
return this.connectSentLatch.await(duration, unit);
|
||||
}
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onMessage(Session session, byte[] buf, int offset, int length) {
|
||||
System.out.printf("Got msg: %s%n", buf);
|
||||
}
|
||||
|
||||
@OnWebSocketError
|
||||
public void onError(Session session, Throwable cause) {
|
||||
System.out.printf("Got exception: %s%n", cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2015 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* 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.server;
|
||||
|
||||
import io.moquette.server.config.IConfig;
|
||||
import io.moquette.server.config.MemoryConfig;
|
||||
import org.fusesource.mqtt.client.*;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class ServerIntegrationFuseTest {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ServerIntegrationPahoTest.class);
|
||||
|
||||
Server m_server;
|
||||
MQTT m_mqtt;
|
||||
BlockingConnection m_subscriber;
|
||||
BlockingConnection m_publisher;
|
||||
IConfig m_config;
|
||||
|
||||
protected void startServer() throws IOException {
|
||||
m_server = new Server();
|
||||
final Properties configProps = IntegrationUtils.prepareTestPropeties();
|
||||
m_config = new MemoryConfig(configProps);
|
||||
m_server.startServer(m_config);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
startServer();
|
||||
|
||||
m_mqtt = new MQTT();
|
||||
m_mqtt.setHost("localhost", 1883);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
if (m_subscriber != null) {
|
||||
m_subscriber.disconnect();
|
||||
}
|
||||
|
||||
if (m_publisher != null) {
|
||||
m_publisher.disconnect();
|
||||
}
|
||||
|
||||
m_server.stopServer();
|
||||
IntegrationUtils.cleanPersistenceFile(m_config);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectWithCredentials() throws Exception {
|
||||
LOG.info("*** connectWithCredetials ***");
|
||||
MQTT mqtt = new MQTT();
|
||||
mqtt.setHost("localhost", 1883);
|
||||
mqtt.setClientId("Publisher");
|
||||
mqtt.setUserName("testuser");
|
||||
mqtt.setPassword("passwd");
|
||||
|
||||
m_publisher = mqtt.blockingConnection();
|
||||
m_publisher.connect();
|
||||
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkWillTestamentIsPublishedOnConnectionKill_noRetain() throws Exception {
|
||||
LOG.info("checkWillTestamentIsPublishedOnConnectionKill");
|
||||
|
||||
String willTestamentTopic = "/will/test";
|
||||
String willTestamentMsg = "Bye bye";
|
||||
|
||||
MQTT mqtt = new MQTT();
|
||||
mqtt.setHost("localhost", 1883);
|
||||
mqtt.setClientId("WillTestamentPublisher");
|
||||
mqtt.setWillRetain(false);
|
||||
mqtt.setWillMessage(willTestamentMsg);
|
||||
mqtt.setWillTopic(willTestamentTopic);
|
||||
m_publisher = mqtt.blockingConnection();
|
||||
m_publisher.connect();
|
||||
|
||||
m_mqtt.setHost("localhost", 1883);
|
||||
m_mqtt.setCleanSession(false);
|
||||
m_mqtt.setClientId("Subscriber");
|
||||
m_subscriber = m_mqtt.blockingConnection();
|
||||
m_subscriber.connect();
|
||||
// Topic[] topics = new Topic[]{new Topic(willTestamentTopic, QoS.AT_LEAST_ONCE)};
|
||||
Topic[] topics = new Topic[]{new Topic(willTestamentTopic, QoS.AT_MOST_ONCE)};
|
||||
m_subscriber.subscribe(topics);
|
||||
|
||||
//Exercise, kill the publisher connection
|
||||
m_publisher.kill();
|
||||
|
||||
//Verify, that the testament is fired
|
||||
Message msg = m_subscriber.receive(500, TimeUnit.MILLISECONDS);
|
||||
assertNotNull("We should get notified with 'Will' message", msg);
|
||||
msg.ack();
|
||||
assertEquals(willTestamentMsg, new String(msg.getPayload()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkReplayofStoredPublishResumeAfter_a_disconnect_cleanSessionFalseQoS1() throws Exception {
|
||||
LOG.info("*** checkReplayofStoredPublishResumeAfter_a_disconnect_cleanSessionFalseQoS1 ***");
|
||||
MQTT mqtt = new MQTT();
|
||||
mqtt.setHost("localhost", 1883);
|
||||
mqtt.setClientId("Publisher");
|
||||
m_publisher = mqtt.blockingConnection();
|
||||
m_publisher.connect();
|
||||
|
||||
m_mqtt.setHost("localhost", 1883);
|
||||
m_mqtt.setCleanSession(false);
|
||||
m_mqtt.setClientId("Subscriber");
|
||||
m_subscriber = m_mqtt.blockingConnection();
|
||||
m_subscriber.connect();
|
||||
Topic[] topics = new Topic[]{new Topic("/topic", QoS.AT_LEAST_ONCE)};
|
||||
m_subscriber.subscribe(topics);
|
||||
|
||||
//force the publisher to send
|
||||
m_publisher.publish("/topic", "Hello world MQTT!!-1".getBytes(), QoS.AT_LEAST_ONCE, false);
|
||||
|
||||
//read the first message and drop the connection
|
||||
Message msg = m_subscriber.receive();
|
||||
msg.ack();
|
||||
assertEquals("Hello world MQTT!!-1", new String(msg.getPayload()));
|
||||
m_subscriber.disconnect();
|
||||
|
||||
m_publisher.publish("/topic", "Hello world MQTT!!-2".getBytes(), QoS.AT_LEAST_ONCE, false);
|
||||
m_publisher.publish("/topic", "Hello world MQTT!!-3".getBytes(), QoS.AT_LEAST_ONCE, false);
|
||||
|
||||
//reconnect and expect to receive the hello 2 message
|
||||
m_subscriber = m_mqtt.blockingConnection();
|
||||
m_subscriber.connect();
|
||||
//topics = new Topic[]{new Topic("/topic", QoS.AT_LEAST_ONCE)};
|
||||
//m_subscriber.subscribe(topics);
|
||||
msg = m_subscriber.receive();
|
||||
msg.ack();
|
||||
assertEquals("Hello world MQTT!!-2", new String(msg.getPayload()));
|
||||
|
||||
msg = m_subscriber.receive();
|
||||
assertEquals("Hello world MQTT!!-3", new String(msg.getPayload()));
|
||||
msg.ack();
|
||||
m_subscriber.disconnect();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkReplayStoredPublish_forNoCleanSession_qos1() throws Exception {
|
||||
LOG.info("*** checkReplayStoredPublish_forNoCleanSession_qos1 ***");
|
||||
MQTT mqtt = new MQTT();
|
||||
mqtt.setHost("localhost", 1883);
|
||||
mqtt.setClientId("Publisher");
|
||||
m_publisher = mqtt.blockingConnection();
|
||||
m_publisher.connect();
|
||||
|
||||
m_mqtt.setHost("localhost", 1883);
|
||||
m_mqtt.setCleanSession(false);
|
||||
m_mqtt.setClientId("Subscriber");
|
||||
m_subscriber = m_mqtt.blockingConnection();
|
||||
m_subscriber.connect();
|
||||
Topic[] topics = new Topic[]{new Topic("/topic", QoS.AT_LEAST_ONCE)};
|
||||
m_subscriber.subscribe(topics);
|
||||
m_subscriber.disconnect();
|
||||
|
||||
//force the publisher to send
|
||||
m_publisher.publish("/topic", "Hello world MQTT!!-1".getBytes(), QoS.AT_LEAST_ONCE, false);
|
||||
|
||||
//reconnect and expect to receive the hello 2 message
|
||||
m_subscriber = m_mqtt.blockingConnection();
|
||||
m_subscriber.connect();
|
||||
topics = new Topic[]{new Topic("/topic", QoS.AT_LEAST_ONCE)};
|
||||
m_subscriber.subscribe(topics);
|
||||
Message msg = m_subscriber.receive(1, TimeUnit.SECONDS);
|
||||
assertNotNull(msg);
|
||||
msg.ack();
|
||||
assertEquals("Hello world MQTT!!-1", new String(msg.getPayload()));
|
||||
// m_subscriber.disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* subscriber connect and subscribe on "topic"
|
||||
* subscriber disconnects
|
||||
* publisher connects and send two message "hello1" "hello2" to "topic"
|
||||
* subscriber connects again and receive "hello1" "hello2"
|
||||
*/
|
||||
@Test
|
||||
public void checkQoS2SubscriberDisconnectReceivePersistedPublishes() throws Exception {
|
||||
LOG.info("*** checkQoS2SubscriberDisconnectReceivePersistedPublishes ***");
|
||||
m_mqtt.setHost("localhost", 1883);
|
||||
m_mqtt.setCleanSession(false);
|
||||
m_mqtt.setClientId("Subscriber");
|
||||
m_subscriber = m_mqtt.blockingConnection();
|
||||
m_subscriber.connect();
|
||||
Topic[] topics = new Topic[]{new Topic("topic", QoS.EXACTLY_ONCE)};
|
||||
m_subscriber.subscribe(topics);
|
||||
m_subscriber.disconnect();
|
||||
|
||||
MQTT mqtt = new MQTT();
|
||||
mqtt.setHost("localhost", 1883);
|
||||
mqtt.setClientId("Publisher");
|
||||
m_publisher = mqtt.blockingConnection();
|
||||
m_publisher.connect();
|
||||
m_publisher.publish("topic", "Hello1".getBytes(), QoS.EXACTLY_ONCE, true);
|
||||
m_publisher.publish("topic", "Hello2".getBytes(), QoS.EXACTLY_ONCE, true);
|
||||
m_publisher.disconnect();
|
||||
|
||||
//subscriber reconnects
|
||||
m_mqtt = new MQTT();
|
||||
m_mqtt.setHost("localhost", 1883);
|
||||
m_mqtt.setClientId("Subscriber");
|
||||
m_mqtt.setCleanSession(false);
|
||||
m_subscriber = m_mqtt.blockingConnection();
|
||||
m_subscriber.connect();
|
||||
//subscriber should receive the 2 messages missed
|
||||
Message msg = m_subscriber.receive(1, TimeUnit.SECONDS);
|
||||
assertNotNull(msg);
|
||||
msg.ack();
|
||||
assertEquals("Hello1", new String(msg.getPayload()));
|
||||
msg = m_subscriber.receive(1, TimeUnit.SECONDS);
|
||||
assertNotNull(msg);
|
||||
msg.ack();
|
||||
assertEquals("Hello2", new String(msg.getPayload()));
|
||||
}
|
||||
|
||||
/**
|
||||
* subscriber connect and subscribe on "a/b" QoS 1 and "a/+" QoS 2
|
||||
* publisher connects and send a message "hello" on "a/b"
|
||||
* subscriber must receive only a single message not twice
|
||||
*/
|
||||
@Test
|
||||
public void checkSinglePublishOnOverlappingSubscriptions() throws Exception {
|
||||
LOG.info("*** checkSinglePublishOnOverlappingSubscriptions ***");
|
||||
MQTT mqtt = new MQTT();
|
||||
mqtt.setHost("localhost", 1883);
|
||||
mqtt.setClientId("Publisher");
|
||||
m_publisher = mqtt.blockingConnection();
|
||||
m_publisher.connect();
|
||||
|
||||
m_mqtt.setHost("localhost", 1883);
|
||||
m_mqtt.setCleanSession(false);
|
||||
m_mqtt.setClientId("Subscriber");
|
||||
m_subscriber = m_mqtt.blockingConnection();
|
||||
m_subscriber.connect();
|
||||
Topic[] topics = new Topic[]{
|
||||
new Topic("a/+", QoS.EXACTLY_ONCE),
|
||||
new Topic("a/b", QoS.AT_LEAST_ONCE)};
|
||||
m_subscriber.subscribe(topics);
|
||||
|
||||
//force the publisher to send
|
||||
m_publisher.publish("a/b", "Hello world MQTT!!".getBytes(), QoS.AT_LEAST_ONCE, false);
|
||||
|
||||
//reconnect and expect to receive the hello 2 message
|
||||
Message msg = m_subscriber.receive(1, TimeUnit.SECONDS);
|
||||
assertNotNull(msg);
|
||||
msg.ack();
|
||||
assertEquals("Hello world MQTT!!", new String(msg.getPayload()));
|
||||
//try to listen a second publish
|
||||
msg = m_subscriber.receive(1, TimeUnit.SECONDS);
|
||||
assertNull(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2015 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* 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.server;
|
||||
|
||||
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.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class ServerIntegrationPahoTest {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ServerIntegrationPahoTest.class);
|
||||
|
||||
static MqttClientPersistence s_dataStore;
|
||||
static MqttClientPersistence s_pubDataStore;
|
||||
|
||||
Server m_server;
|
||||
IMqttClient m_client;
|
||||
TestCallback m_callback;
|
||||
IConfig m_config;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeTests() {
|
||||
String tmpDir = System.getProperty("java.io.tmpdir");
|
||||
s_dataStore = new MqttDefaultFilePersistence(tmpDir);
|
||||
s_pubDataStore = new MqttDefaultFilePersistence(tmpDir + File.separator + "publisher");
|
||||
}
|
||||
|
||||
protected void startServer() throws IOException {
|
||||
m_server = new Server();
|
||||
final Properties configProps = IntegrationUtils.prepareTestPropeties();
|
||||
m_config = new MemoryConfig(configProps);
|
||||
m_server.startServer(m_config);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
String dbPath = IntegrationUtils.localMapDBPath();
|
||||
IntegrationUtils.cleanPersistenceFile(dbPath);
|
||||
// File dbFile = new File(dbPath);
|
||||
// assertFalse(String.format("The DB storagefile %s already exists", dbPath), dbFile.exists());
|
||||
|
||||
startServer();
|
||||
|
||||
m_client = new MqttClient("tcp://localhost:1883", "TestClient", s_dataStore);
|
||||
m_callback = new TestCallback();
|
||||
m_client.setCallback(m_callback);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
if (m_client.isConnected()) {
|
||||
m_client.disconnect();
|
||||
}
|
||||
|
||||
stopServer();
|
||||
}
|
||||
|
||||
private void stopServer() {
|
||||
m_server.stopServer();
|
||||
IntegrationUtils.cleanPersistenceFile(m_config);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscribe() throws Exception {
|
||||
LOG.info("*** testSubscribe ***");
|
||||
m_client.connect();
|
||||
m_client.subscribe("/topic", 0);
|
||||
|
||||
MqttMessage message = new MqttMessage("Hello world!!".getBytes());
|
||||
message.setQos(0);
|
||||
message.setRetained(false);
|
||||
m_client.publish("/topic", message);
|
||||
|
||||
assertEquals("/topic", m_callback.getTopic());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCleanSession_maintainClientSubscriptions() throws Exception {
|
||||
LOG.info("*** testCleanSession_maintainClientSubscriptions ***");
|
||||
MqttConnectOptions options = new MqttConnectOptions();
|
||||
options.setCleanSession(false);
|
||||
m_client.connect(options);
|
||||
m_client.subscribe("/topic", 0);
|
||||
m_client.disconnect();
|
||||
|
||||
//reconnect and publish
|
||||
MqttClient anotherClient = new MqttClient("tcp://localhost:1883", "TestClient", s_dataStore);
|
||||
m_callback = new TestCallback();
|
||||
anotherClient.setCallback(m_callback);
|
||||
anotherClient.connect(options);
|
||||
anotherClient.publish("/topic", "Test my payload".getBytes(), 0, false);
|
||||
|
||||
assertEquals("/topic", m_callback.getTopic());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCleanSession_maintainClientSubscriptions_againstClientDestruction() throws Exception {
|
||||
LOG.info("*** testCleanSession_maintainClientSubscriptions_againstClientDestruction ***");
|
||||
MqttConnectOptions options = new MqttConnectOptions();
|
||||
options.setCleanSession(false);
|
||||
m_client.connect(options);
|
||||
m_client.subscribe("/topic", 0);
|
||||
m_client.disconnect();
|
||||
|
||||
//reconnect and publish
|
||||
m_client.connect(options);
|
||||
m_client.publish("/topic", "Test my payload".getBytes(), 0, false);
|
||||
|
||||
assertEquals("/topic", m_callback.getTopic());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that after a client has connected with clean session false, subscribed
|
||||
* to some topic and exited, if it reconnect with clean session true, the m_server
|
||||
* correctly cleanup every previous subscription
|
||||
*/
|
||||
@Test
|
||||
public void testCleanSession_correctlyClientSubscriptions() throws Exception {
|
||||
LOG.info("*** testCleanSession_correctlyClientSubscriptions ***");
|
||||
MqttConnectOptions options = new MqttConnectOptions();
|
||||
options.setCleanSession(false);
|
||||
m_client.connect(options);
|
||||
m_client.subscribe("/topic", 0);
|
||||
m_client.disconnect();
|
||||
|
||||
//reconnect and publish
|
||||
m_client.connect();
|
||||
m_client.publish("/topic", "Test my payload".getBytes(), 0, false);
|
||||
|
||||
assertEquals("Test my payload", new String(m_callback.getMessage(false).getPayload()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCleanSession_maintainClientSubscriptions_withServerRestart() throws Exception {
|
||||
LOG.info("*** testCleanSession_maintainClientSubscriptions_withServerRestart ***");
|
||||
MqttConnectOptions options = new MqttConnectOptions();
|
||||
options.setCleanSession(false);
|
||||
m_client.connect(options);
|
||||
m_client.subscribe("/topic", 0);
|
||||
m_client.disconnect();
|
||||
|
||||
m_server.stopServer();
|
||||
|
||||
m_server.startServer(IntegrationUtils.prepareTestPropeties());
|
||||
|
||||
//reconnect and publish
|
||||
m_client.connect(options);
|
||||
m_client.publish("/topic", "Test my payload".getBytes(), 0, false);
|
||||
|
||||
assertEquals("/topic", m_callback.getTopic());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetain_maintainMessage_againstClientDestruction() throws Exception {
|
||||
LOG.info("*** testRetain_maintainMessage_againstClientDestruction ***");
|
||||
m_client.connect();
|
||||
m_client.publish("/topic", "Test my payload".getBytes(), 1, true);
|
||||
m_client.disconnect();
|
||||
|
||||
//reconnect and publish
|
||||
m_client.connect();
|
||||
m_client.subscribe("/topic", 0);
|
||||
|
||||
assertEquals("/topic", m_callback.getTopic());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribe_do_not_notify_anymore_same_session() throws Exception {
|
||||
LOG.info("*** testUnsubscribe_do_not_notify_anymore_same_session ***");
|
||||
MqttConnectOptions options = new MqttConnectOptions();
|
||||
options.setCleanSession(false);
|
||||
m_client.connect(options);
|
||||
m_client.subscribe("/topic", 0);
|
||||
m_client.publish("/topic", "Test my payload".getBytes(), 0, false);
|
||||
//m_client.disconnect();
|
||||
assertEquals("/topic", m_callback.getTopic());
|
||||
|
||||
m_client.unsubscribe("/topic");
|
||||
m_callback.reinit();
|
||||
m_client.publish("/topic", "Test my payload".getBytes(), 0, false);
|
||||
|
||||
assertNull(m_callback.getMessage(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribe_do_not_notify_anymore_new_session() throws Exception {
|
||||
LOG.info("*** testUnsubscribe_do_not_notify_anymore_new_session ***");
|
||||
MqttConnectOptions options = new MqttConnectOptions();
|
||||
options.setCleanSession(false);
|
||||
m_client.connect(options);
|
||||
m_client.subscribe("/topic", 0);
|
||||
m_client.publish("/topic", "Test my payload".getBytes(), 0, false);
|
||||
//m_client.disconnect();
|
||||
assertEquals("/topic", m_callback.getTopic());
|
||||
|
||||
m_client.unsubscribe("/topic");
|
||||
m_client.disconnect();
|
||||
|
||||
m_callback.reinit();
|
||||
m_client.connect(options);
|
||||
m_client.publish("/topic", "Test my payload".getBytes(), 0, false);
|
||||
|
||||
assertNull(m_callback.getMessage(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublishWithQoS1() throws Exception {
|
||||
LOG.info("*** testPublishWithQoS1 ***");
|
||||
m_client.connect();
|
||||
m_client.subscribe("/topic", 1);
|
||||
m_client.publish("/topic", "Hello MQTT".getBytes(), 1, false);
|
||||
m_client.disconnect();
|
||||
|
||||
//reconnect and publish
|
||||
MqttMessage message = m_callback.getMessage(true);
|
||||
assertEquals("Hello MQTT", message.toString());
|
||||
assertEquals(1, message.getQos());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublishWithQoS1_notCleanSession() throws Exception {
|
||||
LOG.info("*** testPublishWithQoS1_notCleanSession ***");
|
||||
MqttConnectOptions options = new MqttConnectOptions();
|
||||
options.setCleanSession(false);
|
||||
m_client.connect(options);
|
||||
m_client.subscribe("/topic", 1);
|
||||
m_client.disconnect();
|
||||
|
||||
//publish a QoS 1 message another client publish a message on the topic
|
||||
publishFromAnotherClient("/topic", "Hello MQTT".getBytes(), 1);
|
||||
|
||||
m_client.connect(options);
|
||||
|
||||
assertEquals("Hello MQTT", m_callback.getMessage(true).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkReceivePublishedMessage_after_a_reconnect_with_notCleanSession() throws Exception {
|
||||
LOG.info("*** checkReceivePublishedMessage_after_a_reconnect_with_notCleanSession ***");
|
||||
MqttConnectOptions options = new MqttConnectOptions();
|
||||
options.setCleanSession(false);
|
||||
m_client.connect(options);
|
||||
m_client.subscribe("/topic", 1);
|
||||
m_client.disconnect();
|
||||
|
||||
m_client.connect(options);
|
||||
m_client.subscribe("/topic", 1);
|
||||
|
||||
//publish a QoS 1 message another client publish a message on the topic
|
||||
publishFromAnotherClient("/topic", "Hello MQTT".getBytes(), 1);
|
||||
|
||||
//Verify that after a reconnection the client receive the message
|
||||
MqttMessage message = m_callback.getMessage(true);
|
||||
assertNotNull(message);
|
||||
assertEquals("Hello MQTT", message.toString());
|
||||
}
|
||||
|
||||
private void publishFromAnotherClient(String topic, byte[] payload, int qos) throws Exception {
|
||||
IMqttClient anotherClient = new MqttClient("tcp://localhost:1883", "TestClientPUB", s_pubDataStore);
|
||||
anotherClient.connect();
|
||||
anotherClient.publish(topic, payload, qos, false);
|
||||
anotherClient.disconnect();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublishWithQoS2() throws Exception {
|
||||
LOG.info("*** testPublishWithQoS2 ***");
|
||||
MqttConnectOptions options = new MqttConnectOptions();
|
||||
options.setCleanSession(false);
|
||||
m_client.connect(options);
|
||||
m_client.subscribe("/topic", 2);
|
||||
m_client.disconnect();
|
||||
|
||||
//publish a QoS 1 message another client publish a message on the topic
|
||||
publishFromAnotherClient("/topic", "Hello MQTT".getBytes(), 2);
|
||||
m_callback.reinit();
|
||||
m_client.connect(options);
|
||||
|
||||
MqttMessage message = m_callback.getMessage(true);
|
||||
assertEquals("Hello MQTT", message.toString());
|
||||
assertEquals(2, message.getQos());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublishReceiveWithQoS2() throws Exception {
|
||||
LOG.info("*** testPublishReceiveWithQoS2 ***");
|
||||
MqttConnectOptions options = new MqttConnectOptions();
|
||||
options.setCleanSession(false);
|
||||
m_client.connect(options);
|
||||
m_client.subscribe("/topic", 2);
|
||||
m_client.disconnect();
|
||||
|
||||
//publish a QoS 2 message another client publish a message on the topic
|
||||
publishFromAnotherClient("/topic", "Hello MQTT".getBytes(), 2);
|
||||
m_callback.reinit();
|
||||
m_client.connect(options);
|
||||
|
||||
assertNotNull(m_callback);
|
||||
MqttMessage message = m_callback.getMessage(true);
|
||||
assertNotNull(message);
|
||||
assertEquals("Hello MQTT", message.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void avoidMultipleNotificationsAfterMultipleReconnection_cleanSessionFalseQoS1() throws Exception {
|
||||
LOG.info("*** avoidMultipleNotificationsAfterMultipleReconnection_cleanSessionFalseQoS1, issue #16 ***");
|
||||
MqttConnectOptions options = new MqttConnectOptions();
|
||||
options.setCleanSession(false);
|
||||
m_client.connect(options);
|
||||
m_client.subscribe("/topic", 1);
|
||||
m_client.disconnect();
|
||||
|
||||
publishFromAnotherClient("/topic", "Hello MQTT 1".getBytes(), 1);
|
||||
m_callback.reinit();
|
||||
m_client.connect(options);
|
||||
|
||||
assertNotNull(m_callback);
|
||||
MqttMessage message = m_callback.getMessage(true);
|
||||
assertNotNull(message);
|
||||
assertEquals("Hello MQTT 1", message.toString());
|
||||
m_client.disconnect();
|
||||
|
||||
//publish other message
|
||||
publishFromAnotherClient("/topic", "Hello MQTT 2".getBytes(), 1);
|
||||
|
||||
//reconnect the second time
|
||||
m_callback.reinit();
|
||||
m_client.connect(options);
|
||||
assertNotNull(m_callback);
|
||||
message = m_callback.getMessage(true);
|
||||
assertNotNull(message);
|
||||
assertEquals("Hello MQTT 2", message.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* subscriber A connect and subscribe on "a/b" QoS 1
|
||||
* subscriber B connect and subscribe on "a/+" BUT with QoS 2
|
||||
* publisher connects and send a message "hello" on "a/b"
|
||||
* subscriber A must receive a notification with QoS1
|
||||
* subscriber B must receive a notification with QoS2
|
||||
*/
|
||||
@Test
|
||||
public void checkSubscribersGetCorrectQosNotifications() throws Exception {
|
||||
LOG.info("*** checkSubscribersGetCorrectQosNotifications ***");
|
||||
String tmpDir = System.getProperty("java.io.tmpdir");
|
||||
|
||||
MqttClientPersistence dsSubscriberA = new MqttDefaultFilePersistence(tmpDir + File.separator + "subscriberA");
|
||||
|
||||
MqttClient subscriberA = new MqttClient("tcp://localhost:1883", "SubscriberA", dsSubscriberA);
|
||||
TestCallback cbSubscriberA = new TestCallback();
|
||||
subscriberA.setCallback(cbSubscriberA);
|
||||
subscriberA.connect();
|
||||
subscriberA.subscribe("a/b", 1);
|
||||
|
||||
MqttClientPersistence dsSubscriberB = new MqttDefaultFilePersistence(tmpDir + File.separator + "subscriberB");
|
||||
|
||||
MqttClient subscriberB = new MqttClient("tcp://localhost:1883", "SubscriberB", dsSubscriberB);
|
||||
TestCallback cbSubscriberB = new TestCallback();
|
||||
subscriberB.setCallback(cbSubscriberB);
|
||||
subscriberB.connect();
|
||||
subscriberB.subscribe("a/+", 2);
|
||||
|
||||
|
||||
m_client.connect();
|
||||
m_client.publish("a/b", "Hello world MQTT!!".getBytes(), 2, false);
|
||||
|
||||
MqttMessage messageOnA = cbSubscriberA.getMessage(true);
|
||||
assertEquals("Hello world MQTT!!", new String(messageOnA.getPayload()));
|
||||
assertEquals(1, messageOnA.getQos());
|
||||
subscriberA.disconnect();
|
||||
|
||||
MqttMessage messageOnB = cbSubscriberB.getMessage(true);
|
||||
assertEquals("Hello world MQTT!!", new String(messageOnB.getPayload()));
|
||||
assertEquals(2, messageOnB.getQos());
|
||||
subscriberB.disconnect();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2015 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* 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.server;
|
||||
|
||||
|
||||
import io.moquette.server.config.IConfig;
|
||||
import io.moquette.server.config.MemoryConfig;
|
||||
import org.eclipse.paho.client.mqttv3.IMqttClient;
|
||||
import org.eclipse.paho.client.mqttv3.MqttClient;
|
||||
import org.eclipse.paho.client.mqttv3.MqttClientPersistence;
|
||||
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||
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.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class ServerIntegrationQoSValidationTest {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ServerIntegrationPahoTest.class);
|
||||
|
||||
Server m_server;
|
||||
static MqttClientPersistence s_subDataStore;
|
||||
static MqttClientPersistence s_pubDataStore;
|
||||
|
||||
IMqttClient m_subscriber;
|
||||
IMqttClient m_publisher;
|
||||
TestCallback m_callback;
|
||||
IConfig m_config;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeTests() {
|
||||
String tmpDir = System.getProperty("java.io.tmpdir");
|
||||
s_subDataStore = new MqttDefaultFilePersistence(tmpDir + File.separator + "subscriber");
|
||||
s_pubDataStore = new MqttDefaultFilePersistence(tmpDir + File.separator + "publisher");
|
||||
}
|
||||
|
||||
protected void startServer() throws IOException {
|
||||
m_server = new Server();
|
||||
final Properties configProps = IntegrationUtils.prepareTestPropeties();
|
||||
m_config = new MemoryConfig(configProps);
|
||||
m_server.startServer(m_config);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
startServer();
|
||||
|
||||
m_subscriber = new MqttClient("tcp://localhost:1883", "Subscriber", s_subDataStore);
|
||||
m_callback = new TestCallback();
|
||||
m_subscriber.setCallback(m_callback);
|
||||
m_subscriber.connect();
|
||||
|
||||
m_publisher = new MqttClient("tcp://localhost:1883", "Publisher", s_pubDataStore);
|
||||
m_publisher.connect();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
if (m_publisher.isConnected()) {
|
||||
m_publisher.disconnect();
|
||||
}
|
||||
|
||||
if (m_subscriber.isConnected()) {
|
||||
m_subscriber.disconnect();
|
||||
}
|
||||
|
||||
m_server.stopServer();
|
||||
IntegrationUtils.cleanPersistenceFile(m_config);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkSubscriberQoS0ReceiveQoS0publishes() throws Exception {
|
||||
LOG.info("*** checkSubscriberQoS0ReceiveQoS0publishes ***");
|
||||
m_subscriber.subscribe("/topic", 0);
|
||||
|
||||
m_publisher.publish("/topic", "Hello world MQTT QoS0".getBytes(), 0, false);
|
||||
MqttMessage message = m_callback.getMessage(true);
|
||||
assertEquals("Hello world MQTT QoS0", message.toString());
|
||||
assertEquals(0, message.getQos());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkSubscriberQoS0ReceiveQoS1publishes_downgrade() throws Exception {
|
||||
LOG.info("*** checkSubscriberQoS0ReceiveQoS1publishes_downgrade ***");
|
||||
m_subscriber.subscribe("/topic", 0);
|
||||
|
||||
m_publisher.publish("/topic", "Hello world MQTT QoS1".getBytes(), 1, false);
|
||||
MqttMessage message = m_callback.getMessage(true);
|
||||
assertEquals("Hello world MQTT QoS1", message.toString());
|
||||
assertEquals(0, message.getQos());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkSubscriberQoS0ReceiveQoS2publishes_downgrade() throws Exception {
|
||||
LOG.info("*** checkSubscriberQoS0ReceiveQoS2publishes_downgrade ***");
|
||||
m_subscriber.subscribe("/topic", 0);
|
||||
|
||||
m_publisher.publish("/topic", "Hello world MQTT QoS2".getBytes(), 2, false);
|
||||
MqttMessage message = m_callback.getMessage(true);
|
||||
assertEquals("Hello world MQTT QoS2", message.toString());
|
||||
assertEquals(0, message.getQos());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkSubscriberQoS1ReceiveQoS0publishes() throws Exception {
|
||||
LOG.info("*** checkSubscriberQoS1ReceiveQoS0publishes ***");
|
||||
m_subscriber.subscribe("/topic", 1);
|
||||
|
||||
m_publisher.publish("/topic", "Hello world MQTT QoS0".getBytes(), 0, false);
|
||||
MqttMessage message = m_callback.getMessage(true);
|
||||
assertEquals("Hello world MQTT QoS0", message.toString());
|
||||
assertEquals(0, message.getQos());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkSubscriberQoS1ReceiveQoS1publishes() throws Exception {
|
||||
LOG.info("*** checkSubscriberQoS1ReceiveQoS1publishes ***");
|
||||
m_subscriber.subscribe("/topic", 1);
|
||||
|
||||
m_publisher.publish("/topic", "Hello world MQTT QoS1".getBytes(), 1, false);
|
||||
MqttMessage message = m_callback.getMessage(true);
|
||||
assertEquals("Hello world MQTT QoS1", message.toString());
|
||||
assertEquals(1, message.getQos());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkSubscriberQoS1ReceiveQoS2publishes_downgrade() throws Exception {
|
||||
LOG.info("*** checkSubscriberQoS1ReceiveQoS2publishes_downgrade ***");
|
||||
m_subscriber.subscribe("/topic", 1);
|
||||
|
||||
m_publisher.publish("/topic", "Hello world MQTT QoS2".getBytes(), 2, false);
|
||||
MqttMessage message = m_callback.getMessage(true);
|
||||
assertEquals("Hello world MQTT QoS2", message.toString());
|
||||
assertEquals(1, message.getQos());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkSubscriberQoS2ReceiveQoS0publishes() throws Exception {
|
||||
LOG.info("*** checkSubscriberQoS2ReceiveQoS0publishes ***");
|
||||
m_subscriber.subscribe("/topic", 2);
|
||||
|
||||
m_publisher.publish("/topic", "Hello world MQTT QoS2".getBytes(), 0, false);
|
||||
MqttMessage message = m_callback.getMessage(true);
|
||||
assertEquals("Hello world MQTT QoS2", message.toString());
|
||||
assertEquals(0, message.getQos());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkSubscriberQoS2ReceiveQoS1publishes() throws Exception {
|
||||
LOG.info("*** checkSubscriberQoS2ReceiveQoS1publishes ***");
|
||||
m_subscriber.subscribe("/topic", 2);
|
||||
|
||||
m_publisher.publish("/topic", "Hello world MQTT QoS2".getBytes(), 1, false);
|
||||
MqttMessage message = m_callback.getMessage(true);
|
||||
assertEquals("Hello world MQTT QoS2", message.toString());
|
||||
assertEquals(1, message.getQos());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkSubscriberQoS2ReceiveQoS2publishes() throws Exception {
|
||||
LOG.info("*** checkSubscriberQoS2ReceiveQoS2publishes ***");
|
||||
m_subscriber.subscribe("/topic", 2);
|
||||
|
||||
m_publisher.publish("/topic", "Hello world MQTT QoS2".getBytes(), 2, false);
|
||||
MqttMessage message = m_callback.getMessage(true);
|
||||
assertEquals("Hello world MQTT QoS2", message.toString());
|
||||
assertEquals(2, message.getQos());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2015 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* 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.server;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
import io.moquette.commons.Constants;
|
||||
import org.eclipse.paho.client.mqttv3.IMqttClient;
|
||||
import org.eclipse.paho.client.mqttv3.MqttClient;
|
||||
import org.eclipse.paho.client.mqttv3.MqttClientPersistence;
|
||||
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
||||
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
||||
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.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Check that Moquette could also handle SSL.
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class ServerIntegrationSSLTest {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ServerIntegrationSSLTest.class);
|
||||
|
||||
Server m_server;
|
||||
static MqttClientPersistence s_dataStore;
|
||||
|
||||
IMqttClient m_client;
|
||||
TestCallback m_callback;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeTests() {
|
||||
String tmpDir = System.getProperty("java.io.tmpdir");
|
||||
s_dataStore = new MqttDefaultFilePersistence(tmpDir);
|
||||
}
|
||||
|
||||
protected void startServer() throws IOException {
|
||||
String file = getClass().getResource("/").getPath();
|
||||
System.setProperty("moquette.path", file);
|
||||
m_server = new Server();
|
||||
|
||||
Properties sslProps = new Properties();
|
||||
sslProps.put(io.moquette.commons.Constants.SSL_PORT_PROPERTY_NAME, "8883");
|
||||
sslProps.put(Constants.JKS_PATH_PROPERTY_NAME, "serverkeystore.jks");
|
||||
sslProps.put(Constants.KEY_STORE_PASSWORD_PROPERTY_NAME, "passw0rdsrv");
|
||||
sslProps.put(Constants.KEY_MANAGER_PASSWORD_PROPERTY_NAME, "passw0rdsrv");
|
||||
sslProps.put(Constants.PERSISTENT_STORE_PROPERTY_NAME, IntegrationUtils.localMapDBPath());
|
||||
m_server.startServer(sslProps);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
String dbPath = IntegrationUtils.localMapDBPath();
|
||||
File dbFile = new File(dbPath);
|
||||
assertFalse(String.format("The DB storagefile %s already exists", dbPath), dbFile.exists());
|
||||
|
||||
startServer();
|
||||
|
||||
m_client = new MqttClient("ssl://localhost:8883", "TestClient", s_dataStore);
|
||||
// m_client = new MqttClient("ssl://test.mosquitto.org:8883", "TestClient", s_dataStore);
|
||||
|
||||
m_callback = new TestCallback();
|
||||
m_client.setCallback(m_callback);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
if (m_client != null && m_client.isConnected()) {
|
||||
m_client.disconnect();
|
||||
}
|
||||
|
||||
if (m_server != null) {
|
||||
m_server.stopServer();
|
||||
}
|
||||
String dbPath = IntegrationUtils.localMapDBPath();
|
||||
File dbFile = new File(dbPath);
|
||||
if (dbFile.exists()) {
|
||||
dbFile.delete();
|
||||
}
|
||||
assertFalse(dbFile.exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkSupportSSL() throws Exception {
|
||||
LOG.info("*** checkSupportSSL ***");
|
||||
SSLSocketFactory ssf = configureSSLSocketFactory();
|
||||
|
||||
MqttConnectOptions options = new MqttConnectOptions();
|
||||
options.setSocketFactory(ssf);
|
||||
m_client.connect(options);
|
||||
m_client.subscribe("/topic", 0);
|
||||
m_client.disconnect();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkSupportSSLForMultipleClient() throws Exception {
|
||||
LOG.info("*** checkSupportSSLForMultipleClient ***");
|
||||
SSLSocketFactory ssf = configureSSLSocketFactory();
|
||||
|
||||
MqttConnectOptions options = new MqttConnectOptions();
|
||||
options.setSocketFactory(ssf);
|
||||
m_client.connect(options);
|
||||
m_client.subscribe("/topic", 0);
|
||||
|
||||
MqttClient secondClient = new MqttClient("ssl://localhost:8883", "secondTestClient", new MemoryPersistence());
|
||||
MqttConnectOptions secondClientOptions = new MqttConnectOptions();
|
||||
secondClientOptions.setSocketFactory(ssf);
|
||||
secondClient.connect(secondClientOptions);
|
||||
secondClient.publish("/topic", new MqttMessage("message".getBytes()));
|
||||
secondClient.disconnect();
|
||||
|
||||
m_client.disconnect();
|
||||
}
|
||||
/**
|
||||
* keystore generated into test/resources with command:
|
||||
*
|
||||
* keytool -keystore clientkeystore.jks -alias testclient -genkey -keyalg RSA
|
||||
* -> mandatory to put the name surname
|
||||
* -> password is passw0rd
|
||||
* -> type yes at the end
|
||||
*
|
||||
* to generate the crt file from the keystore
|
||||
* -- keytool -certreq -alias testclient -keystore clientkeystore.jks -file testclient.csr
|
||||
*
|
||||
* keytool -export -alias testclient -keystore clientkeystore.jks -file testclient.crt
|
||||
*
|
||||
* to import an existing certificate:
|
||||
* keytool -keystore clientkeystore.jks -import -alias testclient -file testclient.crt -trustcacerts
|
||||
*/
|
||||
private SSLSocketFactory configureSSLSocketFactory() throws KeyManagementException, NoSuchAlgorithmException, UnrecoverableKeyException, IOException, CertificateException, KeyStoreException {
|
||||
KeyStore ks = KeyStore.getInstance("JKS");
|
||||
InputStream jksInputStream = getClass().getClassLoader().getResourceAsStream("clientkeystore.jks");
|
||||
ks.load(jksInputStream, "passw0rd".toCharArray());
|
||||
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
kmf.init(ks, "passw0rd".toCharArray());
|
||||
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
tmf.init(ks);
|
||||
|
||||
SSLContext sc = SSLContext.getInstance("TLS");
|
||||
TrustManager[] trustManagers = tmf.getTrustManagers();
|
||||
sc.init(kmf.getKeyManagers(), trustManagers, null);
|
||||
|
||||
SSLSocketFactory ssf = sc.getSocketFactory();
|
||||
return ssf;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2015 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* 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.server;
|
||||
|
||||
import io.moquette.server.config.MemoryConfig;
|
||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import io.moquette.server.config.IConfig;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
||||
/**
|
||||
* Integration test to check the function of Moquette with a WebSocket channel.
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class ServerIntegrationWebSocketTest {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ServerIntegrationWebSocketTest.class);
|
||||
|
||||
Server m_server;
|
||||
WebSocketClient client;
|
||||
IConfig m_config;
|
||||
|
||||
protected void startServer() throws IOException {
|
||||
m_server = new Server();
|
||||
final Properties configProps = IntegrationUtils.prepareTestPropeties();
|
||||
m_config = new MemoryConfig(configProps);
|
||||
m_server.startServer(m_config);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
startServer();
|
||||
client = new WebSocketClient();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
client.stop();
|
||||
|
||||
m_server.stopServer();
|
||||
IntegrationUtils.cleanPersistenceFile(m_config);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkPlainConnect() throws Exception {
|
||||
LOG.info("*** checkPlainConnect ***");
|
||||
String destUri = "ws://localhost:" + io.moquette.commons.Constants.WEBSOCKET_PORT;
|
||||
|
||||
MQTTWebSocket socket = new MQTTWebSocket();
|
||||
client.start();
|
||||
URI echoUri = new URI(destUri);
|
||||
ClientUpgradeRequest request = new ClientUpgradeRequest();
|
||||
client.connect(socket, echoUri, request);
|
||||
LOG.info("Connecting to : %s", echoUri);
|
||||
boolean connected = socket.awaitConnected(4, TimeUnit.SECONDS);
|
||||
|
||||
assertTrue(connected);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2015 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* 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.server;
|
||||
|
||||
import io.moquette.proto.messages.ConnectMessage;
|
||||
import io.moquette.proto.messages.AbstractMessage;
|
||||
import io.moquette.proto.messages.AbstractMessage.QOSType;
|
||||
import io.moquette.proto.messages.ConnAckMessage;
|
||||
import io.moquette.server.config.IConfig;
|
||||
import io.moquette.server.config.MemoryConfig;
|
||||
import io.moquette.testclient.Client;
|
||||
import org.fusesource.mqtt.client.*;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class ServerLowlevelMessagesIntegrationTests {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ServerLowlevelMessagesIntegrationTests.class);
|
||||
|
||||
Server m_server;
|
||||
Client m_client;
|
||||
MQTT m_subscriberDef;
|
||||
IConfig m_config;
|
||||
|
||||
protected void startServer() throws IOException {
|
||||
m_server = new Server();
|
||||
final Properties configProps = IntegrationUtils.prepareTestPropeties();
|
||||
m_config = new MemoryConfig(configProps);
|
||||
m_server.startServer(m_config);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
startServer();
|
||||
m_client = new Client("localhost");
|
||||
m_subscriberDef = new MQTT();
|
||||
m_subscriberDef.setHost("localhost", 1883);
|
||||
m_subscriberDef.setClientId("Subscriber");
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
m_client.close();
|
||||
LOG.debug("After raw client close");
|
||||
Thread.sleep(300); //to let the close event pass before server stop event
|
||||
m_server.stopServer();
|
||||
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();
|
||||
connectMessage.setProtocolVersion((byte) 3);
|
||||
connectMessage.setClientID("FAKECLNT");
|
||||
connectMessage.setKeepAlive(keepAlive);
|
||||
m_client.sendMessage(connectMessage);
|
||||
|
||||
//wait 2 times the keepAlive
|
||||
Thread.sleep(keepAlive * 2 * 1000);
|
||||
|
||||
assertTrue(m_client.isConnectionLost());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkWillMessageIsWiredOnClientKeepAliveExpiry() throws Exception {
|
||||
LOG.info("*** checkWillMessageIsWiredOnClientKeepAliveExpiry ***");
|
||||
String willTestamentTopic = "/will/test";
|
||||
String willTestamentMsg = "Bye bye";
|
||||
|
||||
BlockingConnection willSubscriber = m_subscriberDef.blockingConnection();
|
||||
willSubscriber.connect();
|
||||
Topic[] topics = new Topic[]{new Topic(willTestamentTopic, QoS.AT_MOST_ONCE)};
|
||||
willSubscriber.subscribe(topics);
|
||||
|
||||
int keepAlive = 2; //secs
|
||||
ConnectMessage connectMessage = new ConnectMessage();
|
||||
connectMessage.setProtocolVersion((byte) 3);
|
||||
connectMessage.setClientID("FAKECLNT");
|
||||
connectMessage.setKeepAlive(keepAlive);
|
||||
connectMessage.setWillFlag(true);
|
||||
connectMessage.setWillMessage(willTestamentMsg.getBytes());
|
||||
connectMessage.setWillTopic(willTestamentTopic);
|
||||
connectMessage.setWillQos(QOSType.MOST_ONE.byteValue());
|
||||
|
||||
//Execute
|
||||
m_client.sendMessage(connectMessage);
|
||||
long connectTime = System.currentTimeMillis();
|
||||
|
||||
//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
|
||||
Message msg = willSubscriber.receive(3300, TimeUnit.MILLISECONDS);
|
||||
long willMessageReceiveTime = System.currentTimeMillis();
|
||||
if (msg == null) {
|
||||
LOG.warn("testament message is null");
|
||||
}
|
||||
assertNotNull("the will message should be fired after keep alive!", msg);
|
||||
msg.ack();
|
||||
//the will message hasn't to be received before the elapsing of Keep Alive timeout
|
||||
assertTrue(willMessageReceiveTime - connectTime > 3000);
|
||||
|
||||
assertEquals(willTestamentMsg, new String(msg.getPayload()));
|
||||
willSubscriber.disconnect();
|
||||
}
|
||||
|
||||
AbstractMessage receivedMsg;
|
||||
|
||||
@Test
|
||||
public void checkRejectConnectWithEmptyClientID() throws InterruptedException {
|
||||
LOG.info("*** checkRejectConnectWithEmptyClientID ***");
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
m_client.setCallback(new Client.ICallback() {
|
||||
|
||||
public void call(AbstractMessage msg) {
|
||||
receivedMsg = msg;
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
int keepAlive = 2; //secs
|
||||
ConnectMessage connectMessage = new ConnectMessage();
|
||||
connectMessage.setProtocolVersion((byte) 4);
|
||||
connectMessage.setClientID("");
|
||||
connectMessage.setKeepAlive(keepAlive);
|
||||
connectMessage.setWillFlag(false);
|
||||
connectMessage.setWillQos(QOSType.MOST_ONE.byteValue());
|
||||
|
||||
//Execute
|
||||
m_client.sendMessage(connectMessage);
|
||||
|
||||
latch.await(200, TimeUnit.MILLISECONDS);
|
||||
|
||||
assertTrue(receivedMsg instanceof ConnAckMessage);
|
||||
ConnAckMessage connAck = (ConnAckMessage) receivedMsg;
|
||||
assertEquals(ConnAckMessage.IDENTIFIER_REJECTED, connAck.getReturnCode());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2015 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* 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.server;
|
||||
|
||||
import io.moquette.server.config.IConfig;
|
||||
import io.moquette.server.config.MemoryConfig;
|
||||
import org.fusesource.mqtt.client.*;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class ServerRestartIntegrationTest {
|
||||
|
||||
Server m_server;
|
||||
MQTT m_mqtt;
|
||||
BlockingConnection m_subscriber;
|
||||
BlockingConnection m_publisher;
|
||||
IConfig m_config;
|
||||
|
||||
protected void startServer() throws IOException {
|
||||
m_server = new Server();
|
||||
final Properties configProps = IntegrationUtils.prepareTestPropeties();
|
||||
m_config = new MemoryConfig(configProps);
|
||||
m_server.startServer(m_config);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
startServer();
|
||||
|
||||
m_mqtt = new MQTT();
|
||||
|
||||
m_mqtt.setHost("localhost", 1883);
|
||||
m_mqtt.setCleanSession(false);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
if (m_subscriber != null) {
|
||||
m_subscriber.disconnect();
|
||||
}
|
||||
|
||||
if (m_publisher != null) {
|
||||
m_publisher.disconnect();
|
||||
}
|
||||
|
||||
m_server.stopServer();
|
||||
IntegrationUtils.cleanPersistenceFile(m_config);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void checkRestartCleanSubscriptionTree() throws Exception {
|
||||
m_mqtt.setClientId("Subscriber");
|
||||
//subscribe to /topic
|
||||
m_subscriber = m_mqtt.blockingConnection();
|
||||
m_subscriber.connect();
|
||||
Topic[] topics = new Topic[]{new Topic("/topic", QoS.AT_LEAST_ONCE)};
|
||||
m_subscriber.subscribe(topics);
|
||||
m_subscriber.disconnect();
|
||||
|
||||
//shutdown the server
|
||||
m_server.stopServer();
|
||||
IntegrationUtils.cleanPersistenceFile(m_config);
|
||||
|
||||
//restart the server
|
||||
m_server.startServer(IntegrationUtils.prepareTestPropeties());
|
||||
|
||||
//reconnect the Subscriber subscribing to the same /topic but different QoS
|
||||
m_subscriber = m_mqtt.blockingConnection();
|
||||
m_subscriber.connect();
|
||||
topics = new Topic[]{new Topic("/topic", QoS.EXACTLY_ONCE)};
|
||||
m_subscriber.subscribe(topics);
|
||||
|
||||
//should be just one registration so a publisher receive one notification
|
||||
MQTT mqtt = new MQTT();
|
||||
mqtt.setHost("localhost", 1883);
|
||||
mqtt.setClientId("Publisher");
|
||||
m_publisher = mqtt.blockingConnection();
|
||||
m_publisher.connect();
|
||||
m_publisher.publish("/topic", "Hello world MQTT!!".getBytes(), QoS.AT_LEAST_ONCE, false);
|
||||
|
||||
//read the messages
|
||||
Message msg = m_subscriber.receive();
|
||||
msg.ack();
|
||||
assertEquals("Hello world MQTT!!", new String(msg.getPayload()));
|
||||
//no more messages on the same topic will be received
|
||||
assertNull(m_subscriber.receive(1, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void checkDontPublishInactiveClientsAfterServerRestart() throws Exception {
|
||||
m_mqtt.setClientId("SubPub");
|
||||
BlockingConnection conn = subscribeAndPublish("/topic");
|
||||
conn.disconnect();
|
||||
|
||||
//shutdown the server
|
||||
m_server.stopServer();
|
||||
|
||||
//restart the server
|
||||
m_server.startServer(IntegrationUtils.prepareTestPropeties());
|
||||
|
||||
MQTT mqtt = new MQTT();
|
||||
mqtt.setHost("localhost", 1883);
|
||||
mqtt.setClientId("Publisher");
|
||||
m_publisher = mqtt.blockingConnection();
|
||||
m_publisher.connect();
|
||||
m_publisher.publish("/topic", "Hello world MQTT!!".getBytes(), QoS.AT_MOST_ONCE, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientDoesntRemainSubscribedAfterASubscriptionAndServerRestart() throws Exception {
|
||||
m_mqtt.setClientId("Subscriber");
|
||||
//subscribe to /topic
|
||||
m_subscriber = m_mqtt.blockingConnection();
|
||||
m_subscriber.connect();
|
||||
Topic[] topics = new Topic[]{new Topic("/topic", QoS.AT_MOST_ONCE)};
|
||||
//subscribe /topic
|
||||
m_subscriber.subscribe(topics);
|
||||
//unsubscribe from /topic
|
||||
m_subscriber.unsubscribe(new String[]{"/topic"});
|
||||
m_subscriber.disconnect();
|
||||
|
||||
//shutdown the server
|
||||
m_server.stopServer();
|
||||
|
||||
//restart the server
|
||||
m_server.startServer(IntegrationUtils.prepareTestPropeties());
|
||||
//subscriber reconnects
|
||||
MQTT mqttSub = new MQTT();
|
||||
mqttSub.setHost("localhost", 1883);
|
||||
mqttSub.setClientId("Subscriber");
|
||||
m_subscriber = mqttSub.blockingConnection();
|
||||
m_subscriber.connect();
|
||||
|
||||
//publisher publishes on /topic
|
||||
MQTT mqtt = new MQTT();
|
||||
mqtt.setHost("localhost", 1883);
|
||||
mqtt.setClientId("Publisher");
|
||||
m_publisher = mqtt.blockingConnection();
|
||||
m_publisher.connect();
|
||||
m_publisher.publish("/topic", "Hello world MQTT!!".getBytes(), QoS.AT_LEAST_ONCE, false);
|
||||
|
||||
//Expected
|
||||
//the subscriber doesn't get notified (it's fully unsubscribed)
|
||||
assertNull(m_subscriber.receive(1, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect subscribe to topic and publish on the same topic
|
||||
* */
|
||||
private BlockingConnection subscribeAndPublish(String topic) throws Exception {
|
||||
BlockingConnection conn = m_mqtt.blockingConnection();
|
||||
conn.connect();
|
||||
Topic[] topics = new Topic[]{new Topic(topic, QoS.AT_MOST_ONCE)};
|
||||
conn.subscribe(topics);
|
||||
conn.publish(topic, "Hello world MQTT!!".getBytes(), QoS.AT_MOST_ONCE, false);
|
||||
//read the message
|
||||
Message msg = conn.receive();
|
||||
msg.ack();
|
||||
assertEquals("Hello world MQTT!!", new String(msg.getPayload()));
|
||||
return conn;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2015 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* 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.server;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
|
||||
import org.eclipse.paho.client.mqttv3.MqttCallback;
|
||||
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
class TestCallback implements MqttCallback {
|
||||
|
||||
private MqttMessage m_message;
|
||||
private String m_topic;
|
||||
private CountDownLatch m_latch = new CountDownLatch(1);
|
||||
|
||||
public MqttMessage getMessage(boolean checkElapsed) {
|
||||
try {
|
||||
boolean elapsed = !m_latch.await(1, TimeUnit.SECONDS);
|
||||
if (elapsed && checkElapsed) {
|
||||
throw new IllegalStateException("Elapsed the timeout to get the result");
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return m_message;
|
||||
}
|
||||
|
||||
public String getTopic() {
|
||||
try {
|
||||
m_latch.await(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return m_topic;
|
||||
}
|
||||
|
||||
void reinit() {
|
||||
m_latch = new CountDownLatch(1);
|
||||
m_message = null;
|
||||
m_topic = null;
|
||||
}
|
||||
|
||||
public void connectionLost(Throwable cause) {
|
||||
}
|
||||
|
||||
public void messageArrived(String topic, MqttMessage message) throws Exception {
|
||||
m_message = message;
|
||||
m_topic = topic;
|
||||
m_latch.countDown();
|
||||
}
|
||||
|
||||
public void deliveryComplete(IMqttDeliveryToken token) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2015 The original author or authors
|
||||
* ------------------------------------------------------
|
||||
* 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.server.config;
|
||||
|
||||
import io.moquette.commons.Constants;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.text.ParseException;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author andrea
|
||||
*/
|
||||
public class ConfigurationParserTest {
|
||||
|
||||
ConfigurationParser m_parser;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
m_parser = new ConfigurationParser();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkDefaultOptions() {
|
||||
Properties props = m_parser.getProperties();
|
||||
|
||||
verifyDefaults(props);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseEmpty() throws ParseException {
|
||||
Reader conf = new StringReader(" ");
|
||||
m_parser.parse(conf);
|
||||
|
||||
//Verify
|
||||
verifyDefaults(m_parser.getProperties());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseValidComment() throws ParseException {
|
||||
Reader conf = new StringReader("#simple comment");
|
||||
m_parser.parse(conf);
|
||||
|
||||
//Verify
|
||||
verifyDefaults(m_parser.getProperties());
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void parseInvalidComment() throws ParseException {
|
||||
Reader conf = new StringReader(" #simple comment");
|
||||
m_parser.parse(conf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseSingleVariable() throws ParseException {
|
||||
Reader conf = new StringReader("port 1234");
|
||||
m_parser.parse(conf);
|
||||
|
||||
//Verify
|
||||
assertEquals("1234", m_parser.getProperties().getProperty("port"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseCompleteFile() throws ParseException {
|
||||
String content = "# This is initial m_config format \r\n"
|
||||
+ " \r\n"
|
||||
+ "port 1234 \r\n"
|
||||
+ "host localhost \r\n"
|
||||
+ "fake multi word string property\r\n";
|
||||
Reader conf = new StringReader(content);
|
||||
m_parser.parse(conf);
|
||||
|
||||
//Verify
|
||||
Properties props = m_parser.getProperties();
|
||||
assertEquals("1234", props.getProperty("port"));
|
||||
assertEquals("localhost", props.getProperty("host"));
|
||||
assertEquals("multi word string property", props.getProperty("fake"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to verify default options.
|
||||
*/
|
||||
private void verifyDefaults(Properties props) {
|
||||
Assert.assertEquals(Constants.PORT, Integer.parseInt(props.getProperty("port")));
|
||||
Assert.assertEquals(Constants.HOST, props.getProperty("host"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user