Search in sources :

Example 1 with MqttTopicSubscription

use of io.vertx.mqtt.MqttTopicSubscription in project hono by eclipse.

the class AbstractVertxBasedMqttProtocolAdapterTest method testOnSubscribeRegistersAndClosesConnection.

private void testOnSubscribeRegistersAndClosesConnection(final MqttQoS qos) {
    // GIVEN a device connected to an adapter
    givenAnAdapter(properties);
    givenAnEventSenderForAnyTenant();
    final MqttEndpoint endpoint = mockEndpoint();
    // 10 seconds
    when(endpoint.keepAliveTimeSeconds()).thenReturn(10);
    // WHEN a device subscribes to commands
    final CommandConsumer commandConsumer = mock(CommandConsumer.class);
    when(commandConsumer.close(any())).thenReturn(Future.succeededFuture());
    when(commandConsumerFactory.createCommandConsumer(eq("tenant"), eq("deviceId"), VertxMockSupport.anyHandler(), any(), any())).thenReturn(Future.succeededFuture(commandConsumer));
    final List<MqttTopicSubscription> subscriptions = Collections.singletonList(newMockTopicSubscription(getCommandSubscriptionTopic("tenant", "deviceId"), qos));
    final MqttSubscribeMessage msg = mock(MqttSubscribeMessage.class);
    when(msg.messageId()).thenReturn(15);
    when(msg.topicSubscriptions()).thenReturn(subscriptions);
    final var mqttDeviceEndpoint = adapter.createMqttDeviceEndpoint(endpoint, null, OptionalInt.empty());
    endpoint.closeHandler(handler -> mqttDeviceEndpoint.onClose());
    mqttDeviceEndpoint.onSubscribe(msg);
    // THEN the adapter creates a command consumer that is checked periodically
    verify(commandConsumerFactory).createCommandConsumer(eq("tenant"), eq("deviceId"), VertxMockSupport.anyHandler(), any(), any());
    // and the adapter registers a hook on the connection to the device
    final ArgumentCaptor<Handler<Void>> closeHookCaptor = VertxMockSupport.argumentCaptorHandler();
    verify(endpoint).closeHandler(closeHookCaptor.capture());
    // which closes the command consumer when the device disconnects
    closeHookCaptor.getValue().handle(null);
    verify(commandConsumer).close(any());
    // and sends an empty notification downstream with TTD 0
    assertEmptyNotificationHasBeenSentDownstream("tenant", "deviceId", 0);
}
Also used : MqttSubscribeMessage(io.vertx.mqtt.messages.MqttSubscribeMessage) MqttEndpoint(io.vertx.mqtt.MqttEndpoint) MqttTopicSubscription(io.vertx.mqtt.MqttTopicSubscription) CommandConsumer(org.eclipse.hono.client.command.CommandConsumer) AuthHandler(org.eclipse.hono.adapter.auth.device.AuthHandler) Handler(io.vertx.core.Handler)

Example 2 with MqttTopicSubscription

use of io.vertx.mqtt.MqttTopicSubscription in project hono by eclipse.

the class AbstractVertxBasedMqttProtocolAdapterTest method testAdapterSkipsTtdEventOnCmdConnectionCloseIfRemoveConsumerFails.

/**
 * Verifies that the adapter doesn't send a 'disconnectedTtdEvent' on connection loss
 * when removal of the command consumer mapping entry fails (which would be the case
 * when another command consumer mapping had been registered in the mean time, meaning
 * the device has already reconnected).
 */
