io.vertx.proton.ProtonDelivery Java Examples

The following examples show how to use io.vertx.proton.ProtonDelivery. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: TelemetrySenderImplTest.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that the sender does not wait for the peer to settle and
 * accept a message before succeeding.
 */
@Test
public void testSendMessageDoesNotWaitForAcceptedOutcome() {

    // GIVEN a sender that has credit
    when(sender.sendQueueFull()).thenReturn(Boolean.FALSE);
    final DownstreamSender messageSender = new TelemetrySenderImpl(connection, sender, "tenant", "telemetry/tenant");
    final AtomicReference<Handler<ProtonDelivery>> handlerRef = new AtomicReference<>();
    doAnswer(invocation -> {
        handlerRef.set(invocation.getArgument(1));
        return mock(ProtonDelivery.class);
    }).when(sender).send(any(Message.class), VertxMockSupport.anyHandler());

    // WHEN trying to send a message
    final Future<ProtonDelivery> result = messageSender.send("device", "some payload", "application/text");
    // which gets rejected by the peer
    final ProtonDelivery rejected = mock(ProtonDelivery.class);
    when(rejected.remotelySettled()).thenReturn(Boolean.TRUE);
    when(rejected.getRemoteState()).thenReturn(new Rejected());
    handlerRef.get().handle(rejected);

    // THEN the resulting future is succeeded nevertheless
    assertTrue(result.succeeded());
    // and the message has been sent
    verify(sender).send(any(Message.class), eq(handlerRef.get()));
}
 
Example #2
Source File: MappingAndDelegatingCommandHandlerTest.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies the behaviour of the <em>mapAndDelegateIncomingCommandMessage</em> method in a scenario where
 * the command shall get handled by another adapter instance and where sending the command message to
 * the adapter instance fails.
 */
@Test
public void testMapWithCommandHandlerOnAnotherInstanceWithMessageSendingFailed() {
    final String deviceId = "4711";

    // GIVEN a deviceId commandHandler registered for another adapter instance (not the local one)
    final String otherAdapterInstance = "otherAdapterInstance";
    when(commandTargetMapper.getTargetGatewayAndAdapterInstance(anyString(), anyString(), any()))
            .thenReturn(Future.succeededFuture(createTargetAdapterInstanceJson(deviceId, otherAdapterInstance)));

    // AND an error when sending the command message to another adapter instance (no credit)
    when(sender.sendQueueFull()).thenReturn(Boolean.TRUE);

    // register local command handler - that shall not get used
    final AtomicReference<CommandContext> localHandlerCmdContextRef = new AtomicReference<>();
    adapterInstanceCommandHandler.putDeviceSpecificCommandHandler(Constants.DEFAULT_TENANT, deviceId, null, localHandlerCmdContextRef::set);

    // WHEN mapping and delegating the command message
    final Message message = getValidCommandMessage(deviceId);
    final ProtonDelivery delivery = mock(ProtonDelivery.class);
    mappingAndDelegatingCommandHandler.mapAndDelegateIncomingCommandMessage(Constants.DEFAULT_TENANT, delivery, message);

    // THEN the delivery gets RELEASED
    verify(delivery).disposition(any(Released.class), eq(true));
    assertThat(localHandlerCmdContextRef.get()).isNull();
}
 
Example #3
Source File: AbstractRequestResponseClientTest.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that the adapter puts the response from the service to the cache
 * using the max age indicated by a response's <em>max-age</em> cache directive.
 *
 * @param ctx The vert.x test context.
 */
@Test
public void testCreateAndSendRequestAddsResponseToCacheWithMaxAge(final VertxTestContext ctx) {

    // GIVEN an adapter with an empty cache
    client.setResponseCache(cache);

    // WHEN sending a request
    client.createAndSendRequest("get", (Buffer) null, ctx.succeeding(result -> {
        assertEquals(200, result.getStatus());
        // THEN the response has been put to the cache
        verify(cache).put(eq("cacheKey"), any(SimpleRequestResponseResult.class), eq(Duration.ofSeconds(35)));
        ctx.completeNow();
    }), "cacheKey");
    final ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
    verify(sender).send(messageCaptor.capture(), VertxMockSupport.anyHandler());
    final Message response = ProtonHelper.message("result");
    MessageHelper.addProperty(response, MessageHelper.APP_PROPERTY_STATUS, HttpURLConnection.HTTP_OK);
    MessageHelper.addCacheDirective(response, CacheDirective.maxAgeDirective(35));
    response.setCorrelationId(messageCaptor.getValue().getMessageId());
    final ProtonDelivery delivery = mock(ProtonDelivery.class);
    client.handleResponse(delivery, response);
}
 
