use of org.eclipse.hono.util.Adapter in project hono by eclipse.
the class HttpTestBase method testUploadMessageFailsForUnauthorizedGateway.
/**
* Verifies that the HTTP adapter rejects messages from a gateway for an device that it is not authorized for with a
* 403.
*
* @param ctx The test context
*/
@Test
@Timeout(timeUnit = TimeUnit.SECONDS, value = 20)
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.addDeviceForTenant(tenantId, tenant, gatewayId, PWD).compose(ok -> helper.registry.registerDevice(tenantId, deviceId, deviceData)).compose(ok -> {
// WHEN another gateway tries to upload a message for the device
final MultiMap requestHeaders = MultiMap.caseInsensitiveMultiMap().add(HttpHeaders.CONTENT_TYPE, "text/plain").add(HttpHeaders.AUTHORIZATION, getBasicAuth(tenantId, gatewayId, PWD));
return httpClient.update(String.format("%s/%s/%s", getEndpointUri(), tenantId, deviceId), Buffer.buffer("hello"), requestHeaders, ResponsePredicate.status(HttpURLConnection.HTTP_FORBIDDEN));
}).onComplete(ctx.succeedingThenComplete());
}
use of org.eclipse.hono.util.Adapter in project hono by eclipse.
the class HttpTestBase method testUploadMessagesViaGateway.
/**
* Verifies that a number of messages uploaded to the HTTP adapter via a gateway using HTTP Basic auth can be
* successfully consumed via the AMQP Messaging Network.
*
* @param ctx The test context.
* @throws InterruptedException if the test fails.
*/
@Test
public void testUploadMessagesViaGateway(final VertxTestContext ctx) throws InterruptedException {
// GIVEN a device that is connected via two gateways
final Tenant tenant = new Tenant();
final String gatewayOneId = helper.getRandomDeviceId(tenantId);
final String gatewayTwoId = helper.getRandomDeviceId(tenantId);
final Device device = new Device();
device.setVia(Arrays.asList(gatewayOneId, gatewayTwoId));
final VertxTestContext setup = new VertxTestContext();
helper.registry.addDeviceForTenant(tenantId, tenant, gatewayOneId, PWD).compose(ok -> helper.registry.addDeviceToTenant(tenantId, gatewayTwoId, PWD)).compose(ok -> helper.registry.registerDevice(tenantId, deviceId, device)).onComplete(setup.succeedingThenComplete());
assertThat(setup.awaitCompletion(5, TimeUnit.SECONDS)).isTrue();
if (setup.failed()) {
ctx.failNow(setup.causeOfFailure());
return;
}
final MultiMap requestHeadersOne = MultiMap.caseInsensitiveMultiMap().add(HttpHeaders.CONTENT_TYPE, "text/plain").add(HttpHeaders.AUTHORIZATION, getBasicAuth(tenantId, gatewayOneId, PWD)).add(HttpHeaders.ORIGIN, ORIGIN_URI);
final MultiMap requestHeadersTwo = MultiMap.caseInsensitiveMultiMap().add(HttpHeaders.CONTENT_TYPE, "text/plain").add(HttpHeaders.AUTHORIZATION, getBasicAuth(tenantId, gatewayTwoId, PWD)).add(HttpHeaders.ORIGIN, ORIGIN_URI);
final String uri = String.format("%s/%s/%s", getEndpointUri(), tenantId, deviceId);
testUploadMessages(ctx, tenantId, count -> {
final MultiMap headers = (count.intValue() & 1) == 0 ? requestHeadersOne : requestHeadersTwo;
return // GW uses PUT when acting on behalf of a device
httpClient.update(uri, Buffer.buffer("hello " + count), headers, ResponsePredicate.status(HttpURLConnection.HTTP_ACCEPTED));
});
}
use of org.eclipse.hono.util.Adapter in project hono by eclipse.
the class HttpTestBase method testConnectSucceedsWithAutoProvisioning.
/**
* Verifies that the adapter opens a connection if auto-provisioning is enabled for the device certificate.
*
* @param ctx The test context.
* @throws InterruptedException if the test fails.
*/
@Test
public void testConnectSucceedsWithAutoProvisioning(final VertxTestContext ctx) throws InterruptedException {
final VertxTestContext setup = new VertxTestContext();
final MultiMap requestHeaders = MultiMap.caseInsensitiveMultiMap().add(HttpHeaders.CONTENT_TYPE, "text/plain").add(HttpHeaders.ORIGIN, ORIGIN_URI);
helper.getCertificate(deviceCert.certificatePath()).compose(cert -> {
// GIVEN a tenant configured for auto-provisioning
final var tenant = Tenants.createTenantForTrustAnchor(cert);
tenant.getTrustedCertificateAuthorities().get(0).setAutoProvisioningEnabled(true);
return helper.registry.addTenant(tenantId, tenant);
}).onComplete(setup.succeedingThenComplete());
assertThat(setup.awaitCompletion(5, TimeUnit.SECONDS)).isTrue();
if (setup.failed()) {
ctx.failNow(setup.causeOfFailure());
return;
}
testUploadMessages(ctx, tenantId, null, count -> httpClientWithClientCert.create(getEndpointUri(), Buffer.buffer("hello " + count), requestHeaders, ResponsePredicate.status(HttpURLConnection.HTTP_ACCEPTED)).compose(this::verifyAccessControlExposedHeaders), 5, null);
}
use of org.eclipse.hono.util.Adapter in project hono by eclipse.
the class HttpTestBase method testHandleConcurrentUploadWithTtd.
/**
* Verifies that for two consecutive upload requests containing a TTD, sent in close succession so that the command
* triggered by the first request isn't sent before the adapter has received the second upload request, the HTTP
* adapter returns the command as response to the second upload request.
*
* @param ctx The test context.
* @throws InterruptedException if the test is interrupted before having completed.
*/
@Test
@Timeout(timeUnit = TimeUnit.SECONDS, value = 20)
public void testHandleConcurrentUploadWithTtd(final VertxTestContext ctx) throws InterruptedException {
final Tenant tenant = new Tenant();
final CountDownLatch firstMessageReceived = new CountDownLatch(1);
final CountDownLatch secondMessageReceived = new CountDownLatch(1);
// GIVEN a registered device
final VertxTestContext setup = new VertxTestContext();
helper.registry.addDeviceForTenant(tenantId, tenant, deviceId, PWD).compose(ok -> createConsumer(tenantId, msg -> {
logger.trace("received message: {}", msg);
msg.getTimeUntilDisconnectNotification().ifPresent(notification -> {
logger.debug("processing piggy backed message [ttd: {}]", notification.getTtd());
ctx.verify(() -> {
assertThat(notification.getTenantId()).isEqualTo(tenantId);
assertThat(notification.getDeviceId()).isEqualTo(deviceId);
});
});
switch(msg.getContentType()) {
case "text/msg1":
logger.debug("received first message");
firstMessageReceived.countDown();
break;
case "text/msg2":
logger.debug("received second message");
secondMessageReceived.countDown();
break;
default:
}
})).compose(c -> {
// might fail immediately because the link has not been established yet.
return httpClient.create(getEndpointUri(), Buffer.buffer("trigger msg"), MultiMap.caseInsensitiveMultiMap().add(HttpHeaders.CONTENT_TYPE, "application/trigger").add(HttpHeaders.AUTHORIZATION, authorization).add(HttpHeaders.ORIGIN, ORIGIN_URI).add(Constants.HEADER_QOS_LEVEL, "1"), ResponsePredicate.status(200, 300));
}).onComplete(setup.succeedingThenComplete());
assertThat(setup.awaitCompletion(5, TimeUnit.SECONDS)).isTrue();
if (setup.failed()) {
ctx.failNow(setup.causeOfFailure());
return;
}
// WHEN the device sends a first upload request
MultiMap requestHeaders = MultiMap.caseInsensitiveMultiMap().add(HttpHeaders.CONTENT_TYPE, "text/msg1").add(HttpHeaders.AUTHORIZATION, authorization).add(HttpHeaders.ORIGIN, ORIGIN_URI).add(Constants.HEADER_TIME_TILL_DISCONNECT, "10");
final Future<HttpResponse<Buffer>> firstRequest = httpClient.create(getEndpointUri(), Buffer.buffer("hello one"), requestHeaders, ResponsePredicate.status(200, 300)).map(httpResponse -> {
logger.info("received response to first request");
return httpResponse;
});
logger.info("sent first request");
if (!firstMessageReceived.await(5, TimeUnit.SECONDS)) {
ctx.failNow(new IllegalStateException("first message not received in time"));
}
// followed by a second request
requestHeaders = MultiMap.caseInsensitiveMultiMap().add(HttpHeaders.CONTENT_TYPE, "text/msg2").add(HttpHeaders.AUTHORIZATION, authorization).add(HttpHeaders.ORIGIN, ORIGIN_URI).add(Constants.HEADER_TIME_TILL_DISCONNECT, "5");
final Future<HttpResponse<Buffer>> secondRequest = httpClient.create(getEndpointUri(), Buffer.buffer("hello two"), requestHeaders, ResponsePredicate.status(200, 300)).map(httpResponse -> {
logger.info("received response to second request");
return httpResponse;
});
logger.info("sent second request");
// wait for messages having been received
if (!secondMessageReceived.await(5, TimeUnit.SECONDS)) {
ctx.failNow(new IllegalStateException("second message not received in time"));
}
// send command
final JsonObject inputData = new JsonObject().put(COMMAND_JSON_KEY, (int) (Math.random() * 100));
final Future<Void> commandSent = helper.sendOneWayCommand(tenantId, deviceId, COMMAND_TO_SEND, "application/json", inputData.toBuffer(), 3000);
logger.info("sent one-way command to device");
// THEN both requests succeed
CompositeFuture.all(commandSent, firstRequest, secondRequest).onComplete(ctx.succeeding(ok -> {
ctx.verify(() -> {
// and the response to the second request contains a command
assertThat(secondRequest.result().getHeader(Constants.HEADER_COMMAND)).isEqualTo(COMMAND_TO_SEND);
// while the response to the first request is empty
assertThat(firstRequest.result().getHeader(Constants.HEADER_COMMAND)).isNull();
});
ctx.completeNow();
}));
}
use of org.eclipse.hono.util.Adapter in project hono by eclipse.
the class HttpTestBase method testUploadMessagesWithTtdThatReplyWithOneWayCommand.
/**
* Verifies that the HTTP adapter delivers a command to a device and accepts the corresponding
* response from the device.
*
* @param endpointConfig The endpoints to use for sending/receiving commands.
* @param ctx The test context.
* @throws InterruptedException if the test fails.
*/
@ParameterizedTest(name = IntegrationTestSupport.PARAMETERIZED_TEST_NAME_PATTERN)
@MethodSource("commandAndControlVariants")
public void testUploadMessagesWithTtdThatReplyWithOneWayCommand(final HttpCommandEndpointConfiguration endpointConfig, final VertxTestContext ctx) throws InterruptedException {
final Tenant tenant = new Tenant();
final VertxTestContext setup = new VertxTestContext();
final MultiMap requestHeaders = MultiMap.caseInsensitiveMultiMap().add(HttpHeaders.CONTENT_TYPE, "text/plain").add(HttpHeaders.AUTHORIZATION, authorization).add(HttpHeaders.ORIGIN, ORIGIN_URI).add(Constants.HEADER_TIME_TILL_DISCONNECT, "4");
helper.registry.addDeviceForTenant(tenantId, tenant, deviceId, PWD).onComplete(setup.succeedingThenComplete());
assertThat(setup.awaitCompletion(5, TimeUnit.SECONDS)).isTrue();
if (setup.failed()) {
ctx.failNow(setup.causeOfFailure());
return;
}
final String commandTargetDeviceId = endpointConfig.isSubscribeAsGateway() ? helper.setupGatewayDeviceBlocking(tenantId, deviceId, 5) : deviceId;
final String subscribingDeviceId = endpointConfig.isSubscribeAsGatewayForSingleDevice() ? commandTargetDeviceId : deviceId;
testUploadMessages(ctx, tenantId, msg -> {
return msg.getTimeUntilDisconnectNotification().map(notification -> {
logger.trace("received piggy backed message [ttd: {}]: {}", notification.getTtd(), msg);
ctx.verify(() -> {
assertThat(notification.getTenantId()).isEqualTo(tenantId);
assertThat(notification.getDeviceId()).isEqualTo(subscribingDeviceId);
});
// now ready to send a command
final JsonObject inputData = new JsonObject().put(COMMAND_JSON_KEY, (int) (Math.random() * 100));
return helper.sendOneWayCommand(tenantId, commandTargetDeviceId, COMMAND_TO_SEND, "application/json", inputData.toBuffer(), notification.getMillisecondsUntilExpiry());
}).orElseGet(Future::succeededFuture);
}, count -> {
final Buffer payload = Buffer.buffer("hello " + count);
return sendHttpRequestForGatewayOrDevice(payload, requestHeaders, endpointConfig, commandTargetDeviceId, true).map(httpResponse -> {
ctx.verify(() -> {
// assert that the response contains a one-way command
assertWithMessage("response no. %s '%s' header", count, Constants.HEADER_COMMAND).that(httpResponse.getHeader(Constants.HEADER_COMMAND)).isNotNull();
assertThat(httpResponse.getHeader(Constants.HEADER_COMMAND)).isEqualTo(COMMAND_TO_SEND);
assertThat(httpResponse.getHeader(HttpHeaders.CONTENT_TYPE.toString())).isEqualTo("application/json");
assertThat(httpResponse.getHeader(Constants.HEADER_COMMAND_REQUEST_ID)).isNull();
});
return httpResponse;
});
});
}
Aggregations