@Test
public void testAdapterSkipsTtdEventOnCmdConnectionCloseIfRemoveConsumerFails() {
    // GIVEN a device connected to an adapter
    givenAnAdapter(properties);
    givenAnEventSenderForAnyTenant();
    final MqttEndpoint endpoint = mockEndpoint();
    when(endpoint.isConnected()).thenReturn(true);
    // 10 seconds
    when(endpoint.keepAliveTimeSeconds()).thenReturn(10);
    // WHEN a device subscribes to commands
    final CommandConsumer commandConsumer = mock(CommandConsumer.class);
    when(commandConsumer.close(any())).thenReturn(Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_PRECON_FAILED)));
    when(commandConsumerFactory.createCommandConsumer(eq("tenant"), eq("deviceId"), VertxMockSupport.anyHandler(), any(), any())).thenReturn(Future.succeededFuture(commandConsumer));
    final List<MqttTopicSubscription> subscriptions = Collections.singletonList(newMockTopicSubscription(getCommandSubscriptionTopic("tenant", "deviceId"), MqttQoS.AT_MOST_ONCE));
    final MqttSubscribeMessage msg = mock(MqttSubscribeMessage.class);
    when(msg.messageId()).thenReturn(15);
    when(msg.topicSubscriptions()).thenReturn(subscriptions);
    final var mqttDeviceEndpoint = adapter.createMqttDeviceEndpoint(endpoint, null, OptionalInt.empty());
    endpoint.closeHandler(handler -> mqttDeviceEndpoint.onClose());
    mqttDeviceEndpoint.onSubscribe(msg);
    // THEN the adapter creates a command consumer that is checked periodically
    verify(commandConsumerFactory).createCommandConsumer(eq("tenant"), eq("deviceId"), VertxMockSupport.anyHandler(), any(), any());
    // and the adapter registers a hook on the connection to the device
    final ArgumentCaptor<Handler<Void>> closeHookCaptor = VertxMockSupport.argumentCaptorHandler();
    verify(endpoint).closeHandler(closeHookCaptor.capture());
    // which closes the command consumer when the device disconnects
    closeHookCaptor.getValue().handle(null);
    when(endpoint.isConnected()).thenReturn(false);
    verify(commandConsumer).close(any());
    // and since closing the command consumer fails with a precon-failed exception
    // there is only one notification sent during consumer creation,
    assertEmptyNotificationHasBeenSentDownstream("tenant", "deviceId", -1);
    // no 'disconnectedTtdEvent' event with TTD = 0
    assertEmptyNotificationHasNotBeenSentDownstream("tenant", "deviceId", 0);
}
Also used : MqttSubscribeMessage(io.vertx.mqtt.messages.MqttSubscribeMessage) MqttEndpoint(io.vertx.mqtt.MqttEndpoint) MqttTopicSubscription(io.vertx.mqtt.MqttTopicSubscription) CommandConsumer(org.eclipse.hono.client.command.CommandConsumer) ClientErrorException(org.eclipse.hono.client.ClientErrorException) AuthHandler(org.eclipse.hono.adapter.auth.device.AuthHandler) Handler(io.vertx.core.Handler) Test(org.junit.jupiter.api.Test)

Example 3 with MqttTopicSubscription

use of io.vertx.mqtt.MqttTopicSubscription in project hono by eclipse.

the class CommandSubscriptionTest method testSubscriptionSucceedsForAuthenticatedDevice.

/**
 * Verifies that an authenticated device can successfully subscribe for commands
 * targeted at itself using all variants of topic names.
 *
 * @param endpointName The endpoint name used in the topic.
 * @param reqPartName The request part name used in the topic.
 * @param qos The requested QoS.
 */