Example #4
Source File: VertxBasedHttpProtocolAdapterTest.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that a POST request to the command reply URI for that the delivery to the associated link is being remotely settled
 * results in a {@link HttpURLConnection#HTTP_ACCEPTED}.

 * @param ctx The vert.x test context.
 */
@Test
public void testPostCmdResponseForExistingCommandResponseLinkResultsInAccepted(final VertxTestContext ctx) {

    final ProtonDelivery remotelySettledDelivery = mock(ProtonDelivery.class);
    when(remotelySettledDelivery.remotelySettled()).thenReturn(Boolean.TRUE);

    mockSuccessfulAuthentication("DEFAULT_TENANT", "device_1");

    when(commandResponseSender.sendCommandResponse(any(CommandResponse.class), (SpanContext) any())).thenReturn(
            Future.succeededFuture(remotelySettledDelivery));

    httpClient.post(getCommandResponsePath(CMD_REQ_ID))
            .addQueryParam(Constants.HEADER_COMMAND_RESPONSE_STATUS, "200")
            .putHeader(HttpHeaders.CONTENT_TYPE.toString(), HttpUtils.CONTENT_TYPE_JSON)
            .basicAuthentication("testuser@DEFAULT_TENANT", "password123")
            .putHeader(HttpHeaders.ORIGIN.toString(), "hono.eclipse.org")
            .expect(ResponsePredicate.SC_ACCEPTED)
            .sendJsonObject(new JsonObject(), ctx.completing());
}
 
Example #5
Source File: ApplicationClientFactoryImpl.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * {@inheritDoc}
 */
@Override
public Future<MessageConsumer> createAsyncCommandResponseConsumer(
        final String tenantId,
        final String replyId,
        final BiConsumer<ProtonDelivery, Message> consumer,
        final Handler<Void> closeHandler) {

    return connection.executeOnContext(result -> {
        consumerFactory.createClient(
                () -> AsyncCommandResponseConsumerImpl.create(
                        connection,
                        tenantId,
                        replyId,
                        consumer,
                        closeHook -> closeHandler.handle(null)),
                result);
    });
}
 
Example #6
Source File: AbstractAmqpAdapterClientDownstreamSenderTestBase.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Sets up fixture.
 */
@BeforeEach
public void setUp() {
    sender = HonoClientUnitTestHelper.mockProtonSender();

    protonDelivery = mock(ProtonDelivery.class);
    when(protonDelivery.remotelySettled()).thenReturn(true);
    final Accepted deliveryState = new Accepted();
    when(protonDelivery.getRemoteState()).thenReturn(deliveryState);

    when(sender.send(any(Message.class), VertxMockSupport.anyHandler())).thenReturn(protonDelivery);

    final Span span = mock(Span.class);
    when(span.context()).thenReturn(mock(SpanContext.class));
    spanBuilder = HonoClientUnitTestHelper.mockSpanBuilder(span);

    final Tracer tracer = mock(Tracer.class);
    when(tracer.buildSpan(anyString())).thenReturn(spanBuilder);

    connection = HonoClientUnitTestHelper.mockHonoConnection(mock(Vertx.class));

    when(connection.getTracer()).thenReturn(tracer);
    when(connection.createSender(any(), any(), any())).thenReturn(Future.succeededFuture(sender));

}
 
Example #7
Source File: GenericMessageSenderImpl.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Sends an AMQP 1.0 message to the peer this client is configured for
 * and waits for the outcome of the transfer.
 *
 * @param message The message to send.
 * @return A future indicating the outcome of transferring the message.
 *         <p>
 *         The future will succeed with the updated delivery from the peer if
 *         the message has been settled with the <em>accepted</em> outcome.
 *         <p>
 *         The future will be failed with a {@link ServerErrorException} if the
 *         message could not be sent, e.g. due to a lack of credit. It will be
 *         failed with a {@link ClientErrorException} if the message has not
 *         been accepted by the peer.
 * @throws NullPointerException if the message is {@code null}.
 */
@Override
public Future<ProtonDelivery> sendAndWaitForOutcome(final Message message) {
    return connection.executeOnContext(result -> {
        if (sender.isOpen() && sender.getCredit() > 0) {
            sender.send(message, updatedDelivery -> {
                if (updatedDelivery.getRemoteState() instanceof Accepted) {
                    result.complete(updatedDelivery);
                } else if (updatedDelivery.getRemoteState() instanceof Released) {
                    result.fail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE));
                } else {
                    result.fail(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST));
                }
            });
        } else {
            result.fail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE));
        }
    });
}
 
Example #8
Source File: AbstractRequestResponseClientTest.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that the adapter does not put the response from the service to the cache
 * if the response contains a <em>no-cache</em> cache directive.
 *
 * @param ctx The vert.x test context.
 */
@Test
public void testCreateAndSendRequestDoesNotAddResponseToCache(final VertxTestContext ctx) {

    // GIVEN an adapter with an empty cache
    client.setResponseCache(cache);

    // WHEN sending a request
    client.createAndSendRequest("get", (Buffer) null, ctx.succeeding(result -> {
        assertEquals(200, result.getStatus());
        // THEN the response is not put to the cache
        verify(cache, never()).put(eq("cacheKey"), any(SimpleRequestResponseResult.class), any(Duration.class));
        ctx.completeNow();
    }), "cacheKey");
    final ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
    verify(sender).send(messageCaptor.capture(), VertxMockSupport.anyHandler());
    final Message response = ProtonHelper.message("result");
    MessageHelper.addProperty(response, MessageHelper.APP_PROPERTY_STATUS, HttpURLConnection.HTTP_OK);
    MessageHelper.addCacheDirective(response, CacheDirective.noCacheDirective());
    response.setCorrelationId(messageCaptor.getValue().getMessageId());
    final ProtonDelivery delivery = mock(ProtonDelivery.class);
    client.handleResponse(delivery, response);
}
 
Example #9
Source File: AbstractProtocolAdapterBase.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Forwards a response message that has been sent by a device in reply to a
 * command to the sender of the command.
 * <p>
 * This method opens a new link for sending the response, tries to send the
 * response message and then closes the link again.
 *
 * @param tenantId The tenant that the device belongs to.
 * @param response The response message.
 * @param context The currently active OpenTracing span. An implementation
 *         should use this as the parent for any span it creates for tracing
 *         the execution of this operation.
 * @return A future indicating the outcome of the attempt to send
 *         the message. The link will be closed in any case.
 * @throws NullPointerException if any of the parameters other than context are {@code null}.
 */
protected final Future<ProtonDelivery> sendCommandResponse(
        final String tenantId,
        final CommandResponse response,
        final SpanContext context) {

    Objects.requireNonNull(tenantId);
    Objects.requireNonNull(response);

    final Future<CommandResponseSender> senderTracker = createCommandResponseSender(tenantId,
            response.getReplyToId());
    return senderTracker
            .compose(sender -> sender.sendCommandResponse(response, context))
            .map(delivery -> {
                senderTracker.result().close(c -> {});
                return delivery;
            }).recover(t -> {
                if (senderTracker.succeeded()) {
                    senderTracker.result().close(c -> {});
                }
                return Future.failedFuture(t);
            });
}
 
Example #10
Source File: MappingAndDelegatingCommandHandlerTest.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies the behaviour of the <em>mapAndDelegateIncomingCommandMessage</em> method in a scenario where
 * the given command message shall get mapped to a local command handler.
 */
@Test
public void testMapWithLocalCommandHandler() {
    final String deviceId = "4711";

    // GIVEN a registered commandHandler for the deviceId
    final AtomicReference<CommandContext> localHandlerCmdContextRef = new AtomicReference<>();
    adapterInstanceCommandHandler.putDeviceSpecificCommandHandler(Constants.DEFAULT_TENANT, deviceId, null, localHandlerCmdContextRef::set);

    // AND the deviceId commandHandler registered for the local adapter instance
    when(commandTargetMapper.getTargetGatewayAndAdapterInstance(anyString(), anyString(), any()))
            .thenReturn(Future.succeededFuture(createTargetAdapterInstanceJson(deviceId, adapterInstanceId)));

    // WHEN mapping and delegating the command message
    final Message message = getValidCommandMessage(deviceId);
    final ProtonDelivery delivery = mock(ProtonDelivery.class);
    mappingAndDelegatingCommandHandler.mapAndDelegateIncomingCommandMessage(Constants.DEFAULT_TENANT, delivery, message);

    // THEN the local command handler is invoked with the unchanged command message
    assertThat(localHandlerCmdContextRef.get()).isNotNull();
    assertThat(localHandlerCmdContextRef.get().getCommand()).isNotNull();
    assertThat(localHandlerCmdContextRef.get().getCommand().getCommandMessage()).isEqualTo(message);
    assertThat(localHandlerCmdContextRef.get().getCommand().isValid()).isTrue();
    // AND the command message delivery is unchanged (that would be done by the commandHandler)
    verify(delivery, never()).disposition(any(), anyBoolean());
}
 
Example #11
Source File: AdapterInstanceCommandHandlerTest.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
@Test
void testHandleCommandMessageWithHandlerForGatewayAndSpecificDevice() {
    final String deviceId = "4711";
    final String gatewayId = "gw-1";
    final String correlationId = "the-correlation-id";
    final Message message = ProtonHelper.message("input data");
    message.setAddress(String.format("%s/%s/%s",
            CommandConstants.COMMAND_ENDPOINT, Constants.DEFAULT_TENANT, deviceId));
    message.setSubject("doThis");
    message.setCorrelationId(correlationId);

    final Handler<CommandContext> commandHandler = VertxMockSupport.mockHandler();
    adapterInstanceCommandHandler.putDeviceSpecificCommandHandler(Constants.DEFAULT_TENANT, deviceId, gatewayId, commandHandler);

    adapterInstanceCommandHandler.handleCommandMessage(message, mock(ProtonDelivery.class));

    final ArgumentCaptor<CommandContext> commandContextCaptor = ArgumentCaptor.forClass(CommandContext.class);
    verify(commandHandler).handle(commandContextCaptor.capture());
    assertThat(commandContextCaptor.getValue()).isNotNull();
    // assert that command is directed at the gateway
    assertThat(commandContextCaptor.getValue().getCommand().getDeviceId()).isEqualTo(gatewayId);
    assertThat(commandContextCaptor.getValue().getCommand().getOriginalDeviceId()).isEqualTo(deviceId);
}
 
Example #12
Source File: TelemetrySenderImpl.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * {@inheritDoc}
 */
@Override
public Future<ProtonDelivery> sendAndWaitForOutcome(final Message rawMessage, final SpanContext parent) {

    Objects.requireNonNull(rawMessage);

    // we create a child span (instead of a following span) because we depend
    // on the outcome of the sending operation
    final Span span = startChildSpan(parent, rawMessage);
    Tags.MESSAGE_BUS_DESTINATION.set(span, targetAddress);
    TracingHelper.setDeviceTags(span, tenantId, MessageHelper.getDeviceId(rawMessage));
    TracingHelper.injectSpanContext(connection.getTracer(), span.context(), rawMessage);

    return connection.executeOnContext(result -> {
        if (sender.sendQueueFull()) {
            final ServiceInvocationException e = new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "no credit available");
            logMessageSendingError("error sending message [ID: {}, address: {}], no credit available",
                    rawMessage.getMessageId(), getMessageAddress(rawMessage));
            logError(span, e);
            span.finish();
            result.fail(e);
        } else {
            sendMessageAndWaitForOutcome(rawMessage, span).onComplete(result);
        }
    });
}
 
Example #13
Source File: TelemetrySenderImplTest.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that a timeout occurring while a message is sent doesn't cause the corresponding 
 * OpenTracing span to stay unfinished.
 */
@Test
public void testSendMessageFailsOnTimeout() {

    // GIVEN a sender that won't receive a delivery update on sending a message 
    // and directly triggers the timeout handler
    when(sender.send(any(Message.class), VertxMockSupport.anyHandler())).thenReturn(mock(ProtonDelivery.class));
    when(vertx.setTimer(anyLong(), VertxMockSupport.anyHandler())).thenAnswer(invocation -> {
        final Handler<Long> handler = invocation.getArgument(1);
        final long timerId = 1;
        handler.handle(timerId);
        return timerId;
    });
    final DownstreamSender messageSender = new TelemetrySenderImpl(connection, sender, "tenant", "telemetry/tenant");

    // WHEN sending a message
    final Message message = mock(Message.class);
    final Span span = mock(Span.class);
    ((TelemetrySenderImpl) messageSender).sendMessage(message, span);

    // THEN the given Span will nonetheless be finished.
    verify(span).finish();
}
 
Example #14
Source File: CommandResponderTest.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that {@link TraceableCommandResponder} uses the given SpanContext.
 *
 * @param ctx The test context to use for running asynchronous tests.
 */
@Test
public void testSendCommandResponseWithTracing(final VertxTestContext ctx) {

    // GIVEN a TraceableCommandResponder instance
    final TraceableCommandResponder commandResponder = ((TraceableCommandResponder) createCommandResponder());

    // WHEN sending a message using the API...
    final SpanContext spanContext = mock(SpanContext.class);
    final Future<ProtonDelivery> deliveryFuture = commandResponder.sendCommandResponse(DEVICE_ID,
            ADDRESS, CORRELATION_ID, STATUS, PAYLOAD, CONTENT_TYPE, APPLICATION_PROPERTIES, spanContext);

    // ...AND WHEN the disposition is updated by the peer
    updateDisposition();

    deliveryFuture.onComplete(ctx.succeeding(delivery -> {
        // THEN the given SpanContext is used
        ctx.verify(() -> {
            verify(spanBuilder).addReference(any(), eq(spanContext));
            assertMessageConformsAmqpAdapterSpec();
        });
        ctx.completeNow();
    }));
}
 
Example #15
Source File: CommandResponderTest.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that the message created by the client conforms to the expectations of the AMQP adapter.
 *
 * @param ctx The test context to use for running asynchronous tests.
 */
@Test
public void testSendCommandResponseCreatesValidMessage(final VertxTestContext ctx) {

    // GIVEN a CommandResponder instance
    final CommandResponder commandResponder = createCommandResponder();

    // WHEN sending a message using the API...
    final Future<ProtonDelivery> deliveryFuture = commandResponder.sendCommandResponse(DEVICE_ID,
            ADDRESS, CORRELATION_ID, STATUS, PAYLOAD, CONTENT_TYPE, APPLICATION_PROPERTIES);

    // ...AND WHEN the disposition is updated by the peer
    updateDisposition();

    deliveryFuture.onComplete(ctx.succeeding(delivery -> {
        // THEN the AMQP message conforms to the expectations of the AMQP protocol adapter
        ctx.verify(this::assertMessageConformsAmqpAdapterSpec);
        ctx.completeNow();
    }));
}
 
Example #16
Source File: TelemetrySenderTest.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that sending the message waits for the disposition update from the peer.
 *
 * @param ctx The test context to use for running asynchronous tests.
 */
@Test
public void testSendAndWaitForOutcomeWaitsForDispositionUpdate(final VertxTestContext ctx) {

    // GIVEN a TelemetrySender instance
    final TelemetrySender telemetrySender = createTelemetrySender();

    // WHEN sending a message using the API
    final Future<ProtonDelivery> deliveryFuture = telemetrySender.sendAndWaitForOutcome(DEVICE_ID, PAYLOAD,
            CONTENT_TYPE, APPLICATION_PROPERTIES);

    deliveryFuture.onComplete(ctx.completing());

    // THEN the future waits for the disposition to be updated by the peer
    assertThat(deliveryFuture.isComplete()).isFalse();
    updateDisposition();
}
 
Example #17
Source File: TelemetrySenderTest.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that {@link TraceableTelemetrySender#sendAndWaitForOutcome(String, byte[], String, Map, SpanContext)}
 * uses the given SpanContext.
 *
 * @param ctx The test context to use for running asynchronous tests.
 */
@Test
public void testSendAndWaitForOutcomeWithTracing(final VertxTestContext ctx) {

    // GIVEN a TraceableTelemetrySender instance
    final TraceableTelemetrySender telemetrySender = ((TraceableTelemetrySender) createTelemetrySender());

    // WHEN sending a message using the API...
    final SpanContext spanContext = mock(SpanContext.class);
    final Future<ProtonDelivery> deliveryFuture = telemetrySender.sendAndWaitForOutcome(DEVICE_ID, PAYLOAD,
            CONTENT_TYPE, APPLICATION_PROPERTIES, spanContext);

    // ...AND WHEN the disposition is updated by the peer
    updateDisposition();

    deliveryFuture.onComplete(ctx.succeeding(delivery -> {
        // THEN the given SpanContext is used
        ctx.verify(() -> {
            verify(spanBuilder).addReference(any(), eq(spanContext));
            assertMessageConformsAmqpAdapterSpec(ADDRESS);
        });
        ctx.completeNow();
    }));
}
 
Example #18
Source File: TelemetrySenderTest.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that the message created by {@link TelemetrySender#sendAndWaitForOutcome(String, byte[], String, Map)}
 * conforms to the expectations of the AMQP adapter.
 *
 * @param ctx The test context to use for running asynchronous tests.
 */
@Test
public void testSendAndWaitForOutcomeCreatesValidMessage(final VertxTestContext ctx) {

    // GIVEN a TelemetrySender instance
    final TelemetrySender telemetrySender = createTelemetrySender();

    // WHEN sending a message using the API...
    final Future<ProtonDelivery> deliveryFuture = telemetrySender.sendAndWaitForOutcome(DEVICE_ID, PAYLOAD,
            CONTENT_TYPE, APPLICATION_PROPERTIES);

    // ...AND WHEN the disposition is updated by the peer
    updateDisposition();

    deliveryFuture.onComplete(ctx.succeeding(delivery -> {
        // THEN the AMQP message conforms to the expectations of the AMQP protocol adapter
        ctx.verify(() -> assertMessageConformsAmqpAdapterSpec(ADDRESS));
        ctx.completeNow();
    }));
}
 
Example #19
Source File: EventSenderTest.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that the message created by the client conforms to the expectations of the AMQP adapter.
 *
 * @param ctx The test context to use for running asynchronous tests.
 */
@Test
public void testSendCreatesValidMessage(final VertxTestContext ctx) {

    // GIVEN a EventSender instance
    final EventSender eventSender = createEventSender();

    // WHEN sending a message using the API...
    final Future<ProtonDelivery> deliveryFuture = eventSender.send(DEVICE_ID, PAYLOAD, CONTENT_TYPE,
            APPLICATION_PROPERTIES);

    // ...AND WHEN the disposition is updated by the peer
    updateDisposition();

    deliveryFuture.onComplete(ctx.succeeding(delivery -> {
        // THEN the AMQP message conforms to the expectations of the AMQP protocol adapter
        ctx.verify(() -> assertMessageConformsAmqpAdapterSpec(ADDRESS));
        ctx.completeNow();
    }));
}
 
Example #20
Source File: TelemetryAndEventCli.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Connects to the AMQP org.eclipse.hono.cli.app.adapter and send a telemetry/event message to the org.eclipse.hono.cli.app.adapter.
 *
 * @param messageTracker The future to notify when the message is sent. The future is completed with the delivery
 *            upon success or completed with an exception.
 */
private void sendMessage(final CompletableFuture<ProtonDelivery> messageTracker) {

    ctx.runOnContext(go -> {
        connectToAdapter()
        .compose(con -> {
            adapterConnection = con;
            return createSender();
        })
        .map(sender -> {
            final Message message = ProtonHelper.message(messageAddress, payload);
            sender.send(message, delivery -> {
                adapterConnection.close();
                messageTracker.complete(delivery);
            });
            return sender;
        })
        .otherwise(t -> {
            messageTracker.completeExceptionally(t);
            return null;
        });
    });
 }
 
Example #21
Source File: RequestResponseEndpointTest.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that the endpoint rejects malformed request messages.
 */
@Test
public void testHandleMessageRejectsMalformedMessage() {

    final Message msg = ProtonHelper.message();
    final ProtonConnection con = mock(ProtonConnection.class);
    final ProtonDelivery delivery = mock(ProtonDelivery.class);
    final RequestResponseEndpoint<ServiceConfigProperties> endpoint = getEndpoint(false);

    // WHEN a malformed message is received
    endpoint.handleRequestMessage(con, receiver, resource, delivery, msg);

    // THEN the link is closed and the message is rejected
    final ArgumentCaptor<DeliveryState> deliveryState = ArgumentCaptor.forClass(DeliveryState.class);
    verify(delivery).disposition(deliveryState.capture(), eq(Boolean.TRUE));
    assertThat(deliveryState.getValue()).isInstanceOf(Rejected.class);
    verify(receiver, never()).close();
    verify(receiver).flow(1);
}
 
Example #22
Source File: AdapterInstanceCommandHandlerTest.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
@Test
void testHandleCommandMessageWithHandlerForDevice() {
    final String deviceId = "4711";
    final String correlationId = "the-correlation-id";
    final Message message = ProtonHelper.message("input data");
    message.setAddress(String.format("%s/%s/%s",
            CommandConstants.COMMAND_ENDPOINT, Constants.DEFAULT_TENANT, deviceId));
    message.setSubject("doThis");
    message.setCorrelationId(correlationId);

    final Handler<CommandContext> commandHandler = VertxMockSupport.mockHandler();
    adapterInstanceCommandHandler.putDeviceSpecificCommandHandler(Constants.DEFAULT_TENANT, deviceId, null, commandHandler);

    adapterInstanceCommandHandler.handleCommandMessage(message, mock(ProtonDelivery.class));

    final ArgumentCaptor<CommandContext> commandContextCaptor = ArgumentCaptor.forClass(CommandContext.class);
    verify(commandHandler).handle(commandContextCaptor.capture());
    assertThat(commandContextCaptor.getValue()).isNotNull();
    assertThat(commandContextCaptor.getValue().getCommand().getDeviceId()).isEqualTo(deviceId);
}
 
Example #23
Source File: GenericMessageSenderImpl.java    From hono with Eclipse Public License 2.0 5 votes vote down vote up
/**
 * {@inheritDoc}
 */
@Override
public Future<ProtonDelivery> send(final Message message) {
    return connection.executeOnContext(result -> {
        if (sender.isOpen() && sender.getCredit() > 0) {
            result.complete(sender.send(message));
        } else {
            result.fail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE));
        }
    });
}
 
Example #24
Source File: VertxBasedAmqpProtocolAdapterTest.java    From hono with Eclipse Public License 2.0 5 votes vote down vote up
/**
 * Verify that the AMQP adapter forwards command responses downstream.
 *
 * @param ctx The vert.x test context.
 */
@Test
public void testUploadCommandResponseSucceeds(final VertxTestContext ctx) {

    // GIVEN an AMQP adapter
    final VertxBasedAmqpProtocolAdapter adapter = givenAnAmqpAdapter();
    final CommandResponseSender responseSender = givenACommandResponseSenderForAnyTenant();
    final ProtonDelivery delivery = mock(ProtonDelivery.class);
    when(responseSender.sendCommandResponse(any(CommandResponse.class), (SpanContext) any())).thenReturn(Future.succeededFuture(delivery));
    // which is enabled for the test tenant
    final TenantObject tenantObject = givenAConfiguredTenant(TEST_TENANT_ID, true);

    // WHEN an unauthenticated device publishes a command response
    final String replyToAddress = String.format("%s/%s/%s", getCommandResponseEndpoint(), TEST_TENANT_ID,
            Command.getDeviceFacingReplyToId("test-reply-id", TEST_DEVICE));

    final Map<String, Object> propertyMap = new HashMap<>();
    propertyMap.put(MessageHelper.APP_PROPERTY_STATUS, 200);
    final ApplicationProperties props = new ApplicationProperties(propertyMap);
    final Buffer payload = Buffer.buffer("some payload");
    final Message message = getFakeMessage(replyToAddress, payload);
    when(message.getCorrelationId()).thenReturn("correlation-id");
    when(message.getApplicationProperties()).thenReturn(props);

    adapter.onMessageReceived(AmqpContext.fromMessage(delivery, message, null)).onComplete(ctx.succeeding(ok -> {
        ctx.verify(() -> {
            // THEN the adapter forwards the command response message downstream
            verify(responseSender).sendCommandResponse((CommandResponse) any(), (SpanContext) any());
            // and reports the forwarded message
            verify(metrics).reportCommand(
                eq(Direction.RESPONSE),
                eq(TEST_TENANT_ID),
                eq(tenantObject),
                eq(ProcessingOutcome.FORWARDED),
                eq(payload.length()),
                any());
        });
        ctx.completeNow();
    }));
}
 
Example #25
Source File: AbstractVertxBasedHttpProtocolAdapterTest.java    From hono with Eclipse Public License 2.0 5 votes vote down vote up
private DownstreamSender givenAnEventSenderForOutcome(final Future<ProtonDelivery> outcome) {

        final DownstreamSender sender = mock(DownstreamSender.class);
        when(sender.sendAndWaitForOutcome(any(Message.class), (SpanContext) any())).thenReturn(outcome);

        when(downstreamSenderFactory.getOrCreateEventSender(anyString())).thenReturn(Future.succeededFuture(sender));
        return sender;
    }
 
Example #26
Source File: DelegatedCommandSenderImpl.java    From hono with Eclipse Public License 2.0 5 votes vote down vote up
@Override
public Future<ProtonDelivery> sendAndWaitForOutcome(final Message rawMessage, final SpanContext parent) {
    Objects.requireNonNull(rawMessage);

    final Span span = startSpan(parent, rawMessage);
    TracingHelper.injectSpanContext(connection.getTracer(), span.context(), rawMessage);

    return runSendAndWaitForOutcomeOnContext(rawMessage, span);
}
 
Example #27
Source File: VertxBasedAmqpProtocolAdapterTest.java    From hono with Eclipse Public License 2.0 5 votes vote down vote up
/**
 * Verifies that a request to upload an "unsettled" telemetry message from a device that belongs to a tenant for which the AMQP
 * adapter is disabled fails and that the device is notified when the message cannot be processed.
 *
 * @param ctx The vert.x test context.
 */
@Test
public void testUploadTelemetryMessageFailsForDisabledAdapter(final VertxTestContext ctx) {

    // GIVEN an adapter configured to use a user-define server.
    final VertxBasedAmqpProtocolAdapter adapter = givenAnAmqpAdapter();
    final DownstreamSender telemetrySender = givenATelemetrySenderForAnyTenant();

    // AND given a tenant for which the AMQP Adapter is disabled
    final TenantObject tenantObject = givenAConfiguredTenant(TEST_TENANT_ID, false);

    // WHEN a device uploads telemetry data to the adapter (and wants to be notified of failure)
    final ProtonDelivery delivery = mock(ProtonDelivery.class);
    when(delivery.remotelySettled()).thenReturn(false); // AT LEAST ONCE
    final String to = ResourceIdentifier.from(TelemetryConstants.TELEMETRY_ENDPOINT, TEST_TENANT_ID, TEST_DEVICE).toString();
    final Buffer payload = Buffer.buffer("some payload");

    adapter.onMessageReceived(AmqpContext.fromMessage(delivery, getFakeMessage(to, payload), null))
        .onComplete(ctx.failing(t -> {
            ctx.verify(() -> {
                // THEN the adapter does not send the message (regardless of the delivery mode).
                verify(telemetrySender, never()).send(any(Message.class), (SpanContext) any());
                verify(telemetrySender, never()).sendAndWaitForOutcome(any(Message.class), (SpanContext) any());

                // AND notifies the device by sending back a REJECTED disposition
                verify(delivery).disposition(any(Rejected.class), eq(true));

                // AND has reported the message as unprocessable
                verify(metrics).reportTelemetry(
                        eq(EndpointType.TELEMETRY),
                        eq(TEST_TENANT_ID),
                        eq(tenantObject),
                        eq(ProcessingOutcome.UNPROCESSABLE),
                        eq(QoS.AT_LEAST_ONCE),
                        eq(payload.length()),
                        any());
            });
            ctx.completeNow();
        }));
}
 
Example #28
Source File: AmqpSourceBridgeEndpoint.java    From strimzi-kafka-bridge with Apache License 2.0 5 votes vote down vote up
/**
 * Process the message received on the related receiver link
 *
 * @param receiver Proton receiver instance
 * @param delivery Proton delivery instance
 * @param message AMQP message received
 */
private void processMessage(ProtonReceiver receiver, ProtonDelivery delivery, Message message) {

    // replace unsupported "/" (in a topic name in Kafka) with "."
    String kafkaTopic = (receiver.getTarget().getAddress() != null) ?
            receiver.getTarget().getAddress().replace('/', '.') :
            null;

    KafkaProducerRecord<K, V> krecord = this.converter.toKafkaRecord(kafkaTopic, null, message);

    if (delivery.remotelySettled()) {

        // message settled (by sender), no feedback need by Apache Kafka, no disposition to be sent
        this.send(krecord, null);

    } else {
        // message unsettled (by sender), feedback needed by Apache Kafka, disposition to be sent accordingly
        this.send(krecord, writeResult -> {

            if (writeResult.failed()) {

                Throwable exception = writeResult.cause();
                // record not delivered, send REJECTED disposition to the AMQP sender
                log.error("Error on delivery to Kafka {}", exception.getMessage());
                this.rejectedDelivery(receiver.getName(), delivery, exception);

            } else {

                RecordMetadata metadata = writeResult.result();
                // record delivered, send ACCEPTED disposition to the AMQP sender
                log.debug("Delivered to Kafka on topic {} at partition {} [{}]", metadata.getTopic(), metadata.getPartition(), metadata.getOffset());
                this.acceptedDelivery(receiver.getName(), delivery);
            }
        });
    }
}
 
Example #29
Source File: CommandResponseSenderImpl.java    From hono with Eclipse Public License 2.0 5 votes vote down vote up
/**
 * {@inheritDoc}
 */
@Override
public Future<ProtonDelivery> sendCommandResponse(final CommandResponse commandResponse,
        final SpanContext context) {

    Objects.requireNonNull(commandResponse);
    final Message message = commandResponse.toMessage();
    Objects.requireNonNull(message);
    message.setAddress(targetAddress);
    return sendAndWaitForOutcome(message, context);
}
 
Example #30
Source File: AdapterInstanceCommandHandlerTest.java    From hono with Eclipse Public License 2.0 5 votes vote down vote up
@Test
void testHandleCommandMessageWithNoHandlerFound() {
    final Message msg = mock(Message.class);
    final String deviceId = "4711";
    when(msg.getAddress()).thenReturn(String.format("%s/%s/%s",
            CommandConstants.COMMAND_ENDPOINT, Constants.DEFAULT_TENANT, deviceId));
    final ProtonDelivery delivery = mock(ProtonDelivery.class);
    adapterInstanceCommandHandler.handleCommandMessage(msg, delivery);

    final ArgumentCaptor<DeliveryState> deliveryStateCaptor = ArgumentCaptor.forClass(DeliveryState.class);
    verify(delivery).disposition(deliveryStateCaptor.capture(), anyBoolean());
    assertThat(deliveryStateCaptor.getValue()).isNotNull();
    assertThat(deliveryStateCaptor.getValue()).isInstanceOf(Released.class);
}