Search in sources :

Example 11 with TimeUntilDisconnectNotification

use of org.eclipse.hono.util.TimeUntilDisconnectNotification in project hono by eclipse.

the class CommandAndControlMqttIT method testSendCommandViaKafkaFailsForMalformedMessage.

/**
 * Verifies that the adapter rejects malformed command messages sent by applications.
 * <p>
 * This test is applicable only if the messaging network type is Kafka.
 *
 * @param endpointConfig The endpoints to use for sending/receiving commands.
 * @param ctx The vert.x test context.
 * @throws InterruptedException if not all commands and responses are exchanged in time.
 */
@ParameterizedTest(name = IntegrationTestSupport.PARAMETERIZED_TEST_NAME_PATTERN)
@MethodSource("allCombinations")
@Timeout(timeUnit = TimeUnit.SECONDS, value = 20)
@AssumeMessagingSystem(type = MessagingType.kafka)
public void testSendCommandViaKafkaFailsForMalformedMessage(final MqttCommandEndpointConfiguration endpointConfig, final VertxTestContext ctx) throws InterruptedException {
    final String commandTargetDeviceId = endpointConfig.isSubscribeAsGateway() ? helper.setupGatewayDeviceBlocking(tenantId, deviceId, 5) : deviceId;
    final AtomicReference<GenericKafkaSender> kafkaSenderRef = new AtomicReference<>();
    final CountDownLatch expectedCommandResponses = new CountDownLatch(1);
    final VertxTestContext setup = new VertxTestContext();
    final Checkpoint ready = setup.checkpoint(2);
    final Future<MessageConsumer> kafkaAsyncErrorResponseConsumer = helper.createDeliveryFailureCommandResponseConsumer(ctx, tenantId, HttpURLConnection.HTTP_BAD_REQUEST, response -> expectedCommandResponses.countDown(), null);
    createConsumer(tenantId, msg -> {
        // expect empty notification with TTD -1
        setup.verify(() -> assertThat(msg.getContentType()).isEqualTo(EventConstants.CONTENT_TYPE_EMPTY_NOTIFICATION));
        final TimeUntilDisconnectNotification notification = msg.getTimeUntilDisconnectNotification().orElse(null);
        LOGGER.info("received notification [{}]", notification);
        if (notification.getTtd() == -1) {
            ready.flag();
        }
    }).compose(consumer -> helper.registry.addDeviceToTenant(tenantId, deviceId, password)).compose(ok -> connectToAdapter(IntegrationTestSupport.getUsername(deviceId, tenantId), password)).compose(conAck -> subscribeToCommands(commandTargetDeviceId, msg -> {
        // all commands should get rejected because they fail to pass the validity check
        ctx.failNow(new IllegalStateException("should not have received command"));
    }, endpointConfig, MqttQoS.AT_MOST_ONCE)).compose(ok -> helper.createGenericKafkaSender().onSuccess(kafkaSenderRef::set).mapEmpty()).compose(ok -> kafkaAsyncErrorResponseConsumer).onComplete(setup.succeeding(v -> ready.flag()));
    assertWithMessage("setup of adapter finished within %s seconds", IntegrationTestSupport.getTestSetupTimeout()).that(setup.awaitCompletion(IntegrationTestSupport.getTestSetupTimeout(), TimeUnit.SECONDS)).isTrue();
    if (setup.failed()) {
        ctx.failNow(setup.causeOfFailure());
        return;
    }
    final String commandTopic = new HonoTopic(HonoTopic.Type.COMMAND, tenantId).toString();
    LOGGER.debug("sending command message lacking subject and correlation ID - no failure response expected here");
    final Map<String, Object> properties1 = Map.of(MessageHelper.APP_PROPERTY_DEVICE_ID, deviceId, MessageHelper.SYS_PROPERTY_CONTENT_TYPE, MessageHelper.CONTENT_TYPE_OCTET_STREAM, KafkaRecordHelper.HEADER_RESPONSE_REQUIRED, true);
    kafkaSenderRef.get().sendAndWaitForOutcome(commandTopic, tenantId, deviceId, Buffer.buffer(), properties1).onComplete(ctx.succeeding(ok -> {
    }));
    LOGGER.debug("sending command message lacking subject");
    final String correlationId = "1";
    final Map<String, Object> properties2 = Map.of(MessageHelper.SYS_PROPERTY_CORRELATION_ID, correlationId, MessageHelper.APP_PROPERTY_DEVICE_ID, deviceId, MessageHelper.SYS_PROPERTY_CONTENT_TYPE, MessageHelper.CONTENT_TYPE_OCTET_STREAM, KafkaRecordHelper.HEADER_RESPONSE_REQUIRED, true);
    kafkaSenderRef.get().sendAndWaitForOutcome(commandTopic, tenantId, deviceId, Buffer.buffer(), properties2).onComplete(ctx.succeeding(ok -> {
    }));
    final long timeToWait = 2500;
    if (!expectedCommandResponses.await(timeToWait, TimeUnit.MILLISECONDS)) {
        LOGGER.info("Timeout of {} milliseconds reached, stop waiting for command response", timeToWait);
    }
    kafkaAsyncErrorResponseConsumer.result().close().onComplete(ar -> {
        if (expectedCommandResponses.getCount() == 0) {
            ctx.completeNow();
        } else {
            ctx.failNow(new java.lang.IllegalStateException("did not receive command response"));
        }
    });
}
Also used : GenericKafkaSender(org.eclipse.hono.tests.GenericKafkaSender) HttpURLConnection(java.net.HttpURLConnection) BeforeEach(org.junit.jupiter.api.BeforeEach) DownstreamMessage(org.eclipse.hono.application.client.DownstreamMessage) MqttPublishMessage(io.vertx.mqtt.messages.MqttPublishMessage) Timeout(io.vertx.junit5.Timeout) MessagingType(org.eclipse.hono.util.MessagingType) IntegrationTestSupport(org.eclipse.hono.tests.IntegrationTestSupport) ExtendWith(org.junit.jupiter.api.extension.ExtendWith) ChannelPromise(io.netty.channel.ChannelPromise) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Map(java.util.Map) MqttClientImpl(io.vertx.mqtt.impl.MqttClientImpl) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) Method(java.lang.reflect.Method) MethodSource(org.junit.jupiter.params.provider.MethodSource) ChannelOutboundHandlerAdapter(io.netty.channel.ChannelOutboundHandlerAdapter) MessageContext(org.eclipse.hono.application.client.MessageContext) SubscriberRole(org.eclipse.hono.tests.CommandEndpointConfiguration.SubscriberRole) Truth.assertWithMessage(com.google.common.truth.Truth.assertWithMessage) IllegalStateException(javax.jms.IllegalStateException) MessageHelper(org.eclipse.hono.util.MessageHelper) VertxExtension(io.vertx.junit5.VertxExtension) EventConstants(org.eclipse.hono.util.EventConstants) Future(io.vertx.core.Future) CountDownLatch(java.util.concurrent.CountDownLatch) Stream(java.util.stream.Stream) Buffer(io.vertx.core.buffer.Buffer) Checkpoint(io.vertx.junit5.Checkpoint) NetSocketInternal(io.vertx.core.net.impl.NetSocketInternal) VertxTestContext(io.vertx.junit5.VertxTestContext) GenericKafkaSender(org.eclipse.hono.tests.GenericKafkaSender) MqttQoS(io.netty.handler.codec.mqtt.MqttQoS) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ClientErrorException(org.eclipse.hono.client.ClientErrorException) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) TimeUntilDisconnectNotification(org.eclipse.hono.util.TimeUntilDisconnectNotification) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) Message(org.apache.qpid.proton.message.Message) MqttPubAckMessage(io.netty.handler.codec.mqtt.MqttPubAckMessage) Promise(io.vertx.core.Promise) ServerErrorException(org.eclipse.hono.client.ServerErrorException) ProtonHelper(io.vertx.proton.ProtonHelper) KafkaRecordHelper(org.eclipse.hono.client.kafka.KafkaRecordHelper) Truth.assertThat(com.google.common.truth.Truth.assertThat) AssumeMessagingSystem(org.eclipse.hono.tests.AssumeMessagingSystem) TimeUnit(java.util.concurrent.TimeUnit) AtomicLong(java.util.concurrent.atomic.AtomicLong) HonoTopic(org.eclipse.hono.client.kafka.HonoTopic) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) MessageConsumer(org.eclipse.hono.application.client.MessageConsumer) SendMessageTimeoutException(org.eclipse.hono.client.SendMessageTimeoutException) NoopSpan(io.opentracing.noop.NoopSpan) GenericSenderLink(org.eclipse.hono.client.amqp.GenericSenderLink) Handler(io.vertx.core.Handler) IllegalStateException(javax.jms.IllegalStateException) MessageConsumer(org.eclipse.hono.application.client.MessageConsumer) VertxTestContext(io.vertx.junit5.VertxTestContext) AtomicReference(java.util.concurrent.atomic.AtomicReference) HonoTopic(org.eclipse.hono.client.kafka.HonoTopic) CountDownLatch(java.util.concurrent.CountDownLatch) Checkpoint(io.vertx.junit5.Checkpoint) TimeUntilDisconnectNotification(org.eclipse.hono.util.TimeUntilDisconnectNotification) AssumeMessagingSystem(org.eclipse.hono.tests.AssumeMessagingSystem) Timeout(io.vertx.junit5.Timeout) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) MethodSource(org.junit.jupiter.params.provider.MethodSource)