@ParameterizedTest
@MethodSource("endpointAndReqNamesWithQoS")
public void testSubscriptionSucceedsForAuthenticatedDevice(final String endpointName, final String reqPartName, final MqttQoS qos) {
    final Command command = mock(Command.class);
    when(command.isTargetedAtGateway()).thenReturn(false);
    when(command.getTenant()).thenReturn(device.getTenantId());
    when(command.getGatewayOrDeviceId()).thenReturn(device.getDeviceId());
    when(command.getRequestId()).thenReturn("requestId");
    when(command.getName()).thenReturn("doSomething");
    // WHEN subscribing to commands using explicit topic
    MqttTopicSubscription mqttTopicSubscription = new MqttTopicSubscriptionImpl(String.format("%s/tenant/device/%s/#", endpointName, reqPartName), qos);
    CommandSubscription subscription = CommandSubscription.fromTopic(mqttTopicSubscription, device);
    assertThat(subscription).isNotNull();
    assertThat(subscription.getTenant()).isEqualTo("tenant");
    assertThat(subscription.getDeviceId()).isEqualTo("device");
    assertThat(subscription.getEndpoint()).isEqualTo(endpointName);
    assertThat(subscription.getRequestPart()).isEqualTo(reqPartName);
    assertThat(subscription.getQos()).isEqualTo(qos);
    // THEN the command topic does include both the tenant and device ID
    assertThat(subscription.getCommandPublishTopic(command)).isEqualTo(String.format("%s/%s/%s/%s/requestId/doSomething", endpointName, device.getTenantId(), device.getDeviceId(), reqPartName));
    // WHEN subscribing to commands including tenant only
    mqttTopicSubscription = new MqttTopicSubscriptionImpl(String.format("%s/tenant//%s/#", endpointName, reqPartName), qos);
    subscription = CommandSubscription.fromTopic(mqttTopicSubscription, device);
    assertThat(subscription).isNotNull();
    assertThat(subscription.getTenant()).isEqualTo("tenant");
    assertThat(subscription.getDeviceId()).isEqualTo("device");
    assertThat(subscription.getEndpoint()).isEqualTo(endpointName);
    assertThat(subscription.getRequestPart()).isEqualTo(reqPartName);
    assertThat(subscription.getQos()).isEqualTo(qos);
    // THEN the command topic does include the tenant as well
    assertThat(subscription.getCommandPublishTopic(command)).isEqualTo(String.format("%s/%s//%s/requestId/doSomething", endpointName, device.getTenantId(), reqPartName));
    // WHEN subscribing to commands including device ID only
    mqttTopicSubscription = new MqttTopicSubscriptionImpl(String.format("%s//device/%s/#", endpointName, reqPartName), qos);
    subscription = CommandSubscription.fromTopic(mqttTopicSubscription, device);
    assertThat(subscription).isNotNull();
    assertThat(subscription.getTenant()).isEqualTo("tenant");
    assertThat(subscription.getDeviceId()).isEqualTo("device");
    assertThat(subscription.getEndpoint()).isEqualTo(endpointName);
    assertThat(subscription.getRequestPart()).isEqualTo(reqPartName);
    assertThat(subscription.getQos()).isEqualTo(qos);
    // THEN the command topic does include the device ID as well
    assertThat(subscription.getCommandPublishTopic(command)).isEqualTo(String.format("%s//%s/%s/requestId/doSomething", endpointName, device.getDeviceId(), reqPartName));
    // WHEN subscribing to commands using implicit topic
    mqttTopicSubscription = new MqttTopicSubscriptionImpl(String.format("%s///%s/#", endpointName, reqPartName), qos);
    subscription = CommandSubscription.fromTopic(mqttTopicSubscription, device);
    assertThat(subscription).isNotNull();
    assertThat(subscription.getTenant()).isEqualTo("tenant");
    assertThat(subscription.getDeviceId()).isEqualTo("device");
    assertThat(subscription.getEndpoint()).isEqualTo(endpointName);
    assertThat(subscription.getRequestPart()).isEqualTo(reqPartName);
    assertThat(subscription.getQos()).isEqualTo(qos);
    // THEN the command topic does not include tenant nor device ID
    assertThat(subscription.getCommandPublishTopic(command)).isEqualTo(String.format("%s///%s/requestId/doSomething", endpointName, reqPartName));
    // using a tenant other than the tenant that the device belongs to should fail
    mqttTopicSubscription = new MqttTopicSubscriptionImpl(String.format("%s/otherTenant/device/%s/#", endpointName, reqPartName), qos);
    assertThat(CommandSubscription.fromTopic(mqttTopicSubscription, device)).isNull();
}
Also used : MqttTopicSubscriptionImpl(io.vertx.mqtt.impl.MqttTopicSubscriptionImpl) Command(org.eclipse.hono.client.command.Command) MqttTopicSubscription(io.vertx.mqtt.MqttTopicSubscription) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) MethodSource(org.junit.jupiter.params.provider.MethodSource)

Example 4 with MqttTopicSubscription

use of io.vertx.mqtt.MqttTopicSubscription in project hono by eclipse.

the class CommandSubscriptionTest method testSubscriptionSucceedsForAuthenticatedGateway.

/**
 * Verifies that an authenticated gateway can successfully subscribe for commands
 * targeted at one of devices that it is authorized to act on behalf of.
 *
 * @param endpointName The endpoint name used in the topic.
 * @param reqPartName The request part name used in the topic.
 * @param qos The requested QoS.
 */
