use of org.eclipse.hono.util.Adapter in project hono by eclipse.
the class AbstractVertxBasedHttpProtocolAdapterTest method testUploadCommandResponseFailsForOtherDevice.
/**
* Verifies that an authenticated device that is not a gateway fails to
* upload a command response for another device.
*/
@Test
public void testUploadCommandResponseFailsForOtherDevice() {
givenAnAdapter(properties);
final Buffer payload = Buffer.buffer("some payload");
final HttpContext ctx = newHttpContext(payload, "application/text", mock(HttpServerRequest.class), mock(HttpServerResponse.class));
final TenantObject to = TenantObject.from("tenant", true);
// Given an adapter that is enabled for a device's tenant
to.addAdapter(new Adapter(ADAPTER_TYPE).setEnabled(Boolean.TRUE));
when(tenantClient.get(eq("tenant"), (SpanContext) any())).thenReturn(Future.succeededFuture(to));
// which is connected to a Credentials service that has credentials on record for device 9999
when(ctx.getAuthenticatedDevice()).thenReturn(new DeviceUser("tenant", "9999"));
// but for which no registration information is available
when(registrationClient.assertRegistration(anyString(), anyString(), any(), any())).thenReturn(Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_NOT_FOUND, "cannot publish data for device of other tenant")));
adapter.uploadCommandResponseMessage(ctx, "tenant", "device", CMD_REQ_ID, 200);
// Then the device gets a 404
assertContextFailedWithClientError(ctx, HttpURLConnection.HTTP_NOT_FOUND);
// and the response has not been reported as forwarded
verify(metrics).reportCommand(eq(Direction.RESPONSE), eq("tenant"), eq(to), eq(ProcessingOutcome.UNPROCESSABLE), eq(payload.length()), any());
}
use of org.eclipse.hono.util.Adapter in project hono by eclipse.
the class AbstractVertxBasedHttpProtocolAdapterTest method testUploadCommandResponseFailsForDisabledTenant.
/**
* Verifies that the adapter fails the upload of a command response with a 403
* if the adapter is disabled for the device's tenant.
*/
@Test
public void testUploadCommandResponseFailsForDisabledTenant() {
// GIVEN an adapter that is not enabled for a device's tenant
final TenantObject to = TenantObject.from("tenant", true);
to.addAdapter(new Adapter(Constants.PROTOCOL_ADAPTER_TYPE_HTTP).setEnabled(Boolean.FALSE));
when(tenantClient.get(eq("tenant"), (SpanContext) any())).thenReturn(Future.succeededFuture(to));
givenAnAdapter(properties);
// WHEN a device publishes a command response
final Buffer payload = Buffer.buffer("some payload");
final HttpContext ctx = newHttpContext(payload, "application/text", mock(HttpServerRequest.class), mock(HttpServerResponse.class));
adapter.uploadCommandResponseMessage(ctx, "tenant", "device", CMD_REQ_ID, 200);
// THEN the device gets a 403
assertContextFailedWithClientError(ctx, HttpURLConnection.HTTP_FORBIDDEN);
// and the response has been reported as undeliverable
verify(metrics).reportCommand(eq(Direction.RESPONSE), eq("tenant"), eq(to), eq(ProcessingOutcome.UNPROCESSABLE), eq(payload.length()), any());
}
use of org.eclipse.hono.util.Adapter in project hono by eclipse.
the class CoapTestBase method testUploadMessagesUsingClientCertificate.
/**
* Verifies that a number of messages uploaded to Hono's CoAP adapter using TLS_ECDSA based authentication can be
* successfully consumed via the messaging infrastructure.
*
* @param ctx The test context.
* @throws InterruptedException if the test fails.
*/
@Test
public void testUploadMessagesUsingClientCertificate(final VertxTestContext ctx) throws InterruptedException {
final var clientCertLoader = KeyLoader.fromFiles(vertx, PATH_DEVICE_KEY, PATH_DEVICE_CERT);
final var clientCert = (X509Certificate) clientCertLoader.getCertificateChain()[0];
final VertxTestContext setup = new VertxTestContext();
helper.getCertificate(PATH_CA_CERT).compose(caCert -> {
final var tenant = Tenants.createTenantForTrustAnchor(caCert);
return helper.registry.addDeviceForTenant(tenantId, tenant, deviceId, clientCert);
}).onComplete(setup.succeedingThenComplete());
assertThat(setup.awaitCompletion(5, TimeUnit.SECONDS)).isTrue();
if (setup.failed()) {
ctx.failNow(setup.causeOfFailure());
return;
}
final CoapClient client = getCoapsClient(clientCertLoader);
testUploadMessages(ctx, tenantId, () -> warmUp(client, createCoapsRequest(Code.POST, getPostResource(), 0)), count -> {
final Promise<OptionSet> result = Promise.promise();
final Request request = createCoapsRequest(Code.POST, getPostResource(), count);
client.advanced(getHandler(result), request);
return result.future();
});
}
use of org.eclipse.hono.util.Adapter in project hono by eclipse.
the class CoapTestBase method testUploadMessageFailsForUnauthorizedGateway.
/**
* Verifies that the CoAP adapter rejects messages from a gateway for a device that it is not authorized for with a
* 403.
*
* @param ctx The test context
*/
@Test
@Timeout(value = 10, timeUnit = TimeUnit.SECONDS)
public void testUploadMessageFailsForUnauthorizedGateway(final VertxTestContext ctx) {
// GIVEN a device that is connected via gateway "not-the-created-gateway"
final Tenant tenant = new Tenant();
final String gatewayId = helper.getRandomDeviceId(tenantId);
final Device deviceData = new Device();
deviceData.setVia(Collections.singletonList("not-the-created-gateway"));
helper.registry.addPskDeviceForTenant(tenantId, tenant, gatewayId, SECRET).compose(ok -> helper.registry.registerDevice(tenantId, deviceId, deviceData)).compose(ok -> {
// WHEN another gateway tries to upload a message for the device
final Promise<OptionSet> result = Promise.promise();
final CoapClient client = getCoapsClient(gatewayId, tenantId, SECRET);
// THEN a FORBIDDEN response code is returned
client.advanced(getHandler(result, ResponseCode.FORBIDDEN), createCoapsRequest(Code.PUT, getPutResource(tenantId, deviceId), 0));
return result.future();
}).onComplete(ctx.succeedingThenComplete());
}
use of org.eclipse.hono.util.Adapter in project hono by eclipse.
the class CoapTestBase method testUploadMessages.
/**
* Uploads messages to the CoAP endpoint.
*
* @param ctx The test context to run on.
* @param tenantId The tenant that the device belongs to.
* @param warmUp A sender of messages used to warm up the adapter before running the test itself or {@code null} if
* no warm up should be performed.
* @param messageConsumer Consumer that is invoked when a message was received.
* @param requestSender The test device that will publish the data.
* @param numberOfMessages The number of messages that are uploaded.
* @param expectedQos The expected QoS level, may be {@code null} leading to expecting the default for event or telemetry.
* @throws InterruptedException if the test is interrupted before it has finished.
*/
protected void testUploadMessages(final VertxTestContext ctx, final String tenantId, final Supplier<Future<Void>> warmUp, final Consumer<DownstreamMessage<? extends MessageContext>> messageConsumer, final Function<Integer, Future<OptionSet>> requestSender, final int numberOfMessages, final QoS expectedQos) throws InterruptedException {
final CountDownLatch received = new CountDownLatch(numberOfMessages);
final VertxTestContext setup = new VertxTestContext();
createConsumer(tenantId, msg -> {
ctx.verify(() -> {
logger.trace("received {}", msg);
DownstreamMessageAssertions.assertTelemetryMessageProperties(msg, tenantId);
assertThat(msg.getQos()).isEqualTo(getExpectedQoS(expectedQos));
assertAdditionalMessageProperties(msg);
if (messageConsumer != null) {
messageConsumer.accept(msg);
}
});
received.countDown();
if (received.getCount() % 20 == 0) {
logger.info("messages received: {}", numberOfMessages - received.getCount());
}
}).compose(ok -> Optional.ofNullable(warmUp).map(w -> w.get()).orElseGet(() -> Future.succeededFuture())).onComplete(setup.succeedingThenComplete());
ctx.verify(() -> assertThat(setup.awaitCompletion(5, TimeUnit.SECONDS)).isTrue());
final long start = System.currentTimeMillis();
final AtomicInteger messageCount = new AtomicInteger(0);
while (messageCount.get() < numberOfMessages && !ctx.failed()) {
final CountDownLatch sending = new CountDownLatch(1);
requestSender.apply(messageCount.getAndIncrement()).compose(this::assertCoapResponse).onComplete(attempt -> {
if (attempt.succeeded()) {
logger.debug("sent message {}", messageCount.get());
} else {
logger.info("failed to send message {}: {}", messageCount.get(), attempt.cause().getMessage());
ctx.failNow(attempt.cause());
}
sending.countDown();
});
if (messageCount.get() % 20 == 0) {
logger.info("messages sent: {}", messageCount.get());
}
sending.await();
}
if (ctx.failed()) {
return;
}
final long timeToWait = Math.max(TEST_TIMEOUT_MILLIS - 1000, Math.round(numberOfMessages * 20));
if (received.await(timeToWait, TimeUnit.MILLISECONDS)) {
logger.info("sent {} and received {} messages after {} milliseconds", messageCount, numberOfMessages - received.getCount(), System.currentTimeMillis() - start);
ctx.completeNow();
} else {
logger.info("sent {} and received {} messages after {} milliseconds", messageCount, numberOfMessages - received.getCount(), System.currentTimeMillis() - start);
ctx.failNow(new AssertionError("did not receive all messages sent"));
}
}
Aggregations