use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class TelemetryResourceTest method testMessageLimitExceededForATelemetryMessage.
/**
* Verifies that a telemetry message is rejected due to the limit exceeded.
*
* @param ctx The vert.x test context.
*/
@Test
public void testMessageLimitExceededForATelemetryMessage(final VertxTestContext ctx) {
// GIVEN an adapter with a downstream telemetry consumer attached
givenAnAdapter(properties);
givenATelemetrySenderForAnyTenant();
final var resource = givenAResource(adapter);
// WHEN a device that belongs to a tenant for which the message limit is exceeded
// publishes a telemetry message
when(adapter.checkMessageLimit(any(TenantObject.class), anyLong(), any())).thenReturn(Future.failedFuture(new ClientErrorException(429)));
final Buffer payload = Buffer.buffer("some payload");
final CoapExchange coapExchange = newCoapExchange(payload, Type.NON, MediaTypeRegistry.TEXT_PLAIN);
final Device authenticatedDevice = new Device("tenant", "device");
final CoapContext context = CoapContext.fromRequest(coapExchange, authenticatedDevice, authenticatedDevice, "device", span);
resource.handlePostRequest(context).onComplete(ctx.failing(t -> {
ctx.verify(() -> {
// THEN the message is not being forwarded downstream
assertNoTelemetryMessageHasBeenSentDownstream();
// and the device gets a 4.29
assertThat(t).isInstanceOf(ClientErrorException.class);
assertThat(((ClientErrorException) t).getErrorCode()).isEqualTo(429);
verify(metrics).reportTelemetry(eq(MetricsTags.EndpointType.TELEMETRY), eq("tenant"), any(), eq(MetricsTags.ProcessingOutcome.UNPROCESSABLE), eq(MetricsTags.QoS.AT_MOST_ONCE), eq(payload.length()), eq(TtdStatus.NONE), any());
});
ctx.completeNow();
}));
}
use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class TelemetryResourceTest method testUploadTelemetryReleasesCommandForFailedDownstreamSender.
/**
* Verifies that the adapter releases an incoming command if the forwarding of the preceding telemetry
* message did not succeed.
*
* @param ctx The vert.x test context.
*/
@Test
public void testUploadTelemetryReleasesCommandForFailedDownstreamSender(final VertxTestContext ctx) {
// GIVEN an adapter with a downstream telemetry consumer attached
givenAnAdapter(properties);
final Promise<Void> sendTelemetryOutcome = Promise.promise();
givenATelemetrySenderForAnyTenant(sendTelemetryOutcome);
final var resource = givenAResource(adapter);
// and a commandConsumerFactory that upon creating a consumer will invoke it with a command
final CommandContext commandContext = givenAOneWayCommandContext("tenant", "device", "doThis", null, null);
when(commandConsumerFactory.createCommandConsumer(eq("tenant"), eq("device"), VertxMockSupport.anyHandler(), any(), any())).thenAnswer(invocation -> {
final Handler<CommandContext> consumer = invocation.getArgument(2);
consumer.handle(commandContext);
return Future.succeededFuture(commandConsumer);
});
// WHEN a device publishes a telemetry message with a hono-ttd parameter
final Buffer payload = Buffer.buffer("some payload");
final OptionSet options = new OptionSet();
options.addUriQuery(String.format("%s=%d", Constants.HEADER_TIME_TILL_DISCONNECT, 20));
options.setContentFormat(MediaTypeRegistry.TEXT_PLAIN);
final CoapExchange coapExchange = newCoapExchange(payload, Type.CON, options);
final Device authenticatedDevice = new Device("tenant", "device");
final CoapContext context = CoapContext.fromRequest(coapExchange, authenticatedDevice, authenticatedDevice, "device", span);
final Future<Void> result = resource.handlePostRequest(context);
// THEN the message is being forwarded downstream
assertTelemetryMessageHasBeenSentDownstream(QoS.AT_LEAST_ONCE, "tenant", "device", "text/plain");
// with no response being sent to the device yet
verify(coapExchange, never()).respond(any(Response.class));
// WHEN the telemetry message delivery gets failed with an exception representing a "released" delivery outcome
sendTelemetryOutcome.fail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE));
result.onComplete(ctx.failing(t -> {
ctx.verify(() -> {
// THEN the device gets a response with code SERVICE_UNAVAILABLE
assertThat(t).isInstanceOf(ServerErrorException.class);
assertThat(((ServerErrorException) t).getErrorCode()).isEqualTo(HttpURLConnection.HTTP_UNAVAILABLE);
verify(metrics).reportTelemetry(eq(MetricsTags.EndpointType.TELEMETRY), eq("tenant"), any(), eq(ProcessingOutcome.UNDELIVERABLE), eq(MetricsTags.QoS.AT_LEAST_ONCE), eq(payload.length()), eq(TtdStatus.COMMAND), any());
// and the command delivery is released
verify(commandContext).release(any(Throwable.class));
});
ctx.completeNow();
}));
}
use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class CommandResponseResourceTest method testUploadCommandResponseFailsForRejectedOutcome.
/**
* Verifies that the adapter fails the upload of a command response with a 4.00
* response code if it is rejected by the downstream peer.
*
* @param ctx The vert.x test context.
*/
@Test
public void testUploadCommandResponseFailsForRejectedOutcome(final VertxTestContext ctx) {
// GIVEN an adapter with a downstream application attached
givenAnAdapter(properties);
final var resource = givenAResource(adapter);
final Promise<Void> outcome = Promise.promise();
final CommandResponseSender sender = givenACommandResponseSenderForAnyTenant(outcome);
// WHEN a device publishes an command response
final String reqId = Commands.encodeRequestIdParameters("correlation", "replyToId", "device", MessagingType.amqp);
final Buffer payload = Buffer.buffer("some payload");
final OptionSet options = new OptionSet();
options.addUriPath(CommandConstants.COMMAND_RESPONSE_ENDPOINT).addUriPath(reqId);
options.addUriQuery(String.format("%s=%d", Constants.HEADER_COMMAND_RESPONSE_STATUS, 200));
options.setContentFormat(MediaTypeRegistry.TEXT_PLAIN);
final CoapExchange coapExchange = newCoapExchange(payload, Type.CON, options);
final Device authenticatedDevice = new Device("tenant", "device");
final CoapContext context = CoapContext.fromRequest(coapExchange, authenticatedDevice, authenticatedDevice, "device", span);
final Future<Void> result = resource.uploadCommandResponseMessage(context);
outcome.fail(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "malformed message"));
result.onComplete(ctx.failing(t -> {
ctx.verify(() -> {
// THEN the command response is being forwarded downstream
verify(sender).sendCommandResponse(any(TenantObject.class), any(RegistrationAssertion.class), any(CommandResponse.class), any(SpanContext.class));
// and the device gets a 4.00 response
assertThat(t).isInstanceOf(ClientErrorException.class);
assertThat(((ClientErrorException) t).getErrorCode()).isEqualTo(HttpURLConnection.HTTP_BAD_REQUEST);
// and the response has not been reported as forwarded
verify(metrics, never()).reportCommand(eq(Direction.RESPONSE), eq("tenant"), any(), eq(ProcessingOutcome.FORWARDED), anyInt(), any());
});
ctx.completeNow();
}));
}
use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class CoapContextTest method testStartAckTimerDoesNotStartTimer.
/**
* Verifies that no ACK timer is started for a timeout value <= 0.
*/
@ParameterizedTest
@ValueSource(longs = { -1L, 0L })
void testStartAckTimerDoesNotStartTimer(final long timeout) {
final CoapExchange exchange = mock(CoapExchange.class);
final Adapter coapConfig = new Adapter(Constants.PROTOCOL_ADAPTER_TYPE_COAP);
// never send separate ACK
coapConfig.putExtension(CoapConstants.TIMEOUT_TO_ACK, -1L);
final TenantObject tenant = TenantObject.from("tenant", true).addAdapter(coapConfig);
final Device authenticatedDevice = new Device(tenant.getTenantId(), "device-id");
final CoapContext ctx = CoapContext.fromRequest(exchange, authenticatedDevice, authenticatedDevice, "4711", span);
ctx.startAcceptTimer(vertx, tenant, timeout);
verify(vertx, never()).setTimer(anyLong(), VertxMockSupport.anyHandler());
}
use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class CoapContextTest method testStartAckTimerUsesTenantSpecificTimeout.
/**
* Verifies that the tenant specific value set for the ACK timeout gets
* precedence over the global adapter configuration.
*/
@Test
void testStartAckTimerUsesTenantSpecificTimeout() {
final CoapExchange exchange = mock(CoapExchange.class);
final Adapter coapConfig = new Adapter(Constants.PROTOCOL_ADAPTER_TYPE_COAP);
coapConfig.putExtension(CoapConstants.TIMEOUT_TO_ACK, 200);
final TenantObject tenant = TenantObject.from("tenant", true).addAdapter(coapConfig);
final Device authenticatedDevice = new Device(tenant.getTenantId(), "device-id");
final CoapContext ctx = CoapContext.fromRequest(exchange, authenticatedDevice, authenticatedDevice, "4711", span);
ctx.startAcceptTimer(vertx, tenant, 500);
verify(vertx).setTimer(eq(200L), VertxMockSupport.anyHandler());
}
Aggregations