Example 12 with TimeUntilDisconnectNotification

use of org.eclipse.hono.util.TimeUntilDisconnectNotification in project hono by eclipse.

the class CommandAndControlMqttIT method testSendCommandSucceeds.

private void testSendCommandSucceeds(final VertxTestContext ctx, final String commandTargetDeviceId, final Handler<MqttPublishMessage> commandConsumer, final Function<Buffer, Future<Void>> commandSender, final MqttCommandEndpointConfiguration endpointConfig, final int totalNoOfCommandsToSend, final MqttQoS subscribeQos) throws InterruptedException {
    final VertxTestContext setup = new VertxTestContext();
    final Checkpoint ready = setup.checkpoint(2);
    helper.registry.addDeviceToTenant(tenantId, deviceId, password).compose(ok -> connectToAdapter(IntegrationTestSupport.getUsername(deviceId, tenantId), password)).compose(ok -> createConsumer(tenantId, msg -> {
        // expect empty notification with TTD -1
        setup.verify(() -> assertThat(msg.getContentType()).isEqualTo(EventConstants.CONTENT_TYPE_EMPTY_NOTIFICATION));
        final TimeUntilDisconnectNotification notification = msg.getTimeUntilDisconnectNotification().orElse(null);
        LOGGER.info("received notification [{}]", notification);
        setup.verify(() -> assertThat(notification).isNotNull());
        if (notification.getTtd() == -1) {
            ready.flag();
        }
    })).compose(conAck -> subscribeToCommands(commandTargetDeviceId, commandConsumer, endpointConfig, subscribeQos)).onComplete(setup.succeeding(ok -> ready.flag()));
    assertWithMessage("setup of adapter finished within %s seconds", IntegrationTestSupport.getTestSetupTimeout()).that(setup.awaitCompletion(IntegrationTestSupport.getTestSetupTimeout(), TimeUnit.SECONDS)).isTrue();
    if (setup.failed()) {
        ctx.failNow(setup.causeOfFailure());
        return;
    }
    final Checkpoint sendCommandsSucceeded = ctx.checkpoint();
    final CountDownLatch commandsSucceeded = new CountDownLatch(totalNoOfCommandsToSend);
    final AtomicInteger commandsSent = new AtomicInteger(0);
    final AtomicLong lastReceivedTimestamp = new AtomicLong(0);
    final long start = System.currentTimeMillis();
    while (commandsSent.get() < totalNoOfCommandsToSend) {
        final CountDownLatch commandSent = new CountDownLatch(1);
        context.runOnContext(go -> {
            commandsSent.getAndIncrement();
            final Buffer msg = commandsSent.get() % 2 == 0 ? Buffer.buffer("value: " + commandsSent.get()) : // use 'null' payload for half the commands, ensuring such commands also get forwarded
            null;
            commandSender.apply(msg).onComplete(sendAttempt -> {
                if (sendAttempt.failed()) {
                    LOGGER.info("error sending command {}", commandsSent.get(), sendAttempt.cause());
                } else {
                    lastReceivedTimestamp.set(System.currentTimeMillis());
                    commandsSucceeded.countDown();
                    if (commandsSucceeded.getCount() % 20 == 0) {
                        LOGGER.info("commands succeeded: {}", totalNoOfCommandsToSend - commandsSucceeded.getCount());
                    }
                }
                if (commandsSent.get() % 20 == 0) {
                    LOGGER.info("commands sent: " + commandsSent.get());
                }
                commandSent.countDown();
            });
        });
        commandSent.await();
    }
    final long timeToWait = totalNoOfCommandsToSend * 200;
    if (!commandsSucceeded.await(timeToWait, TimeUnit.MILLISECONDS)) {
        LOGGER.info("Timeout of {} milliseconds reached, stop waiting for commands to succeed", timeToWait);
    }
    if (lastReceivedTimestamp.get() == 0L) {
        // no message has been received at all
        lastReceivedTimestamp.set(System.currentTimeMillis());
    }
    final long commandsCompleted = totalNoOfCommandsToSend - commandsSucceeded.getCount();
    LOGGER.info("commands sent: {}, commands succeeded: {} after {} milliseconds", commandsSent.get(), commandsCompleted, lastReceivedTimestamp.get() - start);
    if (commandsCompleted == commandsSent.get()) {
        sendCommandsSucceeded.flag();
    } else {
        ctx.failNow(new IllegalStateException("did not complete all commands sent"));
    }
}
Also used : HttpURLConnection(java.net.HttpURLConnection) BeforeEach(org.junit.jupiter.api.BeforeEach) DownstreamMessage(org.eclipse.hono.application.client.DownstreamMessage) MqttPublishMessage(io.vertx.mqtt.messages.MqttPublishMessage) Timeout(io.vertx.junit5.Timeout) MessagingType(org.eclipse.hono.util.MessagingType) IntegrationTestSupport(org.eclipse.hono.tests.IntegrationTestSupport) ExtendWith(org.junit.jupiter.api.extension.ExtendWith) ChannelPromise(io.netty.channel.ChannelPromise) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Map(java.util.Map) MqttClientImpl(io.vertx.mqtt.impl.MqttClientImpl) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) Method(java.lang.reflect.Method) MethodSource(org.junit.jupiter.params.provider.MethodSource) ChannelOutboundHandlerAdapter(io.netty.channel.ChannelOutboundHandlerAdapter) MessageContext(org.eclipse.hono.application.client.MessageContext) SubscriberRole(org.eclipse.hono.tests.CommandEndpointConfiguration.SubscriberRole) Truth.assertWithMessage(com.google.common.truth.Truth.assertWithMessage) IllegalStateException(javax.jms.IllegalStateException) MessageHelper(org.eclipse.hono.util.MessageHelper) VertxExtension(io.vertx.junit5.VertxExtension) EventConstants(org.eclipse.hono.util.EventConstants) Future(io.vertx.core.Future) CountDownLatch(java.util.concurrent.CountDownLatch) Stream(java.util.stream.Stream) Buffer(io.vertx.core.buffer.Buffer) Checkpoint(io.vertx.junit5.Checkpoint) NetSocketInternal(io.vertx.core.net.impl.NetSocketInternal) VertxTestContext(io.vertx.junit5.VertxTestContext) GenericKafkaSender(org.eclipse.hono.tests.GenericKafkaSender) MqttQoS(io.netty.handler.codec.mqtt.MqttQoS) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ClientErrorException(org.eclipse.hono.client.ClientErrorException) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) TimeUntilDisconnectNotification(org.eclipse.hono.util.TimeUntilDisconnectNotification) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) Message(org.apache.qpid.proton.message.Message) MqttPubAckMessage(io.netty.handler.codec.mqtt.MqttPubAckMessage) Promise(io.vertx.core.Promise) ServerErrorException(org.eclipse.hono.client.ServerErrorException) ProtonHelper(io.vertx.proton.ProtonHelper) KafkaRecordHelper(org.eclipse.hono.client.kafka.KafkaRecordHelper) Truth.assertThat(com.google.common.truth.Truth.assertThat) AssumeMessagingSystem(org.eclipse.hono.tests.AssumeMessagingSystem) TimeUnit(java.util.concurrent.TimeUnit) AtomicLong(java.util.concurrent.atomic.AtomicLong) HonoTopic(org.eclipse.hono.client.kafka.HonoTopic) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) MessageConsumer(org.eclipse.hono.application.client.MessageConsumer) SendMessageTimeoutException(org.eclipse.hono.client.SendMessageTimeoutException) NoopSpan(io.opentracing.noop.NoopSpan) GenericSenderLink(org.eclipse.hono.client.amqp.GenericSenderLink) Handler(io.vertx.core.Handler) Buffer(io.vertx.core.buffer.Buffer) IllegalStateException(javax.jms.IllegalStateException) Checkpoint(io.vertx.junit5.Checkpoint) AtomicLong(java.util.concurrent.atomic.AtomicLong) VertxTestContext(io.vertx.junit5.VertxTestContext) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) TimeUntilDisconnectNotification(org.eclipse.hono.util.TimeUntilDisconnectNotification) CountDownLatch(java.util.concurrent.CountDownLatch)

Aggregations

TimeUntilDisconnectNotification (org.eclipse.hono.util.TimeUntilDisconnectNotification)12 Future (io.vertx.core.Future)10 Handler (io.vertx.core.Handler)10 Buffer (io.vertx.core.buffer.Buffer)10 Map (java.util.Map)10 DownstreamMessage (org.eclipse.hono.application.client.DownstreamMessage)10 MessageConsumer (org.eclipse.hono.application.client.MessageConsumer)10 MessageContext (org.eclipse.hono.application.client.MessageContext)10 Truth.assertThat (com.google.common.truth.Truth.assertThat)8 Truth.assertWithMessage (com.google.common.truth.Truth.assertWithMessage)8 NoopSpan (io.opentracing.noop.NoopSpan)8 Promise (io.vertx.core.Promise)8 Checkpoint (io.vertx.junit5.Checkpoint)8 Timeout (io.vertx.junit5.Timeout)8 VertxExtension (io.vertx.junit5.VertxExtension)8 VertxTestContext (io.vertx.junit5.VertxTestContext)8 ProtonHelper (io.vertx.proton.ProtonHelper)8 HttpURLConnection (java.net.HttpURLConnection)8 CountDownLatch (java.util.concurrent.CountDownLatch)8 TimeUnit (java.util.concurrent.TimeUnit)8