Rearchitected the broker, switching from ProtocolProcessor and publisher to MQTTConnection, Session and PostOffice
This commit is contained in:
+10
-22
@@ -15,14 +15,12 @@
|
||||
*/
|
||||
package io.moquette.spi.impl;
|
||||
|
||||
import io.moquette.interception.InterceptHandler;
|
||||
import io.moquette.persistence.MemoryStorageService;
|
||||
import io.moquette.server.netty.NettyUtils;
|
||||
import io.moquette.spi.IMessagesStore;
|
||||
import io.moquette.spi.ISessionsStore;
|
||||
import io.moquette.spi.impl.security.PermitAllAuthorizator;
|
||||
import io.moquette.spi.impl.security.PermitAllAuthorizatorPolicy;
|
||||
import io.moquette.spi.impl.subscriptions.*;
|
||||
import io.moquette.spi.security.IAuthorizator;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.handler.codec.mqtt.*;
|
||||
@@ -81,7 +79,7 @@ abstract class AbstractProtocolProcessorCommonUtils {
|
||||
subscriptions.init(sessionsRepository);
|
||||
m_processor = new ProtocolProcessor();
|
||||
m_processor.init(subscriptions, m_messagesStore, m_sessionStore, m_mockAuthenticator, true,
|
||||
new PermitAllAuthorizator(), NO_OBSERVERS_INTERCEPTOR, sessionsRepository, false);
|
||||
new PermitAllAuthorizatorPolicy(), NO_OBSERVERS_INTERCEPTOR, sessionsRepository, false);
|
||||
}
|
||||
|
||||
void verifyNoPublishIsReceived() {
|
||||
@@ -126,14 +124,14 @@ abstract class AbstractProtocolProcessorCommonUtils {
|
||||
assertEquals(expectedSubscription, subscription);
|
||||
}
|
||||
|
||||
protected MqttSubAckMessage subscribeWithoutVerify(String topic, MqttQoS desiredQos) {
|
||||
MqttSubscribeMessage subscribe = MqttMessageBuilders.subscribe()
|
||||
.addSubscription(desiredQos, topic)
|
||||
.messageId(1)
|
||||
.build();
|
||||
this.m_processor.processSubscribe(m_channel, subscribe);
|
||||
return m_channel.readOutbound();
|
||||
}
|
||||
// protected MqttSubAckMessage subscribeWithoutVerify(String topic, MqttQoS desiredQos) {
|
||||
// MqttSubscribeMessage subscribe = MqttMessageBuilders.subscribe()
|
||||
// .addSubscription(desiredQos, topic)
|
||||
// .messageId(1)
|
||||
// .build();
|
||||
// this.m_processor.processSubscribe(m_channel, subscribe);
|
||||
// return m_channel.readOutbound();
|
||||
// }
|
||||
|
||||
protected void subscribeAndNotReadResponse(String topic, MqttQoS desiredQos) {
|
||||
MqttSubscribeMessage subscribe = MqttMessageBuilders.subscribe()
|
||||
@@ -143,16 +141,6 @@ abstract class AbstractProtocolProcessorCommonUtils {
|
||||
this.m_processor.processSubscribe(m_channel, subscribe);
|
||||
}
|
||||
|
||||
protected void unsubscribe(String topic) {
|
||||
final int messageId = 1;
|
||||
MqttUnsubscribeMessage msg = MqttMessageBuilders.unsubscribe()
|
||||
.addTopicFilter(topic)
|
||||
.messageId(messageId)
|
||||
.build();
|
||||
|
||||
m_processor.processUnsubscribe(m_channel, msg);
|
||||
}
|
||||
|
||||
protected void unsubscribeAndVerifyAck(String topic) {
|
||||
final int messageId = 1;
|
||||
MqttUnsubscribeMessage msg = MqttMessageBuilders.unsubscribe()
|
||||
|
||||
@@ -1,315 +0,0 @@
|
||||
package io.moquette.spi.impl;
|
||||
|
||||
import io.moquette.persistence.MemoryStorageService;
|
||||
import io.moquette.server.ConnectionDescriptorStore;
|
||||
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.security.PermitAllAuthorizator;
|
||||
import io.moquette.spi.impl.subscriptions.CTrieSubscriptionDirectory;
|
||||
import io.moquette.spi.impl.subscriptions.ISubscriptionsDirectory;
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.handler.codec.mqtt.MqttConnectMessage;
|
||||
import io.netty.handler.codec.mqtt.MqttMessageBuilders;
|
||||
import io.netty.handler.codec.mqtt.MqttVersion;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static io.moquette.spi.impl.NettyChannelAssertions.assertEqualsConnAck;
|
||||
import static io.moquette.spi.impl.ProtocolProcessorTest.*;
|
||||
import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.*;
|
||||
import static java.util.Collections.singleton;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ConnectHandlerTest {
|
||||
|
||||
EmbeddedChannel session;
|
||||
MqttMessageBuilders.ConnectBuilder connMsg;
|
||||
|
||||
IMessagesStore m_messagesStore;
|
||||
ISessionsStore m_sessionStore;
|
||||
ISubscriptionsDirectory subscriptions;
|
||||
MockAuthenticator m_mockAuthenticator;
|
||||
private ConnectHandler sut;
|
||||
private DisconnectHandler disconnectHandler;
|
||||
private SessionsRepository sessionsRepository;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
connMsg = MqttMessageBuilders.connect().protocolVersion(MqttVersion.MQTT_3_1).cleanSession(true);
|
||||
|
||||
session = new EmbeddedChannel();
|
||||
|
||||
MemoryStorageService memStorage = new MemoryStorageService(null, null);
|
||||
m_messagesStore = memStorage.messagesStore();
|
||||
m_sessionStore = memStorage.sessionsStore();
|
||||
m_mockAuthenticator = new MockAuthenticator(singleton(FAKE_CLIENT_ID), singletonMap(TEST_USER, TEST_PWD));
|
||||
|
||||
subscriptions = new CTrieSubscriptionDirectory();
|
||||
sessionsRepository = new SessionsRepository(m_sessionStore, null);
|
||||
subscriptions.init(sessionsRepository);
|
||||
|
||||
final ConnectionDescriptorStore connectionsRegistry = new ConnectionDescriptorStore();
|
||||
sut = new ConnectHandler(connectionsRegistry, NO_OBSERVERS_INTERCEPTOR, sessionsRepository, m_sessionStore, m_mockAuthenticator,
|
||||
new PermitAllAuthorizator(), subscriptions, true, true, false, null);
|
||||
|
||||
disconnectHandler = new DisconnectHandler(connectionsRegistry, sessionsRepository,
|
||||
subscriptions, NO_OBSERVERS_INTERCEPTOR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZeroByteClientIdWithCleanSession() {
|
||||
// Allow zero byte client ids
|
||||
sut = new ConnectHandler(new ConnectionDescriptorStore(), NO_OBSERVERS_INTERCEPTOR, new SessionsRepository(this.m_sessionStore, null), m_sessionStore, m_mockAuthenticator,
|
||||
new PermitAllAuthorizator(), subscriptions, true, true, false, null);
|
||||
|
||||
// Connect message with clean session set to true and client id is null.
|
||||
MqttConnectMessage msg = connMsg.clientId(null)
|
||||
.protocolVersion(MqttVersion.MQTT_3_1_1)
|
||||
.cleanSession(true)
|
||||
.build();
|
||||
|
||||
sut.processConnect(session, msg);
|
||||
assertEqualsConnAck("Connection MUST be accepted, unique clientid MUST be generated and clean session to true",
|
||||
CONNECTION_ACCEPTED, session.readOutbound());
|
||||
assertTrue("Connection should be valid and open,", session.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidAuthentication() {
|
||||
MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID)
|
||||
.username(TEST_USER + "_fake")
|
||||
.password(TEST_PWD)
|
||||
.build();
|
||||
|
||||
// Exercise
|
||||
sut.processConnect(session, msg);
|
||||
|
||||
// Verify
|
||||
assertEqualsConnAck(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD, session.readOutbound());
|
||||
assertFalse("Connection should be closed by the broker.", session.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnect_badClientID() {
|
||||
connMsg.clientId("extremely_long_clientID_greater_than_23").build();
|
||||
|
||||
// Exercise
|
||||
sut.processConnect(session, connMsg.clientId("extremely_long_clientID_greater_than_23").build());
|
||||
|
||||
// Verify
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, session.readOutbound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWill() {
|
||||
MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID).willFlag(true)
|
||||
.willTopic("topic").willMessage("Topic message").build();
|
||||
|
||||
// Exercise
|
||||
// m_handler.setMessaging(mockedMessaging);
|
||||
sut.processConnect(session, msg);
|
||||
|
||||
// Verify
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, session.readOutbound());
|
||||
assertTrue("Connection is accepted and therefore should remain open.", session.isOpen());
|
||||
// TODO verify the call
|
||||
/*
|
||||
* verify(mockedMessaging).publish(eq("topic"), eq("Topic message".getBytes()),
|
||||
* any(AbstractMessage.QOSType.class), anyBoolean(), eq("123"), any(IoSession.class));
|
||||
*/
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectWithSameClientIDBadCredentialsDoesntDropExistingClient() {
|
||||
// Connect a client1
|
||||
MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID)
|
||||
.username(TEST_USER)
|
||||
.password(TEST_PWD)
|
||||
.build();
|
||||
sut.processConnect(session, msg);
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, session.readOutbound());
|
||||
|
||||
// create another connect same clientID but with bad credentials
|
||||
MqttConnectMessage evilClientConnMsg = MqttMessageBuilders.connect()
|
||||
.protocolVersion(MqttVersion.MQTT_3_1)
|
||||
.clientId(FAKE_CLIENT_ID)
|
||||
.username(ProtocolProcessorTest.EVIL_TEST_USER)
|
||||
.password(ProtocolProcessorTest.EVIL_TEST_PWD)
|
||||
.build();
|
||||
|
||||
EmbeddedChannel evilSession = new EmbeddedChannel();
|
||||
|
||||
// Exercise
|
||||
sut.processConnect(evilSession, evilClientConnMsg);
|
||||
|
||||
// Verify
|
||||
// the evil client gets a not auth notification
|
||||
assertEqualsConnAck(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD, evilSession.readOutbound());
|
||||
// the good client remains connected
|
||||
assertTrue(session.isOpen());
|
||||
assertFalse(evilSession.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void acceptAnonymousClient() {
|
||||
MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID).build();
|
||||
|
||||
// Exercise
|
||||
sut.processConnect(session, msg);
|
||||
|
||||
// Verify
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, session.readOutbound());
|
||||
assertTrue("Connection is accepted and therefore should remain open.", session.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validAuthentication() {
|
||||
MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID)
|
||||
.username(TEST_USER).password(TEST_PWD).build();
|
||||
|
||||
// Exercise
|
||||
sut.processConnect(session, msg);
|
||||
|
||||
// Verify
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, session.readOutbound());
|
||||
assertTrue("Connection is accepted and therefore should remain open.", session.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noPasswdAuthentication() {
|
||||
MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID)
|
||||
.username(TEST_USER)
|
||||
.build();
|
||||
|
||||
// Exercise
|
||||
sut.processConnect(session, msg);
|
||||
|
||||
// Verify
|
||||
assertEqualsConnAck(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD, session.readOutbound());
|
||||
assertFalse("Connection should be closed by the broker.", session.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void prohibitAnonymousClient() {
|
||||
MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID).build();
|
||||
reinitProcessorProhibitingAnonymousClients();
|
||||
|
||||
// Exercise
|
||||
sut.processConnect(session, msg);
|
||||
|
||||
// Verify
|
||||
assertEqualsConnAck(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD, session.readOutbound());
|
||||
assertFalse("Connection should be closed by the broker.", session.isOpen());
|
||||
}
|
||||
|
||||
protected void reinitProcessorProhibitingAnonymousClients() {
|
||||
sut = new ConnectHandler(new ConnectionDescriptorStore(), NO_OBSERVERS_INTERCEPTOR, new SessionsRepository(this.m_sessionStore, null), m_sessionStore, m_mockAuthenticator,
|
||||
new PermitAllAuthorizator(), subscriptions, false, true, false, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void prohibitAnonymousClient_providingUsername() {
|
||||
MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID)
|
||||
.username(TEST_USER + "_fake")
|
||||
.build();
|
||||
reinitProcessorProhibitingAnonymousClients();
|
||||
|
||||
// Exercise
|
||||
sut.processConnect(session, msg);
|
||||
|
||||
// Verify
|
||||
assertEqualsConnAck(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD, session.readOutbound());
|
||||
assertFalse("Connection should be closed by the broker.", session.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZeroByteClientIdNotAllowed() {
|
||||
sut = new ConnectHandler(new ConnectionDescriptorStore(), NO_OBSERVERS_INTERCEPTOR, new SessionsRepository(this.m_sessionStore, null), m_sessionStore, m_mockAuthenticator,
|
||||
new PermitAllAuthorizator(), subscriptions, false, false, false, null);
|
||||
|
||||
// Connect message with clean session set to true and client id is null.
|
||||
MqttConnectMessage msg = connMsg.clientId(null)
|
||||
.protocolVersion(MqttVersion.MQTT_3_1_1)
|
||||
.cleanSession(true)
|
||||
.build();
|
||||
|
||||
sut.processConnect(session, msg);
|
||||
assertEqualsConnAck("Zero byte client identifiers are not allowed",
|
||||
CONNECTION_REFUSED_IDENTIFIER_REJECTED, session.readOutbound());
|
||||
|
||||
assertFalse("Connection should closed.", session.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZeroByteClientIdWithoutCleanSession() {
|
||||
// Allow zero byte client ids
|
||||
reinitProtocolProcessorWithZeroLengthClientIdAndAnonymousClients();
|
||||
|
||||
// Connect message without clean session set to true but client id is still null
|
||||
MqttConnectMessage msg = MqttMessageBuilders.connect().clientId(null).protocolVersion(MqttVersion.MQTT_3_1_1)
|
||||
.build();
|
||||
|
||||
sut.processConnect(session, msg);
|
||||
assertEqualsConnAck(
|
||||
"Identifier should be rejected due to having clean session set to false.",
|
||||
CONNECTION_REFUSED_IDENTIFIER_REJECTED,
|
||||
session.readOutbound());
|
||||
|
||||
assertFalse("Connection should be closed by the broker.", session.isOpen());
|
||||
}
|
||||
|
||||
protected void reinitProtocolProcessorWithZeroLengthClientIdAndAnonymousClients() {
|
||||
sut = new ConnectHandler(new ConnectionDescriptorStore(), NO_OBSERVERS_INTERCEPTOR, new SessionsRepository(this.m_sessionStore, null), m_sessionStore, m_mockAuthenticator,
|
||||
new PermitAllAuthorizator(), subscriptions, true, true, false, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnAckContainsSessionPresentFlag() {
|
||||
MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID)
|
||||
.protocolVersion(MqttVersion.MQTT_3_1_1).build();
|
||||
NettyUtils.clientID(session, FAKE_CLIENT_ID);
|
||||
NettyUtils.cleanSession(session, false);
|
||||
|
||||
// Connect a first time
|
||||
sut.processConnect(session, msg);
|
||||
// disconnect
|
||||
disconnectHandler.processDisconnect(session, FAKE_CLIENT_ID);
|
||||
|
||||
// Exercise, reconnect
|
||||
EmbeddedChannel firstReceiverSession = new EmbeddedChannel();
|
||||
sut.processConnect(firstReceiverSession, msg);
|
||||
|
||||
// Verify
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, firstReceiverSession.readOutbound());
|
||||
assertTrue("Connection is accepted and therefore should remain open.", firstReceiverSession.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectWithCleanSessionUpdateClientSession() {
|
||||
// first connect with clean session true
|
||||
MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID).cleanSession(true).build();
|
||||
sut.processConnect(session, msg);
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, session.readOutbound());
|
||||
disconnectHandler.processDisconnect(session, FAKE_CLIENT_ID);
|
||||
assertFalse(session.isOpen());
|
||||
|
||||
// second connect with clean session false
|
||||
session = new EmbeddedChannel();
|
||||
MqttConnectMessage secondConnMsg = MqttMessageBuilders.connect().clientId(FAKE_CLIENT_ID)
|
||||
.protocolVersion(MqttVersion.MQTT_3_1).build();
|
||||
|
||||
sut.processConnect(session, secondConnMsg);
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, session.readOutbound());
|
||||
|
||||
// Verify client session is clean false
|
||||
ClientSession session = sessionsRepository.sessionForClient(FAKE_CLIENT_ID);
|
||||
assertFalse(session.isCleanSession());
|
||||
|
||||
// Verify
|
||||
// assertEqualsConnAck(CONNECTION_ACCEPTED, session.readOutbound());
|
||||
}
|
||||
}
|
||||
@@ -25,12 +25,12 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
/**
|
||||
* Test utility to implements authenticator instance.
|
||||
*/
|
||||
class MockAuthenticator implements IAuthenticator {
|
||||
public class MockAuthenticator implements IAuthenticator {
|
||||
|
||||
private Set<String> m_clientIds;
|
||||
private Map<String, String> m_userPwds;
|
||||
|
||||
MockAuthenticator(Set<String> clientIds, Map<String, String> userPwds) {
|
||||
public MockAuthenticator(Set<String> clientIds, Map<String, String> userPwds) {
|
||||
m_clientIds = clientIds;
|
||||
m_userPwds = userPwds;
|
||||
}
|
||||
|
||||
@@ -27,13 +27,13 @@ import static org.junit.Assert.assertTrue;
|
||||
/**
|
||||
* Some useful assertions used by Netty's EmbeddedChannel in tests.
|
||||
*/
|
||||
final class NettyChannelAssertions {
|
||||
public final class NettyChannelAssertions {
|
||||
|
||||
static void assertEqualsConnAck(MqttConnectReturnCode expectedCode, Object connAck) {
|
||||
public static void assertEqualsConnAck(MqttConnectReturnCode expectedCode, Object connAck) {
|
||||
assertEqualsConnAck(null, expectedCode, connAck);
|
||||
}
|
||||
|
||||
static void assertEqualsConnAck(String msg, MqttConnectReturnCode expectedCode, Object connAck) {
|
||||
public static void assertEqualsConnAck(String msg, MqttConnectReturnCode expectedCode, Object connAck) {
|
||||
assertTrue("connAck is not an instance of ConnAckMessage", connAck instanceof MqttConnAckMessage);
|
||||
MqttConnAckMessage connAckMsg = (MqttConnAckMessage) connAck;
|
||||
|
||||
@@ -43,12 +43,12 @@ final class NettyChannelAssertions {
|
||||
assertEquals(msg, expectedCode, connAckMsg.variableHeader().connectReturnCode());
|
||||
}
|
||||
|
||||
static void assertConnAckAccepted(EmbeddedChannel channel) {
|
||||
public static void assertConnAckAccepted(EmbeddedChannel channel) {
|
||||
channel.flush();
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, channel.readOutbound());
|
||||
}
|
||||
|
||||
static void assertEqualsSubAck(/* byte expectedCode, */ Object subAck) {
|
||||
public static void assertEqualsSubAck(/* byte expectedCode, */ Object subAck) {
|
||||
assertTrue(subAck instanceof MqttSubAckMessage);
|
||||
// SubAckMessage connAckMsg = (SubAckMessage) connAck;
|
||||
// assertEquals(expectedCode, connAckMsg.getReturnCode());
|
||||
|
||||
@@ -16,17 +16,18 @@
|
||||
|
||||
package io.moquette.spi.impl;
|
||||
|
||||
import io.moquette.broker.PostOfficePublishTest;
|
||||
import io.moquette.interception.InterceptHandler;
|
||||
import io.moquette.persistence.MemoryStorageService;
|
||||
import io.moquette.server.netty.NettyUtils;
|
||||
import io.moquette.spi.IMessagesStore;
|
||||
import io.moquette.spi.IMessagesStore.StoredMessage;
|
||||
import io.moquette.spi.impl.security.PermitAllAuthorizator;
|
||||
import io.moquette.spi.impl.security.PermitAllAuthorizatorPolicy;
|
||||
import io.moquette.spi.impl.subscriptions.CTrieSubscriptionDirectory;
|
||||
import io.moquette.spi.impl.subscriptions.ISubscriptionsDirectory;
|
||||
import io.moquette.spi.impl.subscriptions.Subscription;
|
||||
import io.moquette.spi.impl.subscriptions.Topic;
|
||||
import io.moquette.spi.security.IAuthorizator;
|
||||
import io.moquette.spi.security.IAuthorizatorPolicy;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.handler.codec.mqtt.*;
|
||||
@@ -69,201 +70,138 @@ public class ProtocolProcessorTest extends AbstractProtocolProcessorCommonUtils
|
||||
initializeProcessorAndSubsystems();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublishToItself() {
|
||||
final Subscription subscription = new Subscription(FAKE_CLIENT_ID, new Topic(NEWS_TOPIC), AT_MOST_ONCE);
|
||||
//same test moved into PostOfficePublishTest
|
||||
// @Test
|
||||
// public void testPublishToItself() {
|
||||
// final Subscription subscription = new Subscription(FAKE_CLIENT_ID, new Topic(NEWS_TOPIC), AT_MOST_ONCE);
|
||||
//
|
||||
// // subscriptions.matches(topic) redefine the method to return true
|
||||
// ISubscriptionsDirectory subs = new CTrieSubscriptionDirectory() {
|
||||
//
|
||||
// @Override
|
||||
// public List<Subscription> matches(Topic topic) {
|
||||
// if (topic.toString().equals(NEWS_TOPIC)) {
|
||||
// return Collections.singletonList(subscription);
|
||||
// } else {
|
||||
// throw new IllegalArgumentException("Expected " + NEWS_TOPIC + " buf found " + topic);
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// // simulate a connect that register a clientID to an IoSession
|
||||
// MemoryStorageService storageService = new MemoryStorageService(null, null);
|
||||
// SessionsRepository sessionsRepository = new SessionsRepository(storageService.sessionsStore(), null);
|
||||
// subs.init(sessionsRepository);
|
||||
// m_processor.init(subs, m_messagesStore, m_sessionStore, null, true, new PermitAllAuthorizatorPolicy(),
|
||||
// NO_OBSERVERS_INTERCEPTOR, this.sessionsRepository, false);
|
||||
//
|
||||
// connect_v3_1();
|
||||
//
|
||||
// // Exercise
|
||||
// publishToAs("FakeCLI", NEWS_TOPIC, AT_MOST_ONCE, false);
|
||||
//
|
||||
// // Verify
|
||||
// verifyPublishIsReceived();
|
||||
// }
|
||||
|
||||
// subscriptions.matches(topic) redefine the method to return true
|
||||
ISubscriptionsDirectory subs = new CTrieSubscriptionDirectory() {
|
||||
|
||||
@Override
|
||||
public List<Subscription> matches(Topic topic) {
|
||||
if (topic.toString().equals(NEWS_TOPIC)) {
|
||||
return Collections.singletonList(subscription);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Expected " + NEWS_TOPIC + " buf found " + topic);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// simulate a connect that register a clientID to an IoSession
|
||||
MemoryStorageService storageService = new MemoryStorageService(null, null);
|
||||
SessionsRepository sessionsRepository = new SessionsRepository(storageService.sessionsStore(), null);
|
||||
subs.init(sessionsRepository);
|
||||
m_processor.init(subs, m_messagesStore, m_sessionStore, null, true, new PermitAllAuthorizator(),
|
||||
NO_OBSERVERS_INTERCEPTOR, this.sessionsRepository, false);
|
||||
|
||||
connect_v3_1();
|
||||
|
||||
// Exercise
|
||||
publishToAs("FakeCLI", NEWS_TOPIC, AT_MOST_ONCE, false);
|
||||
|
||||
// Verify
|
||||
verifyPublishIsReceived();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublishToMultipleSubscribers() {
|
||||
final Subscription subscription = new Subscription(FAKE_CLIENT_ID, new Topic(NEWS_TOPIC), AT_MOST_ONCE);
|
||||
final Subscription subscriptionClient2 = new Subscription(
|
||||
FAKE_CLIENT_ID2,
|
||||
new Topic(NEWS_TOPIC),
|
||||
AT_MOST_ONCE);
|
||||
|
||||
// subscriptions.matches(topic) redefine the method to return true
|
||||
ISubscriptionsDirectory subs = new CTrieSubscriptionDirectory() {
|
||||
|
||||
@Override
|
||||
public List<Subscription> matches(Topic topic) {
|
||||
if (topic.toString().equals(NEWS_TOPIC)) {
|
||||
return Arrays.asList(subscription, subscriptionClient2);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Expected " + NEWS_TOPIC + " buf found " + topic);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// simulate a connect that register a clientID to an IoSession
|
||||
MemoryStorageService storageService = new MemoryStorageService(null, null);
|
||||
SessionsRepository sessionsRepository = new SessionsRepository(storageService.sessionsStore(), null);
|
||||
subs.init(sessionsRepository);
|
||||
m_processor.init(subs, m_messagesStore, m_sessionStore, null, true, new PermitAllAuthorizator(),
|
||||
NO_OBSERVERS_INTERCEPTOR, this.sessionsRepository, false);
|
||||
|
||||
EmbeddedChannel firstReceiverChannel = new EmbeddedChannel();
|
||||
MqttConnectMessage connectMessage = MqttMessageBuilders.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();
|
||||
MqttConnectMessage connectMessage2 = MqttMessageBuilders.connect().protocolVersion(MqttVersion.MQTT_3_1)
|
||||
.clientId(FAKE_CLIENT_ID2).cleanSession(true).build();
|
||||
m_processor.processConnect(secondReceiverChannel, connectMessage2);
|
||||
assertConnAckAccepted(secondReceiverChannel);
|
||||
|
||||
// Exercise
|
||||
MqttPublishMessage msg = MqttMessageBuilders.publish().topicName(NEWS_TOPIC).qos(AT_MOST_ONCE)
|
||||
.retained(false).payload(Unpooled.copiedBuffer("Hello".getBytes(UTF_8))).build();
|
||||
NettyUtils.userName(m_channel, "FakeCLI");
|
||||
m_processor.processPublish(m_channel, msg);
|
||||
|
||||
// Verify
|
||||
firstReceiverChannel.flush();
|
||||
MqttPublishMessage pub2FirstSubscriber = firstReceiverChannel.readOutbound();
|
||||
assertNotNull(pub2FirstSubscriber);
|
||||
String firstMessageContent = DebugUtils.payload2Str(pub2FirstSubscriber.payload());
|
||||
assertEquals("Hello", firstMessageContent);
|
||||
|
||||
secondReceiverChannel.flush();
|
||||
MqttPublishMessage pub2SecondSubscriber = secondReceiverChannel.readOutbound();
|
||||
assertNotNull(pub2SecondSubscriber);
|
||||
String secondMessageContent = DebugUtils.payload2Str(pub2SecondSubscriber.payload());
|
||||
assertEquals("Hello", secondMessageContent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscribe() {
|
||||
connect();
|
||||
|
||||
// Exercise & verify
|
||||
subscribe(NEWS_TOPIC, AT_MOST_ONCE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscribedToNotAuthorizedTopic() {
|
||||
final String fakeUserName = "UnAuthUser";
|
||||
NettyUtils.userName(m_channel, fakeUserName);
|
||||
|
||||
IAuthorizator mockAuthorizator = mock(IAuthorizator.class);
|
||||
when(mockAuthorizator.canRead(eq(new Topic(NEWS_TOPIC)), eq(fakeUserName), eq(FAKE_CLIENT_ID)))
|
||||
.thenReturn(false);
|
||||
|
||||
m_processor.init(subscriptions, m_messagesStore, m_sessionStore, m_mockAuthenticator, true, mockAuthorizator,
|
||||
NO_OBSERVERS_INTERCEPTOR, this.sessionsRepository, false);
|
||||
|
||||
connect();
|
||||
|
||||
//Exercise
|
||||
MqttSubAckMessage subAckMsg = subscribeWithoutVerify(NEWS_TOPIC, AT_MOST_ONCE);
|
||||
|
||||
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() {
|
||||
connect();
|
||||
assertEquals(0, subscriptions.size());
|
||||
subscribe(NEWS_TOPIC, AT_MOST_ONCE);
|
||||
assertEquals(1, subscriptions.size());
|
||||
|
||||
//Exercise & verify
|
||||
subscribe(NEWS_TOPIC, AT_MOST_ONCE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscribeWithBadFormattedTopic() {
|
||||
connect();
|
||||
assertEquals(0, subscriptions.size());
|
||||
|
||||
//Exercise
|
||||
MqttSubAckMessage subAckMsg = subscribeWithoutVerify(BAD_FORMATTED_TOPIC, AT_MOST_ONCE);
|
||||
|
||||
assertEquals(0, subscriptions.size());
|
||||
verifyFailureQos(subAckMsg);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribeWithBadFormattedTopic() {
|
||||
// Exercise
|
||||
unsubscribe(BAD_FORMATTED_TOPIC);
|
||||
|
||||
// Verify
|
||||
assertFalse("If client unsubscribe with bad topic than channel must be closed, (issue 68)", m_channel.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublishOfRetainedMessage_afterNewSubscription() throws Exception {
|
||||
// simulate a connect that register a clientID to an IoSession
|
||||
final Subscription subscription =
|
||||
new Subscription(PUBLISHER_ID, new Topic(NEWS_TOPIC), AT_MOST_ONCE);
|
||||
|
||||
// subscriptions.matches(topic) redefine the method to return true
|
||||
ISubscriptionsDirectory subs = new CTrieSubscriptionDirectory() {
|
||||
|
||||
@Override
|
||||
public List<Subscription> matches(Topic topic) {
|
||||
if (topic.toString().equals(NEWS_TOPIC)) {
|
||||
return Collections.singletonList(subscription);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Expected " + NEWS_TOPIC + " buf found " + topic);
|
||||
}
|
||||
}
|
||||
};
|
||||
MemoryStorageService storageService = new MemoryStorageService(null, null);
|
||||
SessionsRepository sessionsRepository = new SessionsRepository(storageService.sessionsStore(), null);
|
||||
subs.init(sessionsRepository);
|
||||
|
||||
// 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, this.sessionsRepository, false);
|
||||
connect_v3_1_asClient(PUBLISHER_ID);
|
||||
publishToAs(PUBLISHER_ID, NEWS_TOPIC, AT_MOST_ONCE, true);
|
||||
NettyUtils.cleanSession(m_channel, false);
|
||||
|
||||
// Exercise
|
||||
subscribeAndNotReadResponse("#", AT_MOST_ONCE);
|
||||
|
||||
// Verify
|
||||
verifyPublishIsReceived();
|
||||
}
|
||||
//same test moved into PostOfficePublishTest
|
||||
// @Test
|
||||
// public void testPublishToMultipleSubscribers() {
|
||||
// final Subscription subscription = new Subscription(FAKE_CLIENT_ID, new Topic(NEWS_TOPIC), AT_MOST_ONCE);
|
||||
// final Subscription subscriptionClient2 = new Subscription(
|
||||
// FAKE_CLIENT_ID2,
|
||||
// new Topic(NEWS_TOPIC),
|
||||
// AT_MOST_ONCE);
|
||||
//
|
||||
// // subscriptions.matches(topic) redefine the method to return true
|
||||
// ISubscriptionsDirectory subs = new CTrieSubscriptionDirectory() {
|
||||
//
|
||||
// @Override
|
||||
// public List<Subscription> matches(Topic topic) {
|
||||
// if (topic.toString().equals(NEWS_TOPIC)) {
|
||||
// return Arrays.asList(subscription, subscriptionClient2);
|
||||
// } else {
|
||||
// throw new IllegalArgumentException("Expected " + NEWS_TOPIC + " buf found " + topic);
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// // simulate a connect that register a clientID to an IoSession
|
||||
// MemoryStorageService storageService = new MemoryStorageService(null, null);
|
||||
// SessionsRepository sessionsRepository = new SessionsRepository(storageService.sessionsStore(), null);
|
||||
// subs.init(sessionsRepository);
|
||||
// m_processor.init(subs, m_messagesStore, m_sessionStore, null, true, new PermitAllAuthorizatorPolicy(),
|
||||
// NO_OBSERVERS_INTERCEPTOR, this.sessionsRepository, false);
|
||||
//
|
||||
// EmbeddedChannel firstReceiverChannel = new EmbeddedChannel();
|
||||
// MqttConnectMessage connectMessage = MqttMessageBuilders.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();
|
||||
// MqttConnectMessage connectMessage2 = MqttMessageBuilders.connect().protocolVersion(MqttVersion.MQTT_3_1)
|
||||
// .clientId(FAKE_CLIENT_ID2).cleanSession(true).build();
|
||||
// m_processor.processConnect(secondReceiverChannel, connectMessage2);
|
||||
// assertConnAckAccepted(secondReceiverChannel);
|
||||
//
|
||||
// // Exercise
|
||||
// MqttPublishMessage msg = MqttMessageBuilders.publish().topicName(NEWS_TOPIC).qos(AT_MOST_ONCE)
|
||||
// .retained(false).payload(Unpooled.copiedBuffer("Hello".getBytes(UTF_8))).build();
|
||||
// NettyUtils.userName(m_channel, "FakeCLI");
|
||||
// m_processor.processPublish(m_channel, msg);
|
||||
//
|
||||
// // Verify
|
||||
// firstReceiverChannel.flush();
|
||||
// MqttPublishMessage pub2FirstSubscriber = firstReceiverChannel.readOutbound();
|
||||
// assertNotNull(pub2FirstSubscriber);
|
||||
// String firstMessageContent = DebugUtils.payload2Str(pub2FirstSubscriber.payload());
|
||||
// assertEquals("Hello", firstMessageContent);
|
||||
//
|
||||
// secondReceiverChannel.flush();
|
||||
// MqttPublishMessage pub2SecondSubscriber = secondReceiverChannel.readOutbound();
|
||||
// assertNotNull(pub2SecondSubscriber);
|
||||
// String secondMessageContent = DebugUtils.payload2Str(pub2SecondSubscriber.payload());
|
||||
// assertEquals("Hello", secondMessageContent);
|
||||
// }
|
||||
//
|
||||
// //TODO move this test on PostOfficeSubscribeTest
|
||||
// @Test
|
||||
// public void testPublishOfRetainedMessage_afterNewSubscription() throws Exception {
|
||||
// // simulate a connect that register a clientID to an IoSession
|
||||
// final Subscription subscription =
|
||||
// new Subscription(PUBLISHER_ID, new Topic(NEWS_TOPIC), AT_MOST_ONCE);
|
||||
//
|
||||
// // subscriptions.matches(topic) redefine the method to return true
|
||||
// ISubscriptionsDirectory subs = new CTrieSubscriptionDirectory() {
|
||||
//
|
||||
// @Override
|
||||
// public List<Subscription> matches(Topic topic) {
|
||||
// if (topic.toString().equals(NEWS_TOPIC)) {
|
||||
// return Collections.singletonList(subscription);
|
||||
// } else {
|
||||
// throw new IllegalArgumentException("Expected " + NEWS_TOPIC + " buf found " + topic);
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// MemoryStorageService storageService = new MemoryStorageService(null, null);
|
||||
// SessionsRepository sessionsRepository = new SessionsRepository(storageService.sessionsStore(), null);
|
||||
// subs.init(sessionsRepository);
|
||||
//
|
||||
// // simulate a connect that register a clientID to an IoSession
|
||||
// m_processor.init(subs, m_messagesStore, m_sessionStore, null, true, new PermitAllAuthorizatorPolicy(),
|
||||
// NO_OBSERVERS_INTERCEPTOR, this.sessionsRepository, false);
|
||||
// connect_v3_1_asClient(PUBLISHER_ID);
|
||||
// publishToAs(PUBLISHER_ID, NEWS_TOPIC, AT_MOST_ONCE, true);
|
||||
// NettyUtils.cleanSession(m_channel, false);
|
||||
//
|
||||
// // Exercise
|
||||
// subscribeAndNotReadResponse("#", AT_MOST_ONCE);
|
||||
//
|
||||
// // Verify
|
||||
// verifyPublishIsReceived();
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void testRepublishAndConsumePersistedMessages_onReconnect() {
|
||||
@@ -276,7 +214,7 @@ public class ProtocolProcessorTest extends AbstractProtocolProcessorCommonUtils
|
||||
retainedMessage.setClientID(PUBLISHER_ID);
|
||||
m_messagesStore.storeRetained(new Topic("/topic"), retainedMessage);
|
||||
|
||||
m_processor.init(subs, m_messagesStore, m_sessionStore, null, true, new PermitAllAuthorizator(),
|
||||
m_processor.init(subs, m_messagesStore, m_sessionStore, null, true, new PermitAllAuthorizatorPolicy(),
|
||||
NO_OBSERVERS_INTERCEPTOR, this.sessionsRepository, false);
|
||||
|
||||
connect_v3_1_asClient(PUBLISHER_ID);
|
||||
@@ -285,84 +223,85 @@ public class ProtocolProcessorTest extends AbstractProtocolProcessorCommonUtils
|
||||
assertTrue(this.sessionsRepository.sessionForClient(PUBLISHER_ID).isEmptyQueue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishNoPublishToInactiveSession() {
|
||||
// create an inactive session for Subscriber
|
||||
ISubscriptionsDirectory mockedSubscriptions = mock(ISubscriptionsDirectory.class);
|
||||
Subscription inactiveSub = new Subscription("Subscriber", new Topic("/topic"), MqttQoS.AT_LEAST_ONCE);
|
||||
List<Subscription> inactiveSubscriptions = Collections.singletonList(inactiveSub);
|
||||
when(mockedSubscriptions.matches(eq(new Topic("/topic")))).thenReturn(inactiveSubscriptions);
|
||||
m_processor = new ProtocolProcessor();
|
||||
m_processor.init(mockedSubscriptions, m_messagesStore, m_sessionStore, null, true, new PermitAllAuthorizator(),
|
||||
NO_OBSERVERS_INTERCEPTOR, this.sessionsRepository, false);
|
||||
|
||||
m_processor.sessionsRepository.createNewSession("Subscriber", false);
|
||||
|
||||
// Exercise
|
||||
connectAsClient("Publisher");
|
||||
publishToAs("Publisher", "/topic", AT_MOST_ONCE, true);
|
||||
|
||||
verifyNoPublishIsReceived();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that receiving a publish with retained message and with Q0S = 0 clean the existing
|
||||
* retained messages for that topic.
|
||||
*/
|
||||
@Test
|
||||
public void testCleanRetainedStoreAfterAQoS0AndRetainedTrue() {
|
||||
// force a connect
|
||||
connect_v3_1_asClient("Publisher");
|
||||
|
||||
// prepare and existing retained store
|
||||
publishToAs("Publisher", NEWS_TOPIC, AT_LEAST_ONCE, 100, true);
|
||||
|
||||
Collection<IMessagesStore.StoredMessage> messages = m_messagesStore
|
||||
.searchMatching(key -> key.match(new Topic(NEWS_TOPIC)));
|
||||
assertFalse(messages.isEmpty());
|
||||
|
||||
// Exercise
|
||||
// send a message that clean the previous retained publish
|
||||
publishToAs("Publisher", NEWS_TOPIC, AT_MOST_ONCE, true);
|
||||
|
||||
// Verify
|
||||
messages = m_messagesStore.searchMatching(key -> key.match(new Topic(NEWS_TOPIC)));
|
||||
assertTrue(messages.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLowerTheQosToTheRequestedBySubscription() {
|
||||
Subscription subQos1 = new Subscription("Sub A", new Topic("a/b"), MqttQoS.AT_LEAST_ONCE);
|
||||
assertEquals(MqttQoS.AT_LEAST_ONCE, lowerQosToTheSubscriptionDesired(subQos1, EXACTLY_ONCE));
|
||||
|
||||
Subscription subQos2 = new Subscription("Sub B", new Topic("a/+"), EXACTLY_ONCE);
|
||||
assertEquals(EXACTLY_ONCE, lowerQosToTheSubscriptionDesired(subQos2, EXACTLY_ONCE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscribeReceivePublishedMessageAtSubscriberQoSAndNotPublisherQoS() {
|
||||
ISubscriptionsDirectory subs = new CTrieSubscriptionDirectory();
|
||||
MemoryStorageService storageService = new MemoryStorageService(null, null);
|
||||
SessionsRepository sessionsRepository = new SessionsRepository(storageService.sessionsStore(), null);
|
||||
subs.init(sessionsRepository);
|
||||
|
||||
// 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, this.sessionsRepository, false);
|
||||
connect_v3_1_asClient(PUBLISHER_ID);
|
||||
publishQoS2ToAs(this.m_channel, PUBLISHER_ID, NEWS_TOPIC, 1, true);
|
||||
disconnect();
|
||||
|
||||
// connect from the subscriber
|
||||
EmbeddedChannel subscriberChannel = new EmbeddedChannel();
|
||||
NettyUtils.clientID(subscriberChannel, SUBSCRIBER_ID);
|
||||
NettyUtils.cleanSession(subscriberChannel, false);
|
||||
connectAsClient(subscriberChannel, SUBSCRIBER_ID);
|
||||
|
||||
// subscribe to the topic news with granted QoS0
|
||||
subscribe(subscriberChannel, NEWS_TOPIC, MqttQoS.AT_MOST_ONCE);
|
||||
|
||||
// Verify the retained message arrives with QoS0 instead of QoS2
|
||||
verifyPublishIsReceived(subscriberChannel, HELLO_WORLD_MQTT, MqttQoS.AT_MOST_ONCE);
|
||||
}
|
||||
// Moved to PostOfficePublishTest
|
||||
// @Test
|
||||
// public void publishNoPublishToInactiveSession() {
|
||||
// // create an inactive session for Subscriber
|
||||
// ISubscriptionsDirectory mockedSubscriptions = mock(ISubscriptionsDirectory.class);
|
||||
// Subscription inactiveSub = new Subscription("Subscriber", new Topic("/topic"), MqttQoS.AT_LEAST_ONCE);
|
||||
// List<Subscription> inactiveSubscriptions = Collections.singletonList(inactiveSub);
|
||||
// when(mockedSubscriptions.matches(eq(new Topic("/topic")))).thenReturn(inactiveSubscriptions);
|
||||
// m_processor = new ProtocolProcessor();
|
||||
// m_processor.init(mockedSubscriptions, m_messagesStore, m_sessionStore, null, true, new PermitAllAuthorizatorPolicy(),
|
||||
// NO_OBSERVERS_INTERCEPTOR, this.sessionsRepository, false);
|
||||
//
|
||||
// m_processor.sessionsRepository.createNewSession("Subscriber", false);
|
||||
//
|
||||
// // Exercise
|
||||
// connectAsClient("Publisher");
|
||||
// publishToAs("Publisher", "/topic", AT_MOST_ONCE, true);
|
||||
//
|
||||
// verifyNoPublishIsReceived();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Verify that receiving a publish with retained message and with Q0S = 0 clean the existing
|
||||
// * retained messages for that topic.
|
||||
// */
|
||||
// @Test
|
||||
// public void testCleanRetainedStoreAfterAQoS0AndRetainedTrue() {
|
||||
// // force a connect
|
||||
// connect_v3_1_asClient("Publisher");
|
||||
//
|
||||
// // prepare and existing retained store
|
||||
// publishToAs("Publisher", NEWS_TOPIC, AT_LEAST_ONCE, 100, true);
|
||||
//
|
||||
// Collection<IMessagesStore.StoredMessage> messages = m_messagesStore
|
||||
// .searchMatching(key -> key.match(new Topic(NEWS_TOPIC)));
|
||||
// assertFalse(messages.isEmpty());
|
||||
//
|
||||
// // Exercise
|
||||
// // send a message that clean the previous retained publish
|
||||
// publishToAs("Publisher", NEWS_TOPIC, AT_MOST_ONCE, true);
|
||||
//
|
||||
// // Verify
|
||||
// messages = m_messagesStore.searchMatching(key -> key.match(new Topic(NEWS_TOPIC)));
|
||||
// assertTrue(messages.isEmpty());
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testLowerTheQosToTheRequestedBySubscription() {
|
||||
// Subscription subQos1 = new Subscription("Sub A", new Topic("a/b"), MqttQoS.AT_LEAST_ONCE);
|
||||
// assertEquals(MqttQoS.AT_LEAST_ONCE, lowerQosToTheSubscriptionDesired(subQos1, EXACTLY_ONCE));
|
||||
//
|
||||
// Subscription subQos2 = new Subscription("Sub B", new Topic("a/+"), EXACTLY_ONCE);
|
||||
// assertEquals(EXACTLY_ONCE, lowerQosToTheSubscriptionDesired(subQos2, EXACTLY_ONCE));
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testSubscribeReceivePublishedMessageAtSubscriberQoSAndNotPublisherQoS() {
|
||||
// ISubscriptionsDirectory subs = new CTrieSubscriptionDirectory();
|
||||
// MemoryStorageService storageService = new MemoryStorageService(null, null);
|
||||
// SessionsRepository sessionsRepository = new SessionsRepository(storageService.sessionsStore(), null);
|
||||
// subs.init(sessionsRepository);
|
||||
//
|
||||
// // simulate a connect that register a clientID to an IoSession
|
||||
// m_processor.init(subs, m_messagesStore, m_sessionStore, null, true, new PermitAllAuthorizatorPolicy(),
|
||||
// NO_OBSERVERS_INTERCEPTOR, this.sessionsRepository, false);
|
||||
// connect_v3_1_asClient(PUBLISHER_ID);
|
||||
// publishQoS2ToAs(this.m_channel, PUBLISHER_ID, NEWS_TOPIC, 1, true);
|
||||
// disconnect();
|
||||
//
|
||||
// // connect from the subscriber
|
||||
// EmbeddedChannel subscriberChannel = new EmbeddedChannel();
|
||||
// NettyUtils.clientID(subscriberChannel, SUBSCRIBER_ID);
|
||||
// NettyUtils.cleanSession(subscriberChannel, false);
|
||||
// connectAsClient(subscriberChannel, SUBSCRIBER_ID);
|
||||
//
|
||||
// // subscribe to the topic news with granted QoS0
|
||||
// subscribe(subscriberChannel, NEWS_TOPIC, MqttQoS.AT_MOST_ONCE);
|
||||
//
|
||||
// // Verify the retained message arrives with QoS0 instead of QoS2
|
||||
// verifyPublishIsReceived(subscriberChannel, HELLO_WORLD_MQTT, MqttQoS.AT_MOST_ONCE);
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import io.moquette.persistence.MemoryStorageService;
|
||||
import io.moquette.server.netty.NettyUtils;
|
||||
import io.moquette.spi.IMessagesStore;
|
||||
import io.moquette.spi.ISessionsStore;
|
||||
import io.moquette.spi.impl.security.PermitAllAuthorizator;
|
||||
import io.moquette.spi.impl.security.PermitAllAuthorizatorPolicy;
|
||||
import io.moquette.spi.impl.subscriptions.CTrieSubscriptionDirectory;
|
||||
import io.moquette.spi.impl.subscriptions.ISubscriptionsDirectory;
|
||||
import io.moquette.spi.impl.subscriptions.Subscription;
|
||||
@@ -60,7 +60,7 @@ public class ProtocolProcessor_CONNECT_Test {
|
||||
subscriptions.init(sessionsRepository);
|
||||
processor = new ProtocolProcessor();
|
||||
processor.init(subscriptions, m_messagesStore, sessionStore, mockAuthenticator, true,
|
||||
new PermitAllAuthorizator(), NO_OBSERVERS_INTERCEPTOR,
|
||||
new PermitAllAuthorizatorPolicy(), NO_OBSERVERS_INTERCEPTOR,
|
||||
new SessionsRepository(this.sessionStore, null), false);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
package io.moquette.spi.impl;
|
||||
|
||||
import io.moquette.server.netty.NettyUtils;
|
||||
import io.moquette.spi.impl.security.PermitAllAuthorizator;
|
||||
import io.moquette.spi.impl.subscriptions.Topic;
|
||||
import io.moquette.spi.security.IAuthorizator;
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.handler.codec.mqtt.MqttQoS;
|
||||
import org.junit.Before;
|
||||
|
||||
+328
-326
@@ -31,331 +31,333 @@ public class ProtocolProcessor_VariousUseCases_Test extends AbstractProtocolProc
|
||||
initializeProcessorAndSubsystems();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCleanSession_maintainClientSubscriptions() {
|
||||
connectAsClient(this.m_channel, "TestClient");
|
||||
subscribe("/topic", AT_MOST_ONCE);
|
||||
disconnect();
|
||||
|
||||
// reconnect and publish
|
||||
EmbeddedChannel anotherChannel = new EmbeddedChannel();
|
||||
connectAsClient(anotherChannel, "TestClient");
|
||||
|
||||
publishToAs(anotherChannel, "TestClient", "/topic", AT_MOST_ONCE, false);
|
||||
|
||||
verifyPublishIsReceived(anotherChannel);
|
||||
}
|
||||
|
||||
@Ignore("At the end it's equal to testCleanSession_maintainClientSubscriptions")
|
||||
@Test
|
||||
public void testCleanSession_maintainClientSubscriptions_againstClientDestruction() {
|
||||
connectAsClient("TestClient");
|
||||
subscribe("/topic", AT_MOST_ONCE);
|
||||
disconnect();
|
||||
|
||||
this.m_channel = new EmbeddedChannel();
|
||||
// reconnect and publish
|
||||
connectAsClient("TestClient");
|
||||
|
||||
publishToAs("TestClient", "/topic", AT_MOST_ONCE, false);
|
||||
|
||||
verifyPublishIsReceived();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that after a client has connected with clean session false, subscribed to some topic
|
||||
* and exited, if it reconnects with clean session true, the broker correctly cleanup every
|
||||
* previous subscription
|
||||
*/
|
||||
@Test
|
||||
public void testCleanSession_correctlyClientSubscriptions() {
|
||||
connectAsClient("TestClient");
|
||||
subscribe("/topic", AT_MOST_ONCE);
|
||||
disconnect();
|
||||
|
||||
this.m_channel = new EmbeddedChannel();
|
||||
// reconnect and publish
|
||||
connectWithCleanSession("TestClient");
|
||||
|
||||
publishToAs("TestClient", "/topic", AT_MOST_ONCE, false);
|
||||
|
||||
verifyNoPublishIsReceived();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetain_maintainMessage_againstClientDestruction() {
|
||||
connect();
|
||||
publishToAs(FAKE_CLIENT_ID, "/topic", AT_LEAST_ONCE, 66, true);
|
||||
disconnect();
|
||||
|
||||
// reconnect and publish
|
||||
this.m_channel = new EmbeddedChannel();
|
||||
connect();
|
||||
subscribe("/topic", AT_MOST_ONCE);
|
||||
|
||||
verifyPublishIsReceived();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribe_do_not_notify_anymore_same_session() {
|
||||
connect();
|
||||
subscribe("/topic", AT_MOST_ONCE);
|
||||
publishToAs(FAKE_CLIENT_ID, "/topic", AT_MOST_ONCE, false);
|
||||
verifyPublishIsReceived();
|
||||
|
||||
unsubscribeAndVerifyAck("/topic");
|
||||
publishToAs(FAKE_CLIENT_ID, "/topic", AT_MOST_ONCE, false);
|
||||
verifyNoPublishIsReceived();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribe_do_not_notify_anymore_new_session() {
|
||||
connect();
|
||||
subscribe("/topic", AT_MOST_ONCE);
|
||||
publishToAs(FAKE_CLIENT_ID, "/topic", AT_MOST_ONCE, false);
|
||||
verifyPublishIsReceived();
|
||||
|
||||
unsubscribeAndVerifyAck("/topic");
|
||||
disconnect();
|
||||
|
||||
this.m_channel = new EmbeddedChannel();
|
||||
connect();
|
||||
publishToAs(FAKE_CLIENT_ID, "/topic", AT_MOST_ONCE, false);
|
||||
verifyNoPublishIsReceived();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublishWithQoS1() {
|
||||
connect();
|
||||
subscribe("/topic", AT_LEAST_ONCE);
|
||||
publishToAs(FAKE_CLIENT_ID, "/topic", AT_LEAST_ONCE, 66, false);
|
||||
disconnect();
|
||||
|
||||
verifyPublishIsReceived(AT_LEAST_ONCE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublishWithQoS1_notCleanSession() {
|
||||
connect();
|
||||
subscribe("/topic", AT_LEAST_ONCE);
|
||||
disconnect();
|
||||
|
||||
// publish a QoS 1 message another client publish a message on the topic
|
||||
publishFromAnotherClient("/topic", AT_LEAST_ONCE);
|
||||
|
||||
this.m_channel = new EmbeddedChannel();
|
||||
connect();
|
||||
verifyPublishIsReceived();
|
||||
}
|
||||
|
||||
private void publishFromAnotherClient(String topic, MqttQoS qos) {
|
||||
EmbeddedChannel anotherChannel = new EmbeddedChannel();
|
||||
connectAsClient(anotherChannel, "AnotherClient");
|
||||
publishToAs(anotherChannel, "AnotherClient", topic, qos, 67, false);
|
||||
disconnect(anotherChannel);
|
||||
}
|
||||
|
||||
private void publishFromAnotherClient(String topic, String payload, MqttQoS qos) {
|
||||
EmbeddedChannel anotherChannel = new EmbeddedChannel();
|
||||
connectAsClient(anotherChannel, "AnotherClient");
|
||||
publishToAs(anotherChannel, "AnotherClient", topic, payload, qos, 68, false);
|
||||
disconnect(anotherChannel);
|
||||
}
|
||||
|
||||
private void publishQoS2FromAnotherClient(String topic) {
|
||||
EmbeddedChannel anotherChannel = new EmbeddedChannel();
|
||||
connectAsClient(anotherChannel, "AnotherClient");
|
||||
publishQoS2ToAs(anotherChannel, "AnotherClient", topic, 67, false);
|
||||
disconnect(anotherChannel);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkReceivePublishedMessage_after_a_reconnect_with_notCleanSession() {
|
||||
connect();
|
||||
subscribe("/topic", AT_LEAST_ONCE);
|
||||
disconnect();
|
||||
|
||||
this.m_channel = new EmbeddedChannel();
|
||||
connect();
|
||||
subscribe("/topic", AT_LEAST_ONCE);
|
||||
|
||||
// publish a QoS 1 message another client publish a message on the topic
|
||||
publishFromAnotherClient("/topic", AT_LEAST_ONCE);
|
||||
|
||||
// Verify that after a reconnection the client receive the message
|
||||
verifyPublishIsReceived();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublishWithQoS2() {
|
||||
connect();
|
||||
subscribe("/topic", EXACTLY_ONCE);
|
||||
disconnect();
|
||||
|
||||
publishQoS2FromAnotherClient("/topic");
|
||||
|
||||
this.m_channel = new EmbeddedChannel();
|
||||
connect();
|
||||
|
||||
verifyPublishIsReceived(EXACTLY_ONCE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void avoidMultipleNotificationsAfterMultipleReconnection_cleanSessionFalseQoS1() {
|
||||
connect();
|
||||
subscribe("/topic", AT_LEAST_ONCE);
|
||||
disconnect();
|
||||
|
||||
publishFromAnotherClient("/topic", "Hello MQTT 1", AT_LEAST_ONCE);
|
||||
|
||||
this.m_channel = new EmbeddedChannel();
|
||||
connect();
|
||||
verifyPublishIsReceived("Hello MQTT 1", AT_LEAST_ONCE);
|
||||
disconnect();
|
||||
|
||||
// publish other message
|
||||
publishFromAnotherClient("/topic", "Hello MQTT 2", AT_LEAST_ONCE);
|
||||
|
||||
this.m_channel = new EmbeddedChannel();
|
||||
connect();
|
||||
verifyPublishIsReceived("Hello MQTT 2", AT_LEAST_ONCE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectSubPub_cycle_getTimeout_on_second_disconnect_issue142() {
|
||||
connect();
|
||||
subscribe("/topic", AT_MOST_ONCE);
|
||||
publishToAs(FAKE_CLIENT_ID, "/topic", AT_MOST_ONCE, true);
|
||||
disconnect();
|
||||
|
||||
// second loop
|
||||
this.m_channel = new EmbeddedChannel();
|
||||
connect();
|
||||
subscribe("/topic", AT_MOST_ONCE);
|
||||
publishToAs(FAKE_CLIENT_ID, "/topic", AT_MOST_ONCE, true);
|
||||
disconnect();
|
||||
|
||||
assertFalse("after a disconnect the client should be disconnected", this.m_channel.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkReplayofStoredPublishResumeAfter_a_disconnect_cleanSessionFalseQoS1() {
|
||||
EmbeddedChannel publisher = new EmbeddedChannel();
|
||||
connectAsClient(publisher, "Publisher");
|
||||
|
||||
connect();
|
||||
subscribe("/topic", AT_LEAST_ONCE);
|
||||
|
||||
publishToAs(publisher, "Publisher", "/topic", "Hello world MQTT!!-1", AT_LEAST_ONCE, 99, false);
|
||||
verifyPublishIsReceived("Hello world MQTT!!-1", AT_LEAST_ONCE);
|
||||
disconnect();
|
||||
|
||||
publishToAs(publisher, "Publisher", "/topic", "Hello world MQTT!!-2", AT_LEAST_ONCE, 100, false);
|
||||
publishToAs(publisher, "Publisher", "/topic", "Hello world MQTT!!-3", AT_LEAST_ONCE, 101, false);
|
||||
|
||||
this.m_channel = new EmbeddedChannel();
|
||||
connect();
|
||||
verifyPublishIsReceived("Hello world MQTT!!-2", AT_LEAST_ONCE);
|
||||
verifyPublishIsReceived("Hello world MQTT!!-3", AT_LEAST_ONCE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkReplayStoredPublish_forNoCleanSession_qos1() {
|
||||
EmbeddedChannel publisher = new EmbeddedChannel();
|
||||
connectAsClient(publisher, "Publisher");
|
||||
|
||||
connect();
|
||||
subscribe("/topic", AT_LEAST_ONCE);
|
||||
disconnect();
|
||||
|
||||
publishToAs(publisher, "Publisher", "/topic", "Hello world MQTT!!-1", AT_LEAST_ONCE, 99, false);
|
||||
|
||||
this.m_channel = new EmbeddedChannel();
|
||||
connect();
|
||||
subscribeAndNotReadResponse("/topic", AT_LEAST_ONCE);
|
||||
verifyPublishIsReceived("Hello world MQTT!!-1", AT_LEAST_ONCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
connect();
|
||||
subscribe("topic", EXACTLY_ONCE);
|
||||
disconnect();
|
||||
|
||||
EmbeddedChannel publisher = new EmbeddedChannel();
|
||||
connectAsClient(publisher, "Publisher");
|
||||
publishQoS2ToAs(publisher, "Publisher", "topic", "Hello1", 101, true);
|
||||
publishQoS2ToAs(publisher, "Publisher", "topic", "Hello2", 102, true);
|
||||
disconnect(publisher);
|
||||
|
||||
this.m_channel = new EmbeddedChannel();
|
||||
connect();
|
||||
verifyPublishIsReceived("Hello1", EXACTLY_ONCE);
|
||||
verifyPublishIsReceived("Hello2", EXACTLY_ONCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
EmbeddedChannel publisher = new EmbeddedChannel();
|
||||
connectAsClient(publisher, "Publisher");
|
||||
|
||||
connect();
|
||||
subscribe("a/+", EXACTLY_ONCE);
|
||||
subscribe("a/b", AT_LEAST_ONCE);
|
||||
|
||||
// force the publisher to send
|
||||
publishToAs(publisher, "Publisher", "a/b", "Hello world MQTT!!", AT_LEAST_ONCE, 60, false);
|
||||
|
||||
verifyPublishIsReceived("Hello world MQTT!!", AT_LEAST_ONCE);
|
||||
// try to listen a second publish
|
||||
verifyNoPublishIsReceived();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForceClientDisconnection_issue116() {
|
||||
EmbeddedChannel clientXA = new EmbeddedChannel();
|
||||
connectAsClient(clientXA, "subscriber");
|
||||
subscribe(clientXA, "topic", AT_MOST_ONCE);
|
||||
|
||||
EmbeddedChannel clientXB = new EmbeddedChannel();
|
||||
connectAsClient(clientXB, "publisher");
|
||||
publishQoS2ToAs(clientXB, "publisher", "topic", "Hello", 20, false);
|
||||
|
||||
EmbeddedChannel clientYA = new EmbeddedChannel();
|
||||
connectAsClient(clientYA, "subscriber");
|
||||
subscribe(clientYA, "topic", AT_MOST_ONCE);
|
||||
|
||||
EmbeddedChannel clientYB = new EmbeddedChannel();
|
||||
connectAsClient(clientYB, "publisher");
|
||||
publishQoS2ToAs(clientYB, "publisher", "topic", "Hello 2", 20, true);
|
||||
|
||||
assertFalse("First 'subscriber' channel MUST be closed by the broker", clientXA.isOpen());
|
||||
verifyPublishIsReceived(clientYA, "Hello 2", AT_MOST_ONCE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublishToEmptyTopic() {
|
||||
EmbeddedChannel subscriber = new EmbeddedChannel();
|
||||
connectAsClient(subscriber, "Subscriber");
|
||||
|
||||
subscribe(subscriber, "#", AT_LEAST_ONCE);
|
||||
|
||||
// Exercise
|
||||
connect();
|
||||
publishToAs(FAKE_CLIENT_ID, "", AT_LEAST_ONCE, 1, false);
|
||||
|
||||
// Verify
|
||||
verifyNoPublishIsReceived(subscriber);
|
||||
assertFalse("On empty topic subscription the channel MUST be closed", m_channel.isOpen());
|
||||
}
|
||||
// @Test
|
||||
// public void testCleanSession_maintainClientSubscriptions() {
|
||||
// connectAsClient(this.m_channel, "TestClient");
|
||||
// subscribe("/topic", AT_MOST_ONCE);
|
||||
// disconnect();
|
||||
//
|
||||
// // reconnect and publish
|
||||
// EmbeddedChannel anotherChannel = new EmbeddedChannel();
|
||||
// connectAsClient(anotherChannel, "TestClient");
|
||||
//
|
||||
// publishToAs(anotherChannel, "TestClient", "/topic", AT_MOST_ONCE, false);
|
||||
//
|
||||
// verifyPublishIsReceived(anotherChannel);
|
||||
// }
|
||||
//
|
||||
// @Ignore("At the end it's equal to testCleanSession_maintainClientSubscriptions")
|
||||
// @Test
|
||||
// public void testCleanSession_maintainClientSubscriptions_againstClientDestruction() {
|
||||
// connectAsClient("TestClient");
|
||||
// subscribe("/topic", AT_MOST_ONCE);
|
||||
// disconnect();
|
||||
//
|
||||
// this.m_channel = new EmbeddedChannel();
|
||||
// // reconnect and publish
|
||||
// connectAsClient("TestClient");
|
||||
//
|
||||
// publishToAs("TestClient", "/topic", AT_MOST_ONCE, false);
|
||||
//
|
||||
// verifyPublishIsReceived();
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Check that after a client has connected with clean session false, subscribed to some topic
|
||||
// * and exited, if it reconnects with clean session true, the broker correctly cleanup every
|
||||
// * previous subscription
|
||||
// */
|
||||
// @Test
|
||||
// public void testCleanSession_correctlyClientSubscriptions() {
|
||||
// connectAsClient("TestClient");
|
||||
// subscribe("/topic", AT_MOST_ONCE);
|
||||
// disconnect();
|
||||
//
|
||||
// this.m_channel = new EmbeddedChannel();
|
||||
// // reconnect and publish
|
||||
// connectWithCleanSession("TestClient");
|
||||
//
|
||||
// publishToAs("TestClient", "/topic", AT_MOST_ONCE, false);
|
||||
//
|
||||
// verifyNoPublishIsReceived();
|
||||
// }
|
||||
|
||||
// Duplicated, just verify retain works correctly
|
||||
// @Test
|
||||
// public void testRetain_maintainMessage_againstClientDestruction() {
|
||||
// connect();
|
||||
// publishToAs(FAKE_CLIENT_ID, "/topic", AT_LEAST_ONCE, 66, true);
|
||||
// disconnect();
|
||||
//
|
||||
// // reconnect and publish
|
||||
// this.m_channel = new EmbeddedChannel();
|
||||
// connect();
|
||||
// subscribe("/topic", AT_MOST_ONCE);
|
||||
//
|
||||
// verifyPublishIsReceived();
|
||||
// }
|
||||
|
||||
// @Test
|
||||
// public void testUnsubscribe_do_not_notify_anymore_same_session() {
|
||||
// connect();
|
||||
// subscribe("/topic", AT_MOST_ONCE);
|
||||
// publishToAs(FAKE_CLIENT_ID, "/topic", AT_MOST_ONCE, false);
|
||||
// verifyPublishIsReceived();
|
||||
//
|
||||
// unsubscribeAndVerifyAck("/topic");
|
||||
// publishToAs(FAKE_CLIENT_ID, "/topic", AT_MOST_ONCE, false);
|
||||
// verifyNoPublishIsReceived();
|
||||
// }
|
||||
|
||||
// @Test
|
||||
// public void testUnsubscribe_do_not_notify_anymore_new_session() {
|
||||
// connect();
|
||||
// subscribe("/topic", AT_MOST_ONCE);
|
||||
// publishToAs(FAKE_CLIENT_ID, "/topic", AT_MOST_ONCE, false);
|
||||
// verifyPublishIsReceived();
|
||||
//
|
||||
// unsubscribeAndVerifyAck("/topic");
|
||||
// disconnect();
|
||||
//
|
||||
// this.m_channel = new EmbeddedChannel();
|
||||
// connect();
|
||||
// publishToAs(FAKE_CLIENT_ID, "/topic", AT_MOST_ONCE, false);
|
||||
// verifyNoPublishIsReceived();
|
||||
// }
|
||||
// Moved to PostOfficePublishTest
|
||||
// @Test
|
||||
// public void testPublishWithQoS1() {
|
||||
// connect();
|
||||
// subscribe("/topic", AT_LEAST_ONCE);
|
||||
// publishToAs(FAKE_CLIENT_ID, "/topic", AT_LEAST_ONCE, 66, false);
|
||||
// disconnect();
|
||||
//
|
||||
// verifyPublishIsReceived(AT_LEAST_ONCE);
|
||||
// }
|
||||
|
||||
// Moved to PostOfficePublishTest.forwardQoS1PublishesWhenNotCleanSessionReconnects
|
||||
// @Test
|
||||
// public void testPublishWithQoS1_notCleanSession() {
|
||||
// connect();
|
||||
// subscribe("/topic", AT_LEAST_ONCE);
|
||||
// disconnect();
|
||||
//
|
||||
// // publish a QoS 1 message another client publish a message on the topic
|
||||
// publishFromAnotherClient("/topic", AT_LEAST_ONCE);
|
||||
//
|
||||
// this.m_channel = new EmbeddedChannel();
|
||||
// connect();
|
||||
// verifyPublishIsReceived();
|
||||
// }
|
||||
|
||||
// private void publishFromAnotherClient(String topic, MqttQoS qos) {
|
||||
// EmbeddedChannel anotherChannel = new EmbeddedChannel();
|
||||
// connectAsClient(anotherChannel, "AnotherClient");
|
||||
// publishToAs(anotherChannel, "AnotherClient", topic, qos, 67, false);
|
||||
// disconnect(anotherChannel);
|
||||
// }
|
||||
|
||||
// private void publishFromAnotherClient(String topic, String payload, MqttQoS qos) {
|
||||
// EmbeddedChannel anotherChannel = new EmbeddedChannel();
|
||||
// connectAsClient(anotherChannel, "AnotherClient");
|
||||
// publishToAs(anotherChannel, "AnotherClient", topic, payload, qos, 68, false);
|
||||
// disconnect(anotherChannel);
|
||||
// }
|
||||
|
||||
// private void publishQoS2FromAnotherClient(String topic) {
|
||||
// EmbeddedChannel anotherChannel = new EmbeddedChannel();
|
||||
// connectAsClient(anotherChannel, "AnotherClient");
|
||||
// publishQoS2ToAs(anotherChannel, "AnotherClient", topic, 67, false);
|
||||
// disconnect(anotherChannel);
|
||||
// }
|
||||
|
||||
// @Test
|
||||
// public void checkReceivePublishedMessage_after_a_reconnect_with_notCleanSession() {
|
||||
// connect();
|
||||
// subscribe("/topic", AT_LEAST_ONCE);
|
||||
// disconnect();
|
||||
//
|
||||
// this.m_channel = new EmbeddedChannel();
|
||||
// connect();
|
||||
// subscribe("/topic", AT_LEAST_ONCE);
|
||||
//
|
||||
// // publish a QoS 1 message another client publish a message on the topic
|
||||
// publishFromAnotherClient("/topic", AT_LEAST_ONCE);
|
||||
//
|
||||
// // Verify that after a reconnection the client receive the message
|
||||
// verifyPublishIsReceived();
|
||||
// }
|
||||
|
||||
// @Test
|
||||
// public void testPublishWithQoS2() {
|
||||
// connect();
|
||||
// subscribe("/topic", EXACTLY_ONCE);
|
||||
// disconnect();
|
||||
//
|
||||
// publishQoS2FromAnotherClient("/topic");
|
||||
//
|
||||
// this.m_channel = new EmbeddedChannel();
|
||||
// connect();
|
||||
//
|
||||
// verifyPublishIsReceived(EXACTLY_ONCE);
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void avoidMultipleNotificationsAfterMultipleReconnection_cleanSessionFalseQoS1() {
|
||||
// connect();
|
||||
// subscribe("/topic", AT_LEAST_ONCE);
|
||||
// disconnect();
|
||||
//
|
||||
// publishFromAnotherClient("/topic", "Hello MQTT 1", AT_LEAST_ONCE);
|
||||
//
|
||||
// this.m_channel = new EmbeddedChannel();
|
||||
// connect();
|
||||
// verifyPublishIsReceived("Hello MQTT 1", AT_LEAST_ONCE);
|
||||
// disconnect();
|
||||
//
|
||||
// // publish other message
|
||||
// publishFromAnotherClient("/topic", "Hello MQTT 2", AT_LEAST_ONCE);
|
||||
//
|
||||
// this.m_channel = new EmbeddedChannel();
|
||||
// connect();
|
||||
// verifyPublishIsReceived("Hello MQTT 2", AT_LEAST_ONCE);
|
||||
// }
|
||||
|
||||
// @Test
|
||||
// public void testConnectSubPub_cycle_getTimeout_on_second_disconnect_issue142() {
|
||||
// connect();
|
||||
// subscribe("/topic", AT_MOST_ONCE);
|
||||
// publishToAs(FAKE_CLIENT_ID, "/topic", AT_MOST_ONCE, true);
|
||||
// disconnect();
|
||||
//
|
||||
// // second loop
|
||||
// this.m_channel = new EmbeddedChannel();
|
||||
// connect();
|
||||
// subscribe("/topic", AT_MOST_ONCE);
|
||||
// publishToAs(FAKE_CLIENT_ID, "/topic", AT_MOST_ONCE, true);
|
||||
// disconnect();
|
||||
//
|
||||
// assertFalse("after a disconnect the client should be disconnected", this.m_channel.isOpen());
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void checkReplayofStoredPublishResumeAfter_a_disconnect_cleanSessionFalseQoS1() {
|
||||
// EmbeddedChannel publisher = new EmbeddedChannel();
|
||||
// connectAsClient(publisher, "Publisher");
|
||||
//
|
||||
// connect();
|
||||
// subscribe("/topic", AT_LEAST_ONCE);
|
||||
//
|
||||
// publishToAs(publisher, "Publisher", "/topic", "Hello world MQTT!!-1", AT_LEAST_ONCE, 99, false);
|
||||
// verifyPublishIsReceived("Hello world MQTT!!-1", AT_LEAST_ONCE);
|
||||
// disconnect();
|
||||
//
|
||||
// publishToAs(publisher, "Publisher", "/topic", "Hello world MQTT!!-2", AT_LEAST_ONCE, 100, false);
|
||||
// publishToAs(publisher, "Publisher", "/topic", "Hello world MQTT!!-3", AT_LEAST_ONCE, 101, false);
|
||||
//
|
||||
// this.m_channel = new EmbeddedChannel();
|
||||
// connect();
|
||||
// verifyPublishIsReceived("Hello world MQTT!!-2", AT_LEAST_ONCE);
|
||||
// verifyPublishIsReceived("Hello world MQTT!!-3", AT_LEAST_ONCE);
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void checkReplayStoredPublish_forNoCleanSession_qos1() {
|
||||
// EmbeddedChannel publisher = new EmbeddedChannel();
|
||||
// connectAsClient(publisher, "Publisher");
|
||||
//
|
||||
// connect();
|
||||
// subscribe("/topic", AT_LEAST_ONCE);
|
||||
// disconnect();
|
||||
//
|
||||
// publishToAs(publisher, "Publisher", "/topic", "Hello world MQTT!!-1", AT_LEAST_ONCE, 99, false);
|
||||
//
|
||||
// this.m_channel = new EmbeddedChannel();
|
||||
// connect();
|
||||
// subscribeAndNotReadResponse("/topic", AT_LEAST_ONCE);
|
||||
// verifyPublishIsReceived("Hello world MQTT!!-1", AT_LEAST_ONCE);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 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() {
|
||||
// connect();
|
||||
// subscribe("topic", EXACTLY_ONCE);
|
||||
// disconnect();
|
||||
//
|
||||
// EmbeddedChannel publisher = new EmbeddedChannel();
|
||||
// connectAsClient(publisher, "Publisher");
|
||||
// publishQoS2ToAs(publisher, "Publisher", "topic", "Hello1", 101, true);
|
||||
// publishQoS2ToAs(publisher, "Publisher", "topic", "Hello2", 102, true);
|
||||
// disconnect(publisher);
|
||||
//
|
||||
// this.m_channel = new EmbeddedChannel();
|
||||
// connect();
|
||||
// verifyPublishIsReceived("Hello1", EXACTLY_ONCE);
|
||||
// verifyPublishIsReceived("Hello2", EXACTLY_ONCE);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 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() {
|
||||
// EmbeddedChannel publisher = new EmbeddedChannel();
|
||||
// connectAsClient(publisher, "Publisher");
|
||||
//
|
||||
// connect();
|
||||
// subscribe("a/+", EXACTLY_ONCE);
|
||||
// subscribe("a/b", AT_LEAST_ONCE);
|
||||
//
|
||||
// // force the publisher to send
|
||||
// publishToAs(publisher, "Publisher", "a/b", "Hello world MQTT!!", AT_LEAST_ONCE, 60, false);
|
||||
//
|
||||
// verifyPublishIsReceived("Hello world MQTT!!", AT_LEAST_ONCE);
|
||||
// // try to listen a second publish
|
||||
// verifyNoPublishIsReceived();
|
||||
// }
|
||||
|
||||
// @Test
|
||||
// public void testForceClientDisconnection_issue116() {
|
||||
// EmbeddedChannel clientXA = new EmbeddedChannel();
|
||||
// connectAsClient(clientXA, "subscriber");
|
||||
// subscribe(clientXA, "topic", AT_MOST_ONCE);
|
||||
//
|
||||
// EmbeddedChannel clientXB = new EmbeddedChannel();
|
||||
// connectAsClient(clientXB, "publisher");
|
||||
// publishQoS2ToAs(clientXB, "publisher", "topic", "Hello", 20, false);
|
||||
//
|
||||
// EmbeddedChannel clientYA = new EmbeddedChannel();
|
||||
// connectAsClient(clientYA, "subscriber");
|
||||
// subscribe(clientYA, "topic", AT_MOST_ONCE);
|
||||
//
|
||||
// EmbeddedChannel clientYB = new EmbeddedChannel();
|
||||
// connectAsClient(clientYB, "publisher");
|
||||
// publishQoS2ToAs(clientYB, "publisher", "topic", "Hello 2", 20, true);
|
||||
//
|
||||
// assertFalse("First 'subscriber' channel MUST be closed by the broker", clientXA.isOpen());
|
||||
// verifyPublishIsReceived(clientYA, "Hello 2", AT_MOST_ONCE);
|
||||
// }
|
||||
|
||||
// @Test
|
||||
// public void testPublishToEmptyTopic() {
|
||||
// EmbeddedChannel subscriber = new EmbeddedChannel();
|
||||
// connectAsClient(subscriber, "Subscriber");
|
||||
//
|
||||
// subscribe(subscriber, "#", AT_LEAST_ONCE);
|
||||
//
|
||||
// // Exercise
|
||||
// connect();
|
||||
// publishToAs(FAKE_CLIENT_ID, "", AT_LEAST_ONCE, 1, false);
|
||||
//
|
||||
// // Verify
|
||||
// verifyNoPublishIsReceived(subscriber);
|
||||
// assertFalse("On empty topic subscription the channel MUST be closed", m_channel.isOpen());
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user