use of io.vertx.core.Promise in project hono by eclipse.
the class JmsBasedCredentialsClient method sendRequest.
/**
* Sends a request for an operation.
*
* @param tenantId The tenant to send the message for.
* @param operation The name of the operation to invoke or {@code null} if the message
* should not have a subject.
* @param applicationProperties Application properties to set on the request message or
* {@code null} if no properties should be set.
* @param payload Payload to include or {@code null} if the message should have no body.
* @return A future indicating the outcome of the operation.
*/
public Future<CredentialsObject> sendRequest(final String tenantId, final String operation, final Map<String, Object> applicationProperties, final Buffer payload) {
final Message request;
try {
request = createMessage(payload);
addProperties(request, applicationProperties);
if (operation != null) {
request.setJMSType(operation);
}
if (applicationProperties != null) {
for (Map.Entry<String, Object> entry : applicationProperties.entrySet()) {
if (entry.getValue() instanceof String) {
request.setStringProperty(entry.getKey(), (String) entry.getValue());
} else {
request.setObjectProperty(entry.getKey(), entry.getValue());
}
}
}
} catch (final JMSException e) {
return Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, e));
}
final Future<JmsBasedRequestResponseClient<CredentialsResult<CredentialsObject>>> client = JmsBasedRequestResponseClient.forEndpoint(connection, CredentialsConstants.CREDENTIALS_ENDPOINT, tenantId);
return client.compose(c -> c.send(request, this::getResult)).compose(credentialsResult -> {
final Promise<CredentialsObject> result = Promise.promise();
switch(credentialsResult.getStatus()) {
case HttpURLConnection.HTTP_OK:
case HttpURLConnection.HTTP_CREATED:
result.complete(credentialsResult.getPayload());
break;
case HttpURLConnection.HTTP_NOT_FOUND:
result.fail(new ClientErrorException(credentialsResult.getStatus(), "no such credentials"));
break;
default:
result.fail(StatusCodeMapper.from(credentialsResult));
}
return result.future();
});
}
use of io.vertx.core.Promise in project hono by eclipse.
the class TelemetryHttpIT method testUploadQos1MessageFailsIfDeliveryStateNotUpdated.
/**
* Verifies that the upload of a QoS 1 telemetry message fails with a 503 status code
* when the consumer doesn't update the message delivery state and the
* <em>sendMessageTimeout</em> has elapsed.
*
* @param vertx The vert.x instance.
* @param ctx The test context
* @throws InterruptedException if test is interrupted while running.
*/
@Test
@AssumeMessagingSystem(type = MessagingType.amqp)
public void testUploadQos1MessageFailsIfDeliveryStateNotUpdated(final Vertx vertx, final VertxTestContext ctx) throws InterruptedException {
final AmqpApplicationClient amqpApplicationClient = (AmqpApplicationClient) helper.applicationClient;
// GIVEN a device and a north bound message consumer that doesn't update the message delivery state
final Tenant tenant = new Tenant();
final Checkpoint messageReceived = ctx.checkpoint();
final Checkpoint deliveryStateCheckDone = ctx.checkpoint();
final Checkpoint httpResponseReceived = ctx.checkpoint();
final VertxTestContext setup = new VertxTestContext();
final AtomicReference<ProtonDelivery> deliveryRef = new AtomicReference<>();
helper.registry.addDeviceForTenant(tenantId, tenant, deviceId, PWD).compose(ok -> amqpApplicationClient.createTelemetryConsumer(tenantId, msg -> {
final Promise<Void> result = Promise.promise();
final var delivery = msg.getMessageContext().getDelivery();
deliveryRef.set(delivery);
logger.debug("received message: {}", msg.getMessageContext().getRawMessage());
ctx.verify(() -> {
assertThat(delivery.remotelySettled()).isFalse();
assertThat(delivery.getRemoteState()).isNull();
});
messageReceived.flag();
// don't update the delivery state here
return result.future();
}, remoteClose -> {
})).onComplete(setup.succeedingThenComplete());
assertThat(setup.awaitCompletion(IntegrationTestSupport.getTestSetupTimeout(), TimeUnit.SECONDS)).isTrue();
if (setup.failed()) {
ctx.failNow(setup.causeOfFailure());
return;
}
// WHEN the device tries to upload a telemetry message
final MultiMap requestHeaders = MultiMap.caseInsensitiveMultiMap().add(HttpHeaders.CONTENT_TYPE, "binary/octet-stream").add(HttpHeaders.AUTHORIZATION, authorization).add(HttpHeaders.ORIGIN, ORIGIN_URI).add(Constants.HEADER_QOS_LEVEL, "1");
final Future<HttpResponse<Buffer>> httpResponseFuture = httpClient.create(getEndpointUri(), Buffer.buffer("hello"), requestHeaders, // THEN the message gets rejected by the HTTP adapter with a 503
ResponsePredicate.status(HttpURLConnection.HTTP_UNAVAILABLE));
httpResponseFuture.onComplete(ctx.succeeding(response -> {
ctx.verify(() -> {
final var body = response.bodyAsJsonObject();
assertThat(body.getString(RequestResponseApiConstants.FIELD_ERROR)).isEqualTo(ServiceInvocationException.getLocalizedMessage(SendMessageTimeoutException.CLIENT_FACING_MESSAGE_KEY));
});
httpResponseReceived.flag();
// verify that the telemetry message delivery is remotely settled via the timeout handling in the adapter
vertx.setTimer(50, tid -> {
ctx.verify(() -> {
final ProtonDelivery delivery = deliveryRef.get();
assertThat(delivery).isNotNull();
assertThat(delivery.remotelySettled()).isTrue();
assertThat(delivery.getRemoteState()).isNotNull();
assertThat(delivery.getRemoteState().getType()).isEqualTo(DeliveryState.DeliveryStateType.Released);
});
deliveryStateCheckDone.flag();
});
}));
}
use of io.vertx.core.Promise in project hono by eclipse.
the class MqttPublishTestBase method testAutoProvisioningViaGateway.
/**
* Verifies that an edge device is auto-provisioned if it connects via a gateway equipped with the corresponding
* authority.
*
* @param ctx The test context.
* @throws InterruptedException if the test fails.
*/
@Test
public void testAutoProvisioningViaGateway(final VertxTestContext ctx) throws InterruptedException {
final String tenantId = helper.getRandomTenantId();
final Tenant tenant = new Tenant();
final String gatewayId = helper.getRandomDeviceId(tenantId);
final Device gateway = new Device().setAuthorities(Set.of(RegistryManagementConstants.AUTHORITY_AUTO_PROVISIONING_ENABLED));
final String edgeDeviceId = helper.getRandomDeviceId(tenantId);
final Promise<Void> provisioningNotificationReceived = Promise.promise();
helper.createAutoProvisioningMessageConsumers(ctx, provisioningNotificationReceived, tenantId, edgeDeviceId).compose(ok -> helper.registry.addDeviceForTenant(tenantId, tenant, gatewayId, gateway, password)).compose(ok -> connectToAdapter(IntegrationTestSupport.getUsername(gatewayId, tenantId), password)).compose(ok -> {
customizeConnectedClient();
return send(tenantId, edgeDeviceId, Buffer.buffer("hello".getBytes()), false, null);
}).compose(ok -> provisioningNotificationReceived.future()).compose(ok -> helper.registry.getRegistrationInfo(tenantId, edgeDeviceId)).onComplete(ctx.succeeding(registrationResult -> {
ctx.verify(() -> {
final var info = registrationResult.bodyAsJsonObject();
IntegrationTestSupport.assertDeviceStatusProperties(info.getJsonObject(RegistryManagementConstants.FIELD_STATUS), true);
});
ctx.completeNow();
}));
}
use of io.vertx.core.Promise in project hono by eclipse.
the class MqttConnectionIT method testDeviceConnectionIsClosedOnDeviceOrTenantDisabledOrDeleted.
private void testDeviceConnectionIsClosedOnDeviceOrTenantDisabledOrDeleted(final VertxTestContext ctx, final Supplier<Future<?>> deviceRegistryChangeOperation) {
final Promise<Void> connectionClosedPromise = Promise.promise();
// GIVEN a connected device
helper.registry.addDeviceForTenant(tenantId, new Tenant(), deviceId, password).compose(ok -> connectToAdapter(IntegrationTestSupport.getUsername(deviceId, tenantId), password)).compose(conAckMsg -> {
ctx.verify(() -> assertThat(conAckMsg.code()).isEqualTo(MqttConnectReturnCode.CONNECTION_ACCEPTED));
mqttClient.closeHandler(remoteClose -> connectionClosedPromise.complete());
// WHEN corresponding device/tenant is removed/disabled
return deviceRegistryChangeOperation.get();
}).compose(ok -> connectionClosedPromise.future()).onComplete(ctx.succeedingThenComplete());
}
use of io.vertx.core.Promise in project hono by eclipse.
the class CredentialsApiAuthProvider method validateCredentials.
/**
* Verifies that the credentials provided by a device during the authentication
* process match the credentials on record for that device.
*
* @param deviceCredentials The credentials provided by the device.
* @param credentialsOnRecord The credentials to match against.
* @param spanContext The OpenTracing context to use for tracking the operation.
* @return A future that is succeeded with the authenticated device if the
* credentials have been validated successfully. Otherwise, the
* future is failed with a {@link ServiceInvocationException}.
*/
private Future<Device> validateCredentials(final T deviceCredentials, final CredentialsObject credentialsOnRecord, final SpanContext spanContext) {
final Span currentSpan = TracingHelper.buildServerChildSpan(tracer, spanContext, "validate credentials", getClass().getSimpleName()).withTag(MessageHelper.APP_PROPERTY_TENANT_ID, deviceCredentials.getTenantId()).withTag(TracingHelper.TAG_AUTH_ID.getKey(), deviceCredentials.getAuthId()).withTag(TracingHelper.TAG_CREDENTIALS_TYPE.getKey(), deviceCredentials.getType()).start();
final Promise<Device> result = Promise.promise();
if (!deviceCredentials.getAuthId().equals(credentialsOnRecord.getAuthId())) {
currentSpan.log(String.format("Credentials service returned wrong credentials-on-record [auth-id: %s]", credentialsOnRecord.getAuthId()));
result.fail(new ServerErrorException(HttpURLConnection.HTTP_INTERNAL_ERROR));
} else if (!deviceCredentials.getType().equals(credentialsOnRecord.getType())) {
currentSpan.log(String.format("Credentials service returned wrong credentials-on-record [type: %s]", credentialsOnRecord.getType()));
result.fail(new ServerErrorException(HttpURLConnection.HTTP_INTERNAL_ERROR));
} else if (!credentialsOnRecord.isEnabled()) {
currentSpan.log("credentials-on-record are disabled");
result.fail(new ClientErrorException(HttpURLConnection.HTTP_UNAUTHORIZED));
} else {
doValidateCredentials(deviceCredentials, credentialsOnRecord).onComplete(result);
}
return result.future().map(device -> {
currentSpan.log("validation of credentials succeeded");
currentSpan.finish();
return device;
}).recover(t -> {
currentSpan.log("validation of credentials failed");
TracingHelper.logError(currentSpan, t);
currentSpan.finish();
return Future.failedFuture(t);
});
}
Aggregations