Search in sources :

Example 21 with Rejected

use of org.apache.qpid.proton.amqp.messaging.Rejected in project hono by eclipse.

the class ProtonBasedCredentialsClientTest method testGetCredentialsFailsWithRejectedRequest.

/**
 * Verifies that the client fails if the credentials service cannot be reached.
 *
 * @param ctx The vert.x test context.
 */
@Test
public void testGetCredentialsFailsWithRejectedRequest(final VertxTestContext ctx) {
    // GIVEN a client
    givenAClient(cache);
    final ProtonDelivery update = mock(ProtonDelivery.class);
    when(update.getRemoteState()).thenReturn(new Rejected());
    when(update.remotelySettled()).thenReturn(true);
    when(sender.send(any(Message.class), VertxMockSupport.anyHandler())).thenAnswer(invocation -> {
        final Handler<ProtonDelivery> dispositionHandler = invocation.getArgument(1);
        dispositionHandler.handle(update);
        return mock(ProtonDelivery.class);
    });
    // WHEN getting credentials
    client.get("tenant", CredentialsConstants.SECRETS_TYPE_HASHED_PASSWORD, "test-auth", span.context()).onComplete(ctx.failing(t -> {
        ctx.verify(() -> {
            assertThat(t).isInstanceOf(ClientErrorException.class);
            assertThat(((ClientErrorException) t).getErrorCode()).isEqualTo(HttpURLConnection.HTTP_BAD_REQUEST);
            // THEN the invocation fails and the span is marked as erroneous
            verify(span).setTag(eq(Tags.ERROR.getKey()), eq(Boolean.TRUE));
            // and the span is finished
            verify(span).finish();
        });
        ctx.completeNow();
    }));
}
Also used : HttpURLConnection(java.net.HttpURLConnection) ProtonReceiver(io.vertx.proton.ProtonReceiver) BeforeEach(org.junit.jupiter.api.BeforeEach) LifecycleChange(org.eclipse.hono.notification.deviceregistry.LifecycleChange) ArgumentMatchers.eq(org.mockito.ArgumentMatchers.eq) DeviceChangeNotification(org.eclipse.hono.notification.deviceregistry.DeviceChangeNotification) Tags(io.opentracing.tag.Tags) Timeout(io.vertx.junit5.Timeout) EventBus(io.vertx.core.eventbus.EventBus) ExtendWith(org.junit.jupiter.api.extension.ExtendWith) Mockito.verifyNoMoreInteractions(org.mockito.Mockito.verifyNoMoreInteractions) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) NotificationType(org.eclipse.hono.notification.NotificationType) TracingMockSupport(org.eclipse.hono.test.TracingMockSupport) JsonObject(io.vertx.core.json.JsonObject) AllDevicesOfTenantDeletedNotification(org.eclipse.hono.notification.deviceregistry.AllDevicesOfTenantDeletedNotification) CredentialsResult(org.eclipse.hono.util.CredentialsResult) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Set(java.util.Set) ProtonQoS(io.vertx.proton.ProtonQoS) Instant(java.time.Instant) MessageHelper(org.eclipse.hono.util.MessageHelper) RequestResponseApiConstants(org.eclipse.hono.util.RequestResponseApiConstants) VertxExtension(io.vertx.junit5.VertxExtension) Future(io.vertx.core.Future) Test(org.junit.jupiter.api.Test) VertxMockSupport(org.eclipse.hono.test.VertxMockSupport) Span(io.opentracing.Span) ProtonSender(io.vertx.proton.ProtonSender) NotificationEventBusSupport(org.eclipse.hono.notification.NotificationEventBusSupport) Mockito.mock(org.mockito.Mockito.mock) ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) AbstractNotification(org.eclipse.hono.notification.AbstractNotification) CacheDirective(org.eclipse.hono.util.CacheDirective) VertxTestContext(io.vertx.junit5.VertxTestContext) ArgumentMatchers.anyLong(org.mockito.ArgumentMatchers.anyLong) ProtonDelivery(io.vertx.proton.ProtonDelivery) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) AmqpClientUnitTestHelper(org.eclipse.hono.client.amqp.test.AmqpClientUnitTestHelper) ClientErrorException(org.eclipse.hono.client.ClientErrorException) Cache(com.github.benmanes.caffeine.cache.Cache) Constants(org.eclipse.hono.util.Constants) ConcurrentMap(java.util.concurrent.ConcurrentMap) HashSet(java.util.HashSet) ArgumentCaptor(org.mockito.ArgumentCaptor) Message(org.apache.qpid.proton.message.Message) HonoConnection(org.eclipse.hono.client.HonoConnection) CredentialsChangeNotification(org.eclipse.hono.notification.deviceregistry.CredentialsChangeNotification) RequestResponseClientConfigProperties(org.eclipse.hono.client.RequestResponseClientConfigProperties) Tracer(io.opentracing.Tracer) Vertx(io.vertx.core.Vertx) Mockito.times(org.mockito.Mockito.times) ProtonHelper(io.vertx.proton.ProtonHelper) Mockito.when(org.mockito.Mockito.when) Truth.assertThat(com.google.common.truth.Truth.assertThat) CredentialsConstants(org.eclipse.hono.util.CredentialsConstants) Mockito.verify(org.mockito.Mockito.verify) TimeUnit(java.util.concurrent.TimeUnit) Mockito.never(org.mockito.Mockito.never) AnnotatedCacheKey(org.eclipse.hono.client.util.AnnotatedCacheKey) SendMessageSampler(org.eclipse.hono.client.SendMessageSampler) Handler(io.vertx.core.Handler) CredentialsObject(org.eclipse.hono.util.CredentialsObject) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) ProtonDelivery(io.vertx.proton.ProtonDelivery) Message(org.apache.qpid.proton.message.Message) ClientErrorException(org.eclipse.hono.client.ClientErrorException) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) Test(org.junit.jupiter.api.Test)

Example 22 with Rejected

use of org.apache.qpid.proton.amqp.messaging.Rejected in project hono by eclipse.

the class ProtonBasedMappingAndDelegatingCommandHandler method mapAndDelegateIncomingCommandMessage.

/**
 * Delegates an incoming command to the protocol adapter instance that the target
 * device is connected to.
 * <p>
 * Determines the target gateway (if applicable) and protocol adapter instance for an incoming command
 * and delegates the command to the resulting protocol adapter instance.
 *
 * @param tenantId The tenant that the command target must belong to.
 * @param messageDelivery The delivery of the command message.
 * @param message The command message.
 * @throws NullPointerException if any of the parameters is {@code null}.
 */
public void mapAndDelegateIncomingCommandMessage(final String tenantId, final ProtonDelivery messageDelivery, final Message message) {
    Objects.requireNonNull(tenantId);
    Objects.requireNonNull(messageDelivery);
    Objects.requireNonNull(message);
    final Timer.Sample timer = getMetrics().startTimer();
    // this is the place where a command message on the "command/${tenant}" address arrives *first*
    if (!ResourceIdentifier.isValid(message.getAddress())) {
        log.debug("command message has no valid address");
        final Rejected rejected = new Rejected();
        rejected.setError(new ErrorCondition(Constants.AMQP_BAD_REQUEST, "missing or invalid command target address"));
        messageDelivery.disposition(rejected, true);
        return;
    }
    final ResourceIdentifier targetAddress = ResourceIdentifier.fromString(message.getAddress());
    final String deviceId = targetAddress.getResourceId();
    if (!tenantId.equals(targetAddress.getTenantId())) {
        log.debug("command message address contains invalid tenant [expected: {}, found: {}]", tenantId, targetAddress.getTenantId());
        final Rejected rejected = new Rejected();
        rejected.setError(new ErrorCondition(AmqpError.UNAUTHORIZED_ACCESS, "unauthorized to send command to tenant"));
        messageDelivery.disposition(rejected, true);
        return;
    } else if (Strings.isNullOrEmpty(deviceId)) {
        log.debug("invalid command message address: {}", message.getAddress());
        final Rejected rejected = new Rejected();
        rejected.setError(new ErrorCondition(Constants.AMQP_BAD_REQUEST, "invalid command target address"));
        messageDelivery.disposition(rejected, true);
        return;
    }
    final ProtonBasedCommand command = ProtonBasedCommand.from(message);
    if (command.isValid()) {
        log.trace("received valid command message: {}", command);
    } else {
        log.debug("received invalid command message: {}", command);
    }
    final SpanContext spanContext = TracingHelper.extractSpanContext(tracer, message);
    final Span currentSpan = createSpan(tenantId, deviceId, spanContext);
    command.logToSpan(currentSpan);
    final ProtonBasedCommandContext commandContext = new ProtonBasedCommandContext(command, messageDelivery, currentSpan);
    if (command.isValid()) {
        mapAndDelegateIncomingCommand(commandContext, timer);
    } else {
        // command message is invalid
        commandContext.reject("malformed command message");
        reportInvalidCommand(commandContext, timer);
    }
}
Also used : ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) SpanContext(io.opentracing.SpanContext) Timer(io.micrometer.core.instrument.Timer) ProtonBasedCommandContext(org.eclipse.hono.client.command.amqp.ProtonBasedCommandContext) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) ProtonBasedCommand(org.eclipse.hono.client.command.amqp.ProtonBasedCommand) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) Span(io.opentracing.Span)

Example 23 with Rejected

use of org.apache.qpid.proton.amqp.messaging.Rejected in project hono by eclipse.

the class ProtonBasedMappingAndDelegatingCommandHandlerTest method testMapWithCommandHandlerOnAnotherInstanceWithInvalidMessage.

/**
 * Verifies the behaviour of the <em>mapAndDelegateIncomingCommandMessage</em> method in a scenario where
 * the command shall get handled by some adapter instance, and the command message is invalid.
 */
@Test
public void testMapWithCommandHandlerOnAnotherInstanceWithInvalidMessage() {
    final String deviceId = "4711";
    // GIVEN a deviceId commandHandler registered for some adapter instance
    final String someAdapterInstance = "someAdapterInstance";
    when(commandTargetMapper.getTargetGatewayAndAdapterInstance(anyString(), anyString(), any())).thenReturn(Future.succeededFuture(createTargetAdapterInstanceJson(deviceId, someAdapterInstance)));
    // WHEN mapping and delegating the invalid command message
    final Message message = getValidCommandMessage(deviceId);
    // make the message invalid
    message.setSubject(null);
    final ProtonDelivery delivery = mock(ProtonDelivery.class);
    mappingAndDelegatingCommandHandler.mapAndDelegateIncomingCommandMessage(tenantId, delivery, message);
    // THEN the delivery gets REJECTED
    verify(delivery).disposition(any(Rejected.class), eq(true));
}
Also used : Message(org.apache.qpid.proton.message.Message) ProtonDelivery(io.vertx.proton.ProtonDelivery) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) Test(org.junit.jupiter.api.Test)

Example 24 with Rejected

use of org.apache.qpid.proton.amqp.messaging.Rejected in project hono by eclipse.

the class ProtonBasedCommandRouterClientTest method testRegisterCommandConsumerFailsWithRejectedRequest.

/**
 * Verifies that a client invocation of the <em>register-command-consumer</em> operation fails
 * if the command router service cannot be reached.
 *
 * @param ctx The vert.x test context.
 */
@Test
public void testRegisterCommandConsumerFailsWithRejectedRequest(final VertxTestContext ctx) {
    // GIVEN a remote peer returning a Rejected disposition
    final ProtonDelivery update = mock(ProtonDelivery.class);
    when(update.getRemoteState()).thenReturn(new Rejected());
    when(update.remotelySettled()).thenReturn(true);
    when(sender.send(any(Message.class), VertxMockSupport.anyHandler())).thenAnswer(invocation -> {
        final Handler<ProtonDelivery> dispositionHandler = invocation.getArgument(1);
        dispositionHandler.handle(update);
        return mock(ProtonDelivery.class);
    });
    // WHEN registering the command consumer
    client.registerCommandConsumer("tenant", "deviceId", "adapterInstanceId", null, span.context()).onComplete(ctx.failing(t -> {
        ctx.verify(() -> {
            assertThat(ServiceInvocationException.extractStatusCode(t)).isEqualTo(HttpURLConnection.HTTP_BAD_REQUEST);
            // THEN the invocation fails and the span is marked as erroneous
            verify(span).setTag(eq(Tags.ERROR.getKey()), eq(Boolean.TRUE));
            // and the span is finished
            verify(span).finish();
        });
        ctx.completeNow();
    }));
}
Also used : HttpURLConnection(java.net.HttpURLConnection) ProtonReceiver(io.vertx.proton.ProtonReceiver) BeforeEach(org.junit.jupiter.api.BeforeEach) ArgumentMatchers.eq(org.mockito.ArgumentMatchers.eq) Tags(io.opentracing.tag.Tags) Timeout(io.vertx.junit5.Timeout) EventBus(io.vertx.core.eventbus.EventBus) ExtendWith(org.junit.jupiter.api.extension.ExtendWith) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) Duration(java.time.Duration) Map(java.util.Map) TracingMockSupport(org.eclipse.hono.test.TracingMockSupport) JsonObject(io.vertx.core.json.JsonObject) ProtonQoS(io.vertx.proton.ProtonQoS) MessageHelper(org.eclipse.hono.util.MessageHelper) VertxExtension(io.vertx.junit5.VertxExtension) Future(io.vertx.core.Future) Test(org.junit.jupiter.api.Test) List(java.util.List) VertxMockSupport(org.eclipse.hono.test.VertxMockSupport) Span(io.opentracing.Span) ProtonSender(io.vertx.proton.ProtonSender) ArgumentMatchers.longThat(org.mockito.ArgumentMatchers.longThat) Mockito.mock(org.mockito.Mockito.mock) ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) IntStream(java.util.stream.IntStream) CacheDirective(org.eclipse.hono.util.CacheDirective) VertxTestContext(io.vertx.junit5.VertxTestContext) ArgumentMatchers.anyLong(org.mockito.ArgumentMatchers.anyLong) ProtonDelivery(io.vertx.proton.ProtonDelivery) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) AmqpClientUnitTestHelper(org.eclipse.hono.client.amqp.test.AmqpClientUnitTestHelper) CommandRouterConstants(org.eclipse.hono.util.CommandRouterConstants) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) AtomicReference(java.util.concurrent.atomic.AtomicReference) ArgumentCaptor(org.mockito.ArgumentCaptor) Message(org.apache.qpid.proton.message.Message) LinkedList(java.util.LinkedList) HonoConnection(org.eclipse.hono.client.HonoConnection) RequestResponseClientConfigProperties(org.eclipse.hono.client.RequestResponseClientConfigProperties) CommandRouterAction(org.eclipse.hono.util.CommandRouterConstants.CommandRouterAction) Tracer(io.opentracing.Tracer) Vertx(io.vertx.core.Vertx) Mockito.times(org.mockito.Mockito.times) ProtonHelper(io.vertx.proton.ProtonHelper) Mockito.when(org.mockito.Mockito.when) Truth.assertThat(com.google.common.truth.Truth.assertThat) Mockito.verify(org.mockito.Mockito.verify) TimeUnit(java.util.concurrent.TimeUnit) Clock(java.time.Clock) SendMessageSampler(org.eclipse.hono.client.SendMessageSampler) Handler(io.vertx.core.Handler) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) ProtonDelivery(io.vertx.proton.ProtonDelivery) Message(org.apache.qpid.proton.message.Message) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) Test(org.junit.jupiter.api.Test)

Example 25 with Rejected

use of org.apache.qpid.proton.amqp.messaging.Rejected in project hono by eclipse.

the class ProtonBasedCommandContext method updateDelivery.

private void updateDelivery(final DeliveryState deliveryState) {
    final Span span = getTracingSpan();
    if (delivery.isSettled()) {
        final String msg = String.format("cannot complete incoming delivery of command message with outcome '%s' - delivery already settled locally; local state: %s", deliveryState, delivery.getLocalState());
        TracingHelper.logError(getTracingSpan(), msg);
        LOG.info("{} [{}]", msg, getCommand());
    } else {
        final boolean wasAlreadyRemotelySettled = delivery.remotelySettled();
        // if delivery is already settled remotely call "disposition" anyway to update local state and settle locally
        delivery.disposition(deliveryState, true);
        if (wasAlreadyRemotelySettled) {
            final String msg = String.format("cannot complete incoming delivery of command message with outcome '%s' - delivery already settled remotely; remote state: %s", deliveryState, delivery.getRemoteState());
            TracingHelper.logError(getTracingSpan(), msg);
            LOG.info("{} [{}]", msg, getCommand());
        } else if (Accepted.class.isInstance(deliveryState)) {
            LOG.trace("accepted command message [{}]", getCommand());
            span.log("accepted command for device");
        } else if (Released.class.isInstance(deliveryState)) {
            LOG.debug("released command message [{}]", getCommand());
            TracingHelper.logError(span, "released command for device");
        } else if (Modified.class.isInstance(deliveryState)) {
            final Modified modified = (Modified) deliveryState;
            LOG.debug("modified command message [{}]", getCommand());
            TracingHelper.logError(span, "modified command for device" + (Boolean.TRUE.equals(modified.getDeliveryFailed()) ? "; delivery failed" : "") + (Boolean.TRUE.equals(modified.getUndeliverableHere()) ? "; undeliverable here" : ""));
        } else if (Rejected.class.isInstance(deliveryState)) {
            final ErrorCondition errorCondition = ((Rejected) deliveryState).getError();
            LOG.debug("rejected command message [error: {}, command: {}]", errorCondition, getCommand());
            TracingHelper.logError(span, "rejected command for device" + ((errorCondition != null && errorCondition.getDescription() != null) ? "; error: " + errorCondition.getDescription() : ""));
        } else {
            LOG.warn("unexpected delivery state [{}] when settling command message [{}]", deliveryState, getCommand());
            TracingHelper.logError(span, "unexpected delivery state: " + deliveryState);
        }
    }
    span.finish();
}
Also used : Modified(org.apache.qpid.proton.amqp.messaging.Modified) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) Span(io.opentracing.Span) Accepted(org.apache.qpid.proton.amqp.messaging.Accepted)

Aggregations

Rejected (org.apache.qpid.proton.amqp.messaging.Rejected)59 Message (org.apache.qpid.proton.message.Message)32 ProtonDelivery (io.vertx.proton.ProtonDelivery)28 Handler (io.vertx.core.Handler)27 DeliveryState (org.apache.qpid.proton.amqp.transport.DeliveryState)23 ErrorCondition (org.apache.qpid.proton.amqp.transport.ErrorCondition)23 Accepted (org.apache.qpid.proton.amqp.messaging.Accepted)21 Span (io.opentracing.Span)19 Test (org.junit.jupiter.api.Test)19 ProtonHelper (io.vertx.proton.ProtonHelper)18 ProtonSender (io.vertx.proton.ProtonSender)18 Released (org.apache.qpid.proton.amqp.messaging.Released)18 Future (io.vertx.core.Future)17 HttpURLConnection (java.net.HttpURLConnection)17 MessageHelper (org.eclipse.hono.util.MessageHelper)17 ProtonQoS (io.vertx.proton.ProtonQoS)16 ClientErrorException (org.eclipse.hono.client.ClientErrorException)16 ProtonReceiver (io.vertx.proton.ProtonReceiver)15 ArgumentMatchers.anyString (org.mockito.ArgumentMatchers.anyString)15 Truth.assertThat (com.google.common.truth.Truth.assertThat)14