Dropper Hazelcast because Moquette is not designed to be clusterizable
Separated the connect/disconnect logic into ConnectHandler/DisconnectHandler Moved the sending of CONN ACK after session creation/update Moved the will message management inside the session class
This commit is contained in:
@@ -0,0 +1,315 @@
|
||||
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());
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,6 @@ package io.moquette.spi.impl;
|
||||
|
||||
import io.moquette.persistence.MemoryStorageService;
|
||||
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;
|
||||
@@ -34,7 +33,7 @@ import org.junit.Test;
|
||||
import static io.moquette.spi.impl.NettyChannelAssertions.assertEqualsConnAck;
|
||||
import static io.moquette.spi.impl.NettyChannelAssertions.assertEqualsSubAck;
|
||||
import static io.moquette.spi.impl.ProtocolProcessorTest.*;
|
||||
import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.*;
|
||||
import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_ACCEPTED;
|
||||
import static java.util.Collections.singleton;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
@@ -42,322 +41,61 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ProtocolProcessor_CONNECT_Test {
|
||||
|
||||
EmbeddedChannel m_session;
|
||||
MqttMessageBuilders.ConnectBuilder connMsg;
|
||||
ProtocolProcessor m_processor;
|
||||
|
||||
IMessagesStore m_messagesStore;
|
||||
ISessionsStore m_sessionStore;
|
||||
ISubscriptionsDirectory subscriptions;
|
||||
MockAuthenticator m_mockAuthenticator;
|
||||
private EmbeddedChannel session;
|
||||
private ProtocolProcessor processor;
|
||||
private ISessionsStore sessionStore;
|
||||
|
||||
@Before
|
||||
public void setUp() throws InterruptedException {
|
||||
connMsg = MqttMessageBuilders.connect().protocolVersion(MqttVersion.MQTT_3_1).cleanSession(true);
|
||||
|
||||
m_session = new EmbeddedChannel();
|
||||
public void setUp() {
|
||||
session = new EmbeddedChannel();
|
||||
|
||||
MemoryStorageService memStorage = new MemoryStorageService(null, null);
|
||||
m_messagesStore = memStorage.messagesStore();
|
||||
m_sessionStore = memStorage.sessionsStore();
|
||||
// m_messagesStore.initStore();
|
||||
IMessagesStore m_messagesStore = memStorage.messagesStore();
|
||||
sessionStore = memStorage.sessionsStore();
|
||||
|
||||
m_mockAuthenticator = new MockAuthenticator(singleton(FAKE_CLIENT_ID), singletonMap(TEST_USER, TEST_PWD));
|
||||
MockAuthenticator mockAuthenticator = new MockAuthenticator(singleton(FAKE_CLIENT_ID), singletonMap(TEST_USER, TEST_PWD));
|
||||
|
||||
subscriptions = new CTrieSubscriptionDirectory();
|
||||
SessionsRepository sessionsRepository = new SessionsRepository(m_sessionStore, null);
|
||||
ISubscriptionsDirectory subscriptions = new CTrieSubscriptionDirectory();
|
||||
SessionsRepository sessionsRepository = new SessionsRepository(sessionStore, null);
|
||||
subscriptions.init(sessionsRepository);
|
||||
m_processor = new ProtocolProcessor();
|
||||
m_processor.init(subscriptions, m_messagesStore, m_sessionStore, m_mockAuthenticator, true,
|
||||
processor = new ProtocolProcessor();
|
||||
processor.init(subscriptions, m_messagesStore, sessionStore, mockAuthenticator, true,
|
||||
new PermitAllAuthorizator(), NO_OBSERVERS_INTERCEPTOR,
|
||||
new SessionsRepository(this.m_sessionStore, null), false);
|
||||
new SessionsRepository(this.sessionStore, null), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnect_badClientID() {
|
||||
connMsg.clientId("extremely_long_clientID_greater_than_23").build();
|
||||
|
||||
// Exercise
|
||||
m_processor.processConnect(m_session, connMsg.clientId("extremely_long_clientID_greater_than_23").build());
|
||||
|
||||
// Verify
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, m_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);
|
||||
m_processor.processConnect(m_session, msg);
|
||||
|
||||
// Verify
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, m_session.readOutbound());
|
||||
assertTrue("Connection is accepted and therefore should remain open.", m_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 validAuthentication() {
|
||||
MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID)
|
||||
.username(TEST_USER).password(TEST_PWD).build();
|
||||
|
||||
// Exercise
|
||||
m_processor.processConnect(m_session, msg);
|
||||
|
||||
// Verify
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, m_session.readOutbound());
|
||||
assertTrue("Connection is accepted and therefore should remain open.", m_session.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noPasswdAuthentication() {
|
||||
MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID)
|
||||
.username(TEST_USER)
|
||||
.build();
|
||||
|
||||
// Exercise
|
||||
m_processor.processConnect(m_session, msg);
|
||||
|
||||
// Verify
|
||||
assertEqualsConnAck(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD, m_session.readOutbound());
|
||||
assertFalse("Connection should be closed by the broker.", m_session.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidAuthentication() {
|
||||
MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID)
|
||||
.username(TEST_USER + "_fake")
|
||||
.password(TEST_PWD)
|
||||
.build();
|
||||
|
||||
// Exercise
|
||||
m_processor.processConnect(m_session, msg);
|
||||
|
||||
// Verify
|
||||
assertEqualsConnAck(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD, m_session.readOutbound());
|
||||
assertFalse("Connection should be closed by the broker.", m_session.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void prohibitAnonymousClient() {
|
||||
MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID).build();
|
||||
reinitProcessorProhibitingAnonymousClients();
|
||||
|
||||
// Exercise
|
||||
m_processor.processConnect(m_session, msg);
|
||||
|
||||
// Verify
|
||||
assertEqualsConnAck(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD, m_session.readOutbound());
|
||||
assertFalse("Connection should be closed by the broker.", m_session.isOpen());
|
||||
}
|
||||
|
||||
protected void reinitProcessorProhibitingAnonymousClients() {
|
||||
m_processor.init(subscriptions, m_messagesStore, m_sessionStore, m_mockAuthenticator, false,
|
||||
new PermitAllAuthorizator(), NO_OBSERVERS_INTERCEPTOR, new SessionsRepository(this.m_sessionStore, null), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void prohibitAnonymousClient_providingUsername() {
|
||||
MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID)
|
||||
.username(TEST_USER + "_fake")
|
||||
.build();
|
||||
reinitProcessorProhibitingAnonymousClients();
|
||||
|
||||
// Exercise
|
||||
m_processor.processConnect(m_session, msg);
|
||||
|
||||
// Verify
|
||||
assertEqualsConnAck(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD, m_session.readOutbound());
|
||||
assertFalse("Connection should be closed by the broker.", m_session.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void acceptAnonymousClient() {
|
||||
MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID).build();
|
||||
|
||||
// Exercise
|
||||
m_processor.processConnect(m_session, msg);
|
||||
|
||||
// Verify
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, m_session.readOutbound());
|
||||
assertTrue("Connection is accepted and therefore should remain open.", m_session.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectWithCleanSessionUpdateClientSession() throws InterruptedException {
|
||||
// first connect with clean session true
|
||||
MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID).cleanSession(true).build();
|
||||
m_processor.processConnect(m_session, msg);
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, m_session.readOutbound());
|
||||
m_processor.processDisconnect(m_session);
|
||||
assertFalse(m_session.isOpen());
|
||||
|
||||
// second connect with clean session false
|
||||
m_session = new EmbeddedChannel();
|
||||
MqttConnectMessage secondConnMsg = MqttMessageBuilders.connect().clientId(FAKE_CLIENT_ID)
|
||||
.protocolVersion(MqttVersion.MQTT_3_1).build();
|
||||
|
||||
m_processor.processConnect(m_session, secondConnMsg);
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, m_session.readOutbound());
|
||||
|
||||
// Verify client session is clean false
|
||||
ClientSession session = m_processor.sessionsRepository.sessionForClient(FAKE_CLIENT_ID);
|
||||
assertFalse(session.isCleanSession());
|
||||
|
||||
// Verify
|
||||
// assertEqualsConnAck(CONNECTION_ACCEPTED, m_session.readOutbound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectWithSameClientIDBadCredentialsDoesntDropExistingClient() {
|
||||
// Connect a client1
|
||||
MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID)
|
||||
.username(TEST_USER)
|
||||
.password(TEST_PWD)
|
||||
.build();
|
||||
m_processor.processConnect(m_session, msg);
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, m_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
|
||||
m_processor.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(m_session.isOpen());
|
||||
assertFalse(evilSession.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnAckContainsSessionPresentFlag() throws InterruptedException {
|
||||
MqttConnectMessage msg = connMsg.clientId(FAKE_CLIENT_ID)
|
||||
.protocolVersion(MqttVersion.MQTT_3_1_1).build();
|
||||
NettyUtils.clientID(m_session, FAKE_CLIENT_ID);
|
||||
NettyUtils.cleanSession(m_session, false);
|
||||
|
||||
// Connect a first time
|
||||
m_processor.processConnect(m_session, msg);
|
||||
// disconnect
|
||||
m_processor.processDisconnect(m_session);
|
||||
|
||||
// Exercise, reconnect
|
||||
EmbeddedChannel firstReceiverSession = new EmbeddedChannel();
|
||||
m_processor.processConnect(firstReceiverSession, msg);
|
||||
|
||||
// Verify
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, firstReceiverSession.readOutbound());
|
||||
assertTrue("Connection is accepted and therefore should remain open.", firstReceiverSession.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleReconnection() throws InterruptedException {
|
||||
public void testMultipleReconnection() {
|
||||
// connect with clean a false and subscribe to a topic
|
||||
MqttConnectMessage msg = MqttMessageBuilders.connect().clientId(FAKE_CLIENT_ID)
|
||||
.protocolVersion(MqttVersion.MQTT_3_1_1).build();
|
||||
m_processor.processConnect(m_session, msg);
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, m_session.readOutbound());
|
||||
assertTrue("Connection is accepted and therefore should remain open.", m_session.isOpen());
|
||||
processor.processConnect(session, msg);
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, session.readOutbound());
|
||||
assertTrue("Connection is accepted and therefore should remain open.", session.isOpen());
|
||||
|
||||
// subscribe
|
||||
MqttSubscribeMessage subscribeMsg = MqttMessageBuilders.subscribe()
|
||||
.addSubscription(MqttQoS.AT_MOST_ONCE, ProtocolProcessorTest.NEWS_TOPIC).messageId(10).build();
|
||||
|
||||
NettyUtils.clientID(m_session, FAKE_CLIENT_ID);
|
||||
NettyUtils.cleanSession(m_session, false);
|
||||
m_processor.processSubscribe(m_session, subscribeMsg);
|
||||
Subscription expectedSubscription = new Subscription(
|
||||
FAKE_CLIENT_ID,
|
||||
new Topic(ProtocolProcessorTest.NEWS_TOPIC),
|
||||
MqttQoS.AT_MOST_ONCE);
|
||||
verifySubscriptionExists(m_sessionStore, expectedSubscription);
|
||||
assertEqualsSubAck(m_session.readOutbound());
|
||||
NettyUtils.clientID(session, FAKE_CLIENT_ID);
|
||||
NettyUtils.cleanSession(session, false);
|
||||
processor.processSubscribe(session, subscribeMsg);
|
||||
final Topic newTopic = new Topic(ProtocolProcessorTest.NEWS_TOPIC);
|
||||
Subscription expectedSubscription = new Subscription(FAKE_CLIENT_ID, newTopic, MqttQoS.AT_MOST_ONCE);
|
||||
verifySubscriptionExists(sessionStore, expectedSubscription);
|
||||
assertEqualsSubAck(session.readOutbound());
|
||||
|
||||
// disconnect
|
||||
m_processor.processDisconnect(m_session);
|
||||
assertFalse(m_session.isOpen());
|
||||
processor.processDisconnect(session);
|
||||
assertFalse(session.isOpen());
|
||||
|
||||
// reconnect clean session a false
|
||||
m_session = new EmbeddedChannel();
|
||||
m_processor.processConnect(m_session, msg);
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, m_session.readOutbound());
|
||||
assertTrue("Connection is accepted and therefore should remain open.", m_session.isOpen());
|
||||
session = new EmbeddedChannel();
|
||||
processor.processConnect(session, msg);
|
||||
assertEqualsConnAck(CONNECTION_ACCEPTED, session.readOutbound());
|
||||
assertTrue("Connection is accepted and therefore should remain open.", session.isOpen());
|
||||
|
||||
// verify that the first subscription is still preserved
|
||||
verifySubscriptionExists(m_sessionStore, expectedSubscription);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZeroByteClientIdWithoutCleanSession() {
|
||||
// Allow zero byte client ids
|
||||
m_processor = new ProtocolProcessor();
|
||||
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();
|
||||
|
||||
m_processor.processConnect(m_session, msg);
|
||||
assertEqualsConnAck(
|
||||
"Identifier should be rejected due to having clean session set to false.",
|
||||
CONNECTION_REFUSED_IDENTIFIER_REJECTED,
|
||||
m_session.readOutbound());
|
||||
|
||||
assertFalse("Connection should be closed by the broker.", m_session.isOpen());
|
||||
}
|
||||
|
||||
protected void reinitProtocolProcessorWithZeroLengthClientIdAndAnonymousClients() {
|
||||
m_processor.init(subscriptions, m_messagesStore, m_sessionStore, m_mockAuthenticator, true, true,
|
||||
new PermitAllAuthorizator(), NO_OBSERVERS_INTERCEPTOR, new SessionsRepository(this.m_sessionStore, null), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZeroByteClientIdWithCleanSession() {
|
||||
// Allow zero byte client ids
|
||||
m_processor = new ProtocolProcessor();
|
||||
reinitProtocolProcessorWithZeroLengthClientIdAndAnonymousClients();
|
||||
|
||||
// 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();
|
||||
|
||||
m_processor.processConnect(m_session, msg);
|
||||
assertEqualsConnAck("Connection MUST be accepted, unique clientid MUST be generated and clean session to true",
|
||||
CONNECTION_ACCEPTED, m_session.readOutbound());
|
||||
assertTrue("Connection should be valid and open,", m_session.isOpen());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZeroByteClientIdNotAllowed() {
|
||||
// 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();
|
||||
|
||||
m_processor.processConnect(m_session, msg);
|
||||
assertEqualsConnAck("Zero byte client identifiers are not allowed",
|
||||
CONNECTION_REFUSED_IDENTIFIER_REJECTED, m_session.readOutbound());
|
||||
|
||||
assertFalse("Connection should closed.", m_session.isOpen());
|
||||
verifySubscriptionExists(sessionStore, expectedSubscription);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-15
@@ -32,7 +32,7 @@ public class ProtocolProcessor_VariousUseCases_Test extends AbstractProtocolProc
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCleanSession_maintainClientSubscriptions() throws InterruptedException {
|
||||
public void testCleanSession_maintainClientSubscriptions() {
|
||||
connectAsClient(this.m_channel, "TestClient");
|
||||
subscribe("/topic", AT_MOST_ONCE);
|
||||
disconnect();
|
||||
@@ -48,7 +48,7 @@ public class ProtocolProcessor_VariousUseCases_Test extends AbstractProtocolProc
|
||||
|
||||
@Ignore("At the end it's equal to testCleanSession_maintainClientSubscriptions")
|
||||
@Test
|
||||
public void testCleanSession_maintainClientSubscriptions_againstClientDestruction() throws InterruptedException {
|
||||
public void testCleanSession_maintainClientSubscriptions_againstClientDestruction() {
|
||||
connectAsClient("TestClient");
|
||||
subscribe("/topic", AT_MOST_ONCE);
|
||||
disconnect();
|
||||
@@ -68,7 +68,7 @@ public class ProtocolProcessor_VariousUseCases_Test extends AbstractProtocolProc
|
||||
* previous subscription
|
||||
*/
|
||||
@Test
|
||||
public void testCleanSession_correctlyClientSubscriptions() throws InterruptedException {
|
||||
public void testCleanSession_correctlyClientSubscriptions() {
|
||||
connectAsClient("TestClient");
|
||||
subscribe("/topic", AT_MOST_ONCE);
|
||||
disconnect();
|
||||
@@ -109,7 +109,7 @@ public class ProtocolProcessor_VariousUseCases_Test extends AbstractProtocolProc
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsubscribe_do_not_notify_anymore_new_session() throws InterruptedException {
|
||||
public void testUnsubscribe_do_not_notify_anymore_new_session() {
|
||||
connect();
|
||||
subscribe("/topic", AT_MOST_ONCE);
|
||||
publishToAs(FAKE_CLIENT_ID, "/topic", AT_MOST_ONCE, false);
|
||||
@@ -125,7 +125,7 @@ public class ProtocolProcessor_VariousUseCases_Test extends AbstractProtocolProc
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublishWithQoS1() throws InterruptedException {
|
||||
public void testPublishWithQoS1() {
|
||||
connect();
|
||||
subscribe("/topic", AT_LEAST_ONCE);
|
||||
publishToAs(FAKE_CLIENT_ID, "/topic", AT_LEAST_ONCE, 66, false);
|
||||
@@ -148,21 +148,21 @@ public class ProtocolProcessor_VariousUseCases_Test extends AbstractProtocolProc
|
||||
verifyPublishIsReceived();
|
||||
}
|
||||
|
||||
protected void publishFromAnotherClient(String topic, MqttQoS qos) {
|
||||
private void publishFromAnotherClient(String topic, MqttQoS qos) {
|
||||
EmbeddedChannel anotherChannel = new EmbeddedChannel();
|
||||
connectAsClient(anotherChannel, "AnotherClient");
|
||||
publishToAs(anotherChannel, "AnotherClient", topic, qos, 67, false);
|
||||
disconnect(anotherChannel);
|
||||
}
|
||||
|
||||
protected void publishFromAnotherClient(String topic, String payload, MqttQoS qos) {
|
||||
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);
|
||||
}
|
||||
|
||||
protected void publishQoS2FromAnotherClient(String topic) {
|
||||
private void publishQoS2FromAnotherClient(String topic) {
|
||||
EmbeddedChannel anotherChannel = new EmbeddedChannel();
|
||||
connectAsClient(anotherChannel, "AnotherClient");
|
||||
publishQoS2ToAs(anotherChannel, "AnotherClient", topic, 67, false);
|
||||
@@ -187,7 +187,7 @@ public class ProtocolProcessor_VariousUseCases_Test extends AbstractProtocolProc
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublishWithQoS2() throws InterruptedException {
|
||||
public void testPublishWithQoS2() {
|
||||
connect();
|
||||
subscribe("/topic", EXACTLY_ONCE);
|
||||
disconnect();
|
||||
@@ -201,8 +201,7 @@ public class ProtocolProcessor_VariousUseCases_Test extends AbstractProtocolProc
|
||||
}
|
||||
|
||||
@Test
|
||||
public void avoidMultipleNotificationsAfterMultipleReconnection_cleanSessionFalseQoS1()
|
||||
throws InterruptedException {
|
||||
public void avoidMultipleNotificationsAfterMultipleReconnection_cleanSessionFalseQoS1() {
|
||||
connect();
|
||||
subscribe("/topic", AT_LEAST_ONCE);
|
||||
disconnect();
|
||||
@@ -223,7 +222,7 @@ public class ProtocolProcessor_VariousUseCases_Test extends AbstractProtocolProc
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectSubPub_cycle_getTimeout_on_second_disconnect_issue142() throws InterruptedException {
|
||||
public void testConnectSubPub_cycle_getTimeout_on_second_disconnect_issue142() {
|
||||
connect();
|
||||
subscribe("/topic", AT_MOST_ONCE);
|
||||
publishToAs(FAKE_CLIENT_ID, "/topic", AT_MOST_ONCE, true);
|
||||
@@ -240,7 +239,7 @@ public class ProtocolProcessor_VariousUseCases_Test extends AbstractProtocolProc
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkReplayofStoredPublishResumeAfter_a_disconnect_cleanSessionFalseQoS1() throws InterruptedException {
|
||||
public void checkReplayofStoredPublishResumeAfter_a_disconnect_cleanSessionFalseQoS1() {
|
||||
EmbeddedChannel publisher = new EmbeddedChannel();
|
||||
connectAsClient(publisher, "Publisher");
|
||||
|
||||
@@ -261,7 +260,7 @@ public class ProtocolProcessor_VariousUseCases_Test extends AbstractProtocolProc
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkReplayStoredPublish_forNoCleanSession_qos1() throws InterruptedException {
|
||||
public void checkReplayStoredPublish_forNoCleanSession_qos1() {
|
||||
EmbeddedChannel publisher = new EmbeddedChannel();
|
||||
connectAsClient(publisher, "Publisher");
|
||||
|
||||
@@ -283,7 +282,7 @@ public class ProtocolProcessor_VariousUseCases_Test extends AbstractProtocolProc
|
||||
* "hello2"
|
||||
*/
|
||||
@Test
|
||||
public void checkQoS2SubscriberDisconnectReceivePersistedPublishes() throws InterruptedException {
|
||||
public void checkQoS2SubscriberDisconnectReceivePersistedPublishes() {
|
||||
connect();
|
||||
subscribe("topic", EXACTLY_ONCE);
|
||||
disconnect();
|
||||
|
||||
Reference in New Issue
Block a user