@ParameterizedTest
@MethodSource("endpointAndReqNamesWithQoS")
public void testSubscriptionSucceedsForAuthenticatedGateway(final String endpointName, final String reqPartName, final MqttQoS qos) {
    final String gatewayManagedDeviceId = "gatewayManagedDevice";
    final Command command = mock(Command.class);
    when(command.isTargetedAtGateway()).thenReturn(true);
    when(command.getTenant()).thenReturn(gw.getTenantId());
    when(command.getGatewayId()).thenReturn(gw.getDeviceId());
    when(command.getGatewayOrDeviceId()).thenReturn(gw.getDeviceId());
    when(command.getDeviceId()).thenReturn(gatewayManagedDeviceId);
    when(command.getRequestId()).thenReturn("requestId");
    when(command.getName()).thenReturn("doSomething");
    // WHEN subscribing to commands for a specific device omitting tenant
    MqttTopicSubscription mqttTopicSubscription = new MqttTopicSubscriptionImpl(String.format("%s//%s/%s/#", endpointName, gatewayManagedDeviceId, reqPartName), qos);
    CommandSubscription subscription = CommandSubscription.fromTopic(mqttTopicSubscription, gw);
    assertThat(subscription).isNotNull();
    assertThat(subscription.getTenant()).isEqualTo(gw.getTenantId());
    assertThat(subscription.getDeviceId()).isEqualTo(gatewayManagedDeviceId);
    assertThat(subscription.getAuthenticatedDeviceId()).isEqualTo(gw.getDeviceId());
    assertThat(subscription.getQos()).isEqualTo(qos);
    assertThat(subscription.isGatewaySubscriptionForSpecificDevice()).isEqualTo(true);
    // THEN the command topic does not include the tenant either
    assertThat(subscription.getCommandPublishTopic(command)).isEqualTo(String.format("%s//%s/%s/requestId/doSomething", endpointName, gatewayManagedDeviceId, reqPartName));
    // WHEN subscribing to commands for a specific device including the tenant
    mqttTopicSubscription = new MqttTopicSubscriptionImpl(String.format("%s/%s/%s/%s/#", endpointName, device.getTenantId(), gatewayManagedDeviceId, reqPartName), qos);
    subscription = CommandSubscription.fromTopic(mqttTopicSubscription, gw);
    assertThat(subscription).isNotNull();
    assertThat(subscription.getTenant()).isEqualTo(gw.getTenantId());
    assertThat(subscription.getDeviceId()).isEqualTo(gatewayManagedDeviceId);
    assertThat(subscription.getAuthenticatedDeviceId()).isEqualTo(gw.getDeviceId());
    assertThat(subscription.getQos()).isEqualTo(qos);
    assertThat(subscription.isGatewaySubscriptionForSpecificDevice()).isEqualTo(true);
    // THEN the command topic does include the tenant as well
    assertThat(subscription.getCommandPublishTopic(command)).isEqualTo(String.format("%s/%s/%s/%s/requestId/doSomething", endpointName, gw.getTenantId(), gatewayManagedDeviceId, reqPartName));
    // WHEN subscribing to commands for all devices omitting tenant
    mqttTopicSubscription = new MqttTopicSubscriptionImpl(String.format("%s//+/%s/#", endpointName, reqPartName), qos);
    subscription = CommandSubscription.fromTopic(mqttTopicSubscription, gw);
    assertThat(subscription).isNotNull();
    assertThat(subscription.getTenant()).isEqualTo(gw.getTenantId());
    assertThat(subscription.getDeviceId()).isEqualTo(gw.getDeviceId());
    assertThat(subscription.getAuthenticatedDeviceId()).isEqualTo(gw.getDeviceId());
    assertThat(subscription.getQos()).isEqualTo(qos);
    assertThat(subscription.isGatewaySubscriptionForSpecificDevice()).isEqualTo(false);
    // THEN the command topic does not include the tenant either
    assertThat(subscription.getCommandPublishTopic(command)).isEqualTo(String.format("%s//%s/%s/requestId/doSomething", endpointName, gatewayManagedDeviceId, reqPartName));
    // WHEN subscribing to commands for all devices including the tenant
    mqttTopicSubscription = new MqttTopicSubscriptionImpl(String.format("%s/%s/+/%s/#", endpointName, device.getTenantId(), reqPartName), qos);
    subscription = CommandSubscription.fromTopic(mqttTopicSubscription, gw);
    assertThat(subscription).isNotNull();
    assertThat(subscription.getTenant()).isEqualTo(gw.getTenantId());
    assertThat(subscription.getDeviceId()).isEqualTo(gw.getDeviceId());
    assertThat(subscription.getAuthenticatedDeviceId()).isEqualTo(gw.getDeviceId());
    assertThat(subscription.getQos()).isEqualTo(qos);
    assertThat(subscription.isGatewaySubscriptionForSpecificDevice()).isEqualTo(false);
    // THEN the command topic does include the tenant as well
    assertThat(subscription.getCommandPublishTopic(command)).isEqualTo(String.format("%s/%s/%s/%s/requestId/doSomething", endpointName, gw.getTenantId(), gatewayManagedDeviceId, reqPartName));
    // using a tenant other than the tenant that the gateway belongs to should fail
    mqttTopicSubscription = new MqttTopicSubscriptionImpl(String.format("%s/otherTenant/+/%s/#", endpointName, reqPartName), qos);
    assertThat(CommandSubscription.fromTopic(mqttTopicSubscription, gw)).isNull();
}
Also used : MqttTopicSubscriptionImpl(io.vertx.mqtt.impl.MqttTopicSubscriptionImpl) Command(org.eclipse.hono.client.command.Command) MqttTopicSubscription(io.vertx.mqtt.MqttTopicSubscription) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) MethodSource(org.junit.jupiter.params.provider.MethodSource)

Example 5 with MqttTopicSubscription

use of io.vertx.mqtt.MqttTopicSubscription in project hono by eclipse.

the class CommandSubscriptionTest method testSubscriptionSucceedsForUnauthenticatedDevice.

/**
 * Verifies that an unauthenticated device can successfully subscribe for commands
 * using the default topic.
 *
 * @param endpointName The endpoint name used in the topic.
 * @param reqPartName The request part name used in the topic.
 * @param qos The requested QoS.
 */
@ParameterizedTest
@MethodSource("endpointAndReqNamesWithQoS")
public void testSubscriptionSucceedsForUnauthenticatedDevice(final String endpointName, final String reqPartName, final MqttQoS qos) {
    final MqttTopicSubscription mqttTopicSubscription = new MqttTopicSubscriptionImpl(String.format("%s/tenant1/deviceA/%s/#", endpointName, reqPartName), qos);
    final CommandSubscription subscription = CommandSubscription.fromTopic(mqttTopicSubscription, null);
    assertThat(subscription).isNotNull();
    assertThat(subscription.getTenant()).isEqualTo("tenant1");
    assertThat(subscription.getDeviceId()).isEqualTo("deviceA");
    assertThat(subscription.getEndpoint()).isEqualTo(endpointName);
    assertThat(subscription.getRequestPart()).isEqualTo(reqPartName);
    assertThat(subscription.getQos()).isEqualTo(qos);
}
Also used : MqttTopicSubscriptionImpl(io.vertx.mqtt.impl.MqttTopicSubscriptionImpl) MqttTopicSubscription(io.vertx.mqtt.MqttTopicSubscription) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) MethodSource(org.junit.jupiter.params.provider.MethodSource)

Aggregations

MqttTopicSubscription (io.vertx.mqtt.MqttTopicSubscription)14 MqttTopicSubscriptionImpl (io.vertx.mqtt.impl.MqttTopicSubscriptionImpl)8 ParameterizedTest (org.junit.jupiter.params.ParameterizedTest)8 MethodSource (org.junit.jupiter.params.provider.MethodSource)6 MqttEndpoint (io.vertx.mqtt.MqttEndpoint)5 Test (org.junit.jupiter.api.Test)4 MqttSubscribeMessage (io.vertx.mqtt.messages.MqttSubscribeMessage)3 ArrayList (java.util.ArrayList)3 CommandConsumer (org.eclipse.hono.client.command.CommandConsumer)3 MqttQoS (io.netty.handler.codec.mqtt.MqttQoS)2 Span (io.opentracing.Span)2 Handler (io.vertx.core.Handler)2 MqttPublishMessage (io.vertx.mqtt.messages.MqttPublishMessage)2 List (java.util.List)2 AuthHandler (org.eclipse.hono.adapter.auth.device.AuthHandler)2 Command (org.eclipse.hono.client.command.Command)2 AbstractVerticle (io.vertx.core.AbstractVerticle)1 Buffer (io.vertx.core.buffer.Buffer)1 Runner (io.vertx.example.mqtt.util.Runner)1 MqttServer (io.vertx.mqtt.MqttServer)1