use of io.vertx.proton.ProtonDelivery in project hono by eclipse.
the class ForwardingTelemetryDownstreamAdapterTest method testProcessMessageDiscardsMessageIfNoCreditIsAvailable.
/**
* Verifies that telemetry data is discarded if no downstream credit is available.
*
* @param ctx The test context.
*/
@SuppressWarnings("unchecked")
@Test
public void testProcessMessageDiscardsMessageIfNoCreditIsAvailable(final TestContext ctx) {
final UpstreamReceiver client = TestSupport.newClient();
final ProtonDelivery upstreamDelivery = mock(ProtonDelivery.class);
when(upstreamDelivery.remotelySettled()).thenReturn(Boolean.FALSE);
// GIVEN an adapter with a connection to a downstream container
ProtonSender sender = TestSupport.newMockSender(false);
when(sender.sendQueueFull()).thenReturn(true);
final ForwardingEventDownstreamAdapter adapter = new ForwardingEventDownstreamAdapter(vertx, newMockSenderFactory(sender));
adapter.setMetrics(mock(MessagingMetrics.class));
adapter.setDownstreamConnectionFactory(TestSupport.newMockConnectionFactory(false));
adapter.start(Future.future());
adapter.addSender(client, sender);
// WHEN processing an event
final Message msg = ProtonHelper.message(TELEMETRY_MSG_CONTENT);
MessageHelper.addDeviceId(msg, DEVICE_ID);
adapter.processMessage(client, upstreamDelivery, msg);
// THEN the the message is accepted
verify(upstreamDelivery).disposition(any(Released.class), eq(Boolean.TRUE));
// but is not delivered to the downstream container
verify(sender, never()).send(any(Message.class), any(Handler.class));
}
use of io.vertx.proton.ProtonDelivery in project hono by eclipse.
the class RegistrationClientImplTest method testAssertRegistrationInvokesServiceIfNoCacheConfigured.
/**
* Verifies that the client retrieves registration information from the
* Device Registration service if no cache is configured.
*
* @param ctx The vert.x test context.
*/
@SuppressWarnings("unchecked")
@Test
public void testAssertRegistrationInvokesServiceIfNoCacheConfigured(final TestContext ctx) {
// GIVEN an adapter with no cache configured
final JsonObject registrationAssertion = newRegistrationAssertionResult();
final Message response = ProtonHelper.message(registrationAssertion.encode());
MessageHelper.addProperty(response, MessageHelper.APP_PROPERTY_STATUS, HttpURLConnection.HTTP_OK);
// WHEN getting registration information
final Async assertion = ctx.async();
client.assertRegistration("device").setHandler(ctx.asyncAssertSuccess(result -> assertion.complete()));
final ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
verify(sender).send(messageCaptor.capture(), any(Handler.class));
response.setCorrelationId(messageCaptor.getValue().getMessageId());
final ProtonDelivery delivery = mock(ProtonDelivery.class);
client.handleResponse(delivery, response);
// THEN the registration information has been retrieved from the service
assertion.await();
// and not been put to the cache
verify(cache, never()).put(any(), any(RegistrationResult.class), any(Duration.class));
}
use of io.vertx.proton.ProtonDelivery in project hono by eclipse.
the class TelemetrySenderImplTest method testSendMessageFailsOnLackOfCredit.
/**
* Verifies that the sender fails if no credit is available.
*
* @param ctx The vert.x test context.
*/
@SuppressWarnings("unchecked")
@Test
public void testSendMessageFailsOnLackOfCredit(final TestContext ctx) {
// GIVEN a sender that has no credit
when(sender.sendQueueFull()).thenReturn(Boolean.TRUE);
MessageSender messageSender = new TelemetrySenderImpl(config, sender, "tenant", "telemetry/tenant", context);
// WHEN trying to send a message
final Future<ProtonDelivery> result = messageSender.send("device", "some payload", "application/text", "token");
// THEN the message is not sent
assertFalse(result.succeeded());
verify(sender, never()).send(any(Message.class), any(Handler.class));
}
use of io.vertx.proton.ProtonDelivery in project hono by eclipse.
the class TenantClientImplTest method testGetTenantAddsInfoToCacheOnCacheMiss.
/**
* Verifies that on a cache miss the adapter retrieves tenant information
* from the Tenant service and puts it to the cache.
*
* @param ctx The vert.x test context.
*/
@SuppressWarnings("unchecked")
@Test
public void testGetTenantAddsInfoToCacheOnCacheMiss(final TestContext ctx) {
// GIVEN an adapter with an empty cache
client.setResponseCache(cache);
final JsonObject tenantResult = newTenantResult("tenant");
// WHEN getting tenant information
final Async get = ctx.async();
client.get("tenant").setHandler(ctx.asyncAssertSuccess(tenant -> get.complete()));
final ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
verify(sender).send(messageCaptor.capture(), any(Handler.class));
final Message response = ProtonHelper.message(tenantResult.encode());
MessageHelper.addProperty(response, MessageHelper.APP_PROPERTY_STATUS, HttpURLConnection.HTTP_OK);
MessageHelper.addCacheDirective(response, CacheDirective.maxAgeDirective(60));
response.setCorrelationId(messageCaptor.getValue().getMessageId());
final ProtonDelivery delivery = mock(ProtonDelivery.class);
client.handleResponse(delivery, response);
// THEN the tenant result has been added to the cache
get.await();
verify(cache).put(eq(TriTuple.of(TenantAction.get, "tenant", null)), any(TenantResult.class), any(Duration.class));
}
use of io.vertx.proton.ProtonDelivery in project hono by eclipse.
the class RequestResponseEndpoint method handleMessage.
/**
* Handles a request message received from a client.
* <p>
* The message gets rejected if
* <ul>
* <li>the message does not pass {@linkplain #passesFormalVerification(ResourceIdentifier, Message) formal verification}
* or</li>
* <li>the client is not {@linkplain #isAuthorized(HonoUser, ResourceIdentifier, Message) authorized to execute the operation}
* indicated by the message's <em>subject</em> or</li>
* <li>its payload cannot be parsed</li>
* </ul>
*
* @param con The connection with the client.
* @param receiver The link over which the message has been received.
* @param targetAddress The address the message is sent to.
* @param delivery The message's delivery status.
* @param message The message.
*/
protected final void handleMessage(final ProtonConnection con, final ProtonReceiver receiver, final ResourceIdentifier targetAddress, ProtonDelivery delivery, Message message) {
final Future<Void> formalCheck = Future.future();
if (passesFormalVerification(targetAddress, message)) {
formalCheck.complete();
} else {
formalCheck.fail(new AmqpErrorException(AmqpError.DECODE_ERROR, "malformed payload"));
}
final HonoUser clientPrincipal = Constants.getClientPrincipal(con);
formalCheck.compose(ok -> isAuthorized(clientPrincipal, targetAddress, message)).compose(authorized -> {
logger.debug("client [{}] is {}authorized to {}:{}", clientPrincipal.getName(), authorized ? "" : "not ", targetAddress, message.getSubject());
if (authorized) {
try {
processRequest(message, targetAddress, clientPrincipal);
ProtonHelper.accepted(delivery, true);
return Future.succeededFuture();
} catch (DecodeException e) {
return Future.failedFuture(new AmqpErrorException(AmqpError.DECODE_ERROR, "malformed payload"));
}
} else {
return Future.failedFuture(new AmqpErrorException(AmqpError.UNAUTHORIZED_ACCESS, "unauthorized"));
}
}).otherwise(t -> {
if (t instanceof AmqpErrorException) {
AmqpErrorException cause = (AmqpErrorException) t;
MessageHelper.rejected(delivery, cause.asErrorCondition());
} else {
logger.debug("error processing request [resource: {}, op: {}]: {}", targetAddress, message.getSubject(), t.getMessage());
MessageHelper.rejected(delivery, ProtonHelper.condition(AmqpError.INTERNAL_ERROR, "internal error"));
}
return null;
});
}
Aggregations