use of org.apache.qpid.proton.amqp.messaging.Released in project hono by eclipse.
the class ForwardingEventDownstreamAdapterTest method testProcessMessageReleasesMessageIfNoCreditIsAvailable.
/**
* Verifies that an event is released if no downstream credit is available.
*
* @param ctx The test context.
*/
@SuppressWarnings("unchecked")
@Test
public void testProcessMessageReleasesMessageIfNoCreditIsAvailable(final TestContext ctx) {
final UpstreamReceiver client = newClient();
final ProtonDelivery delivery = mock(ProtonDelivery.class);
when(delivery.remotelySettled()).thenReturn(Boolean.FALSE);
// GIVEN an adapter with a connection to a downstream container
ProtonSender sender = newMockSender(false);
when(sender.sendQueueFull()).thenReturn(true);
ForwardingEventDownstreamAdapter adapter = new ForwardingEventDownstreamAdapter(vertx, newMockSenderFactory(sender));
adapter.setMetrics(mock(MessagingMetrics.class));
adapter.setDownstreamConnectionFactory(newMockConnectionFactory(false));
adapter.start(Future.future());
adapter.addSender(client, sender);
// WHEN processing an event
Message msg = ProtonHelper.message(EVENT_MSG_CONTENT);
MessageHelper.addDeviceId(msg, DEVICE_ID);
adapter.processMessage(client, delivery, msg);
// THEN the message is released
verify(delivery).disposition(any(Released.class), eq(Boolean.TRUE));
// and not delivered to the downstream container
verify(sender, never()).send(any(Message.class), any(Handler.class));
}
use of org.apache.qpid.proton.amqp.messaging.Released in project hono by eclipse.
the class EventConsumerImplTest method testCreateRegistersBiConsumerAsMessageHandler.
/**
* Verifies that the message delivery for a received event is forwarded to the
* registered event consumer.
*
* @param ctx The test context.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
@Test
public void testCreateRegistersBiConsumerAsMessageHandler(final TestContext ctx) {
// GIVEN an event consumer that releases all messages
final Async consumerCreation = ctx.async();
final BiConsumer<ProtonDelivery, Message> eventConsumer = (delivery, message) -> {
ProtonHelper.released(delivery, true);
};
final RecordImpl attachments = new RecordImpl();
final Source source = mock(Source.class);
when(source.toString()).thenReturn("event/tenant");
final ProtonReceiver receiver = mock(ProtonReceiver.class);
when(receiver.getSource()).thenReturn(source);
when(receiver.attachments()).thenReturn(attachments);
when(receiver.getRemoteQoS()).thenReturn(ProtonQoS.AT_LEAST_ONCE);
when(receiver.open()).then(answer -> {
consumerCreation.complete();
return receiver;
});
final ProtonConnection con = mock(ProtonConnection.class);
when(con.createReceiver(anyString())).thenReturn(receiver);
when(receiver.openHandler(any(Handler.class))).thenAnswer(invocation -> {
final Handler handler = invocation.getArgument(0);
handler.handle(Future.succeededFuture(receiver));
return receiver;
});
final ArgumentCaptor<ProtonMessageHandler> messageHandler = ArgumentCaptor.forClass(ProtonMessageHandler.class);
EventConsumerImpl.create(vertx.getOrCreateContext(), new ClientConfigProperties(), con, "tenant", eventConsumer, open -> {
}, remoteDetach -> {
});
consumerCreation.await();
verify(receiver).handler(messageHandler.capture());
// WHEN an event is received
final ProtonDelivery delivery = mock(ProtonDelivery.class);
final Message msg = mock(Message.class);
messageHandler.getValue().handle(delivery, msg);
// THEN the message is released and settled
verify(delivery).disposition(any(Released.class), eq(Boolean.TRUE));
}
use of org.apache.qpid.proton.amqp.messaging.Released in project azure-service-bus-java by Azure.
the class CoreMessageReceiver method onReceiveComplete.
@Override
public void onReceiveComplete(Delivery delivery) {
this.underlyingFactory.getRetryPolicy().resetRetryCount(this.getClientId());
byte[] deliveryTag = delivery.getTag();
String deliveryTagAsString = StringUtil.convertBytesToString(delivery.getTag());
TRACE_LOGGER.debug("Received a delivery '{}' from '{}'", deliveryTagAsString, this.receivePath);
if (deliveryTag == null || deliveryTag.length == 0 || !this.tagsToDeliveriesMap.containsKey(deliveryTagAsString)) {
TRACE_LOGGER.debug("Received a message from '{}'. Adding to prefecthed messages.", this.receivePath);
try {
Message message = Util.readMessageFromDelivery(receiveLink, delivery);
if (this.settleModePair.getSenderSettleMode() == SenderSettleMode.SETTLED) {
// No op. Delivery comes settled from the sender
delivery.disposition(Accepted.getInstance());
delivery.settle();
} else {
this.tagsToDeliveriesMap.put(StringUtil.convertBytesToString(delivery.getTag()), delivery);
receiveLink.advance();
}
// Accuracy of count is not that important. So not making those two operations atomic
this.currentPrefetechedMessagesCount.incrementAndGet();
this.prefetchedMessages.add(new MessageWithDeliveryTag(message, delivery.getTag()));
} catch (Exception e) {
TRACE_LOGGER.warn("Reading message from delivery '{}' from '{}', session '{}' failed with unexpected exception.", deliveryTagAsString, this.receivePath, this.sessionId, e);
delivery.disposition(Released.getInstance());
delivery.settle();
return;
}
} else {
DeliveryState remoteState = delivery.getRemoteState();
TRACE_LOGGER.debug("Received a delivery '{}' with state '{}' from '{}'", deliveryTagAsString, remoteState, this.receivePath);
if (remoteState instanceof Outcome) {
Outcome remoteOutcome = (Outcome) remoteState;
UpdateStateWorkItem matchingUpdateStateWorkItem = this.pendingUpdateStateRequests.get(deliveryTagAsString);
if (matchingUpdateStateWorkItem != null) {
// This comparison is ugly. Using it for the lack of equals operation on Outcome classes
if (remoteOutcome.getClass().getName().equals(matchingUpdateStateWorkItem.outcome.getClass().getName())) {
TRACE_LOGGER.debug("Completing a pending updateState operation for delivery '{}' from '{}'", deliveryTagAsString, this.receivePath);
this.completePendingUpdateStateWorkItem(delivery, deliveryTagAsString, matchingUpdateStateWorkItem, null);
} else {
// if(matchingUpdateStateWorkItem.expectedOutcome instanceof Accepted)
// {
TRACE_LOGGER.warn("Received delivery '{}' state '{}' doesn't match expected state '{}'", deliveryTagAsString, remoteState, matchingUpdateStateWorkItem.outcome);
// Complete requests
if (remoteOutcome instanceof Rejected) {
Rejected rejected = (Rejected) remoteOutcome;
ErrorCondition error = rejected.getError();
Exception exception = ExceptionUtil.toException(error);
if (ExceptionUtil.isGeneralError(error.getCondition())) {
this.lastKnownLinkError = exception;
this.lastKnownErrorReportedAt = Instant.now();
}
Duration retryInterval = this.retryPolicy.getNextRetryInterval(this.getClientId(), exception, matchingUpdateStateWorkItem.getTimeoutTracker().remaining());
if (retryInterval == null) {
TRACE_LOGGER.error("Completing pending updateState operation for delivery '{}' with exception", deliveryTagAsString, exception);
this.completePendingUpdateStateWorkItem(delivery, deliveryTagAsString, matchingUpdateStateWorkItem, exception);
} else {
matchingUpdateStateWorkItem.setLastKnownException(exception);
// Retry after retry interval
TRACE_LOGGER.debug("Pending updateState operation for delivery '{}' will be retried after '{}'", deliveryTagAsString, retryInterval);
try {
this.underlyingFactory.scheduleOnReactorThread((int) retryInterval.toMillis(), new DispatchHandler() {
@Override
public void onEvent() {
delivery.disposition((DeliveryState) matchingUpdateStateWorkItem.getOutcome());
}
});
} catch (IOException ioException) {
this.completePendingUpdateStateWorkItem(delivery, deliveryTagAsString, matchingUpdateStateWorkItem, new ServiceBusException(false, "Operation failed while scheduling a retry on Reactor, see cause for more details.", ioException));
}
}
} else if (remoteOutcome instanceof Released) {
Exception exception = new OperationCancelledException(remoteOutcome.toString());
TRACE_LOGGER.error("Completing pending updateState operation for delivery '{}' with exception", deliveryTagAsString, exception);
this.completePendingUpdateStateWorkItem(delivery, deliveryTagAsString, matchingUpdateStateWorkItem, exception);
} else {
Exception exception = new ServiceBusException(false, remoteOutcome.toString());
TRACE_LOGGER.error("Completing pending updateState operation for delivery '{}' with exception", deliveryTagAsString, exception);
this.completePendingUpdateStateWorkItem(delivery, deliveryTagAsString, matchingUpdateStateWorkItem, exception);
}
// }
}
} else {
// Should not happen. Ignore it
}
} else {
// Ignore it. we are only interested in terminal delivery states
}
}
}
use of org.apache.qpid.proton.amqp.messaging.Released in project hono by eclipse.
the class ProtonBasedMappingAndDelegatingCommandHandlerTest method testMapWithCommandHandlerNotFound.
/**
* Verifies the behaviour of the <em>mapAndDelegateIncomingCommandMessage</em> method in a scenario where
* the command handler is not found.
*/
@Test
public void testMapWithCommandHandlerNotFound() {
final String deviceId = "4711";
// GIVEN a 'NOT_FOUND' error when looking up the adapter instance
when(commandTargetMapper.getTargetGatewayAndAdapterInstance(anyString(), anyString(), any())).thenReturn(Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_NOT_FOUND)));
// WHEN mapping and delegating a command message
final Message message = getValidCommandMessage(deviceId);
final ProtonDelivery delivery = mock(ProtonDelivery.class);
mappingAndDelegatingCommandHandler.mapAndDelegateIncomingCommandMessage(tenantId, delivery, message);
// THEN the disposition is RELEASED
verify(delivery).disposition(any(Released.class), eq(true));
}
use of org.apache.qpid.proton.amqp.messaging.Released in project hono by eclipse.
the class ProtonBasedMappingAndDelegatingCommandHandlerTest method testMapWithCommandHandlerOnAnotherInstanceWithMessageSendingFailed.
/**
* Verifies the behaviour of the <em>mapAndDelegateIncomingCommandMessage</em> method in a scenario where
* the command shall get handled by some 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 some adapter instance
final String someAdapterInstance = "someAdapterInstance";
when(commandTargetMapper.getTargetGatewayAndAdapterInstance(anyString(), anyString(), any())).thenReturn(Future.succeededFuture(createTargetAdapterInstanceJson(deviceId, someAdapterInstance)));
// AND an error when sending the command message to that adapter instance (no credit)
when(sender.sendQueueFull()).thenReturn(Boolean.TRUE);
// WHEN mapping and delegating the command message
final Message message = getValidCommandMessage(deviceId);
final ProtonDelivery delivery = mock(ProtonDelivery.class);
mappingAndDelegatingCommandHandler.mapAndDelegateIncomingCommandMessage(tenantId, delivery, message);
// THEN the delivery gets RELEASED
verify(delivery).disposition(any(Released.class), eq(true));
}
Aggregations