use of org.eclipse.hono.util.RegistrationAssertion in project hono by eclipse.
the class CommandTargetMapperImpl method getTargetGatewayAndAdapterInstance.
@Override
public final Future<JsonObject> getTargetGatewayAndAdapterInstance(final String tenantId, final String deviceId, final SpanContext context) {
Objects.requireNonNull(tenantId);
Objects.requireNonNull(deviceId);
final Span span = TracingHelper.buildChildSpan(tracer, context, "get target gateway and adapter instance", CommandTargetMapper.class.getSimpleName()).withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CONSUMER).withTag(TracingHelper.TAG_TENANT_ID, tenantId).withTag(TracingHelper.TAG_DEVICE_ID, deviceId).start();
return registrationClient.assertRegistration(tenantId, deviceId, null, span.context()).map(RegistrationAssertion::getAuthorizedGateways).recover(t -> {
LOG.debug("Error retrieving gateways authorized to act on behalf of device [tenant-id: {}, device-id: {}]", tenantId, deviceId, t);
return Future.failedFuture(ServiceInvocationException.extractStatusCode(t) == HttpURLConnection.HTTP_NOT_FOUND ? new DeviceDisabledOrNotRegisteredException(tenantId, HttpURLConnection.HTTP_NOT_FOUND) : t);
}).compose(viaGateways -> {
return deviceConnectionInfo.getCommandHandlingAdapterInstances(tenantId, deviceId, new HashSet<>(viaGateways), span).compose(resultJson -> determineTargetInstanceJson(resultJson, deviceId, viaGateways, span));
}).onFailure(t -> {
LOG.debug("Error getting target gateway and adapter instance", t);
TracingHelper.logError(span, t);
Tags.HTTP_STATUS.set(span, ServiceInvocationException.extractStatusCode(t));
}).onComplete(ar -> span.finish());
}
use of org.eclipse.hono.util.RegistrationAssertion in project hono by eclipse.
the class KafkaBasedCommandResponseSenderTest method testIfValidCommandResponseKafkaRecordIsSent.
@Test
void testIfValidCommandResponseKafkaRecordIsSent(final VertxTestContext ctx, final Vertx vertx) {
// GIVEN a command response sender
final String tenantId = "test-tenant";
final String deviceId = "test-device";
final String correlationId = UUID.randomUUID().toString();
final String contentType = "text/plain";
final String payload = "the-payload";
final int status = 200;
final String additionalHeader1Name = "testHeader1";
final String additionalHeader1Value = "testHeader1Value";
final String additionalHeader2Name = "testHeader2";
final String additionalHeader2Value = "testHeader2Value";
final Map<String, Object> additionalProperties = Map.of(additionalHeader1Name, additionalHeader1Value, additionalHeader2Name, additionalHeader2Value);
final CommandResponse commandResponse = CommandResponse.fromAddressAndCorrelationId(String.format("%s/%s/%s", CommandConstants.COMMAND_RESPONSE_ENDPOINT, tenantId, Commands.getDeviceFacingReplyToId("", deviceId, MessagingType.kafka)), correlationId, Buffer.buffer(payload), contentType, status);
commandResponse.setAdditionalProperties(additionalProperties);
final Span span = TracingMockSupport.mockSpan();
final Tracer tracer = TracingMockSupport.mockTracer(span);
final var mockProducer = KafkaClientUnitTestHelper.newMockProducer(true);
final var factory = CachingKafkaProducerFactory.testFactory(vertx, (n, c) -> KafkaClientUnitTestHelper.newKafkaProducer(mockProducer));
final var sender = new KafkaBasedCommandResponseSender(vertx, factory, kafkaProducerConfig, tracer);
final TenantObject tenant = TenantObject.from(tenantId);
tenant.setResourceLimits(new ResourceLimits().setMaxTtlCommandResponse(10L));
// WHEN sending a command response
sender.sendCommandResponse(tenant, new RegistrationAssertion(deviceId), commandResponse, NoopSpan.INSTANCE.context()).onComplete(ctx.succeeding(t -> {
ctx.verify(() -> {
// THEN the producer record is created from the given values...
final ProducerRecord<String, Buffer> record = mockProducer.history().get(0);
assertThat(record.key()).isEqualTo(deviceId);
assertThat(record.topic()).isEqualTo(new HonoTopic(HonoTopic.Type.COMMAND_RESPONSE, tenantId).toString());
assertThat(record.value().toString()).isEqualTo(payload);
// Verify if the record contains the necessary headers.
final Headers headers = record.headers();
KafkaClientUnitTestHelper.assertUniqueHeaderWithExpectedValue(headers, MessageHelper.APP_PROPERTY_TENANT_ID, tenantId);
KafkaClientUnitTestHelper.assertUniqueHeaderWithExpectedValue(headers, MessageHelper.APP_PROPERTY_DEVICE_ID, deviceId);
KafkaClientUnitTestHelper.assertUniqueHeaderWithExpectedValue(headers, MessageHelper.SYS_PROPERTY_CORRELATION_ID, correlationId);
KafkaClientUnitTestHelper.assertUniqueHeaderWithExpectedValue(headers, MessageHelper.APP_PROPERTY_STATUS, status);
KafkaClientUnitTestHelper.assertUniqueHeaderWithExpectedValue(headers, MessageHelper.SYS_PROPERTY_CONTENT_TYPE, contentType);
final var creationTimeHeader = headers.headers(MessageHelper.SYS_PROPERTY_CREATION_TIME);
assertThat(creationTimeHeader).hasSize(1);
final Long creationTimeMillis = Json.decodeValue(Buffer.buffer(creationTimeHeader.iterator().next().value()), Long.class);
assertThat(creationTimeMillis).isGreaterThan(0L);
KafkaClientUnitTestHelper.assertUniqueHeaderWithExpectedValue(headers, MessageHelper.SYS_HEADER_PROPERTY_TTL, 10000L);
KafkaClientUnitTestHelper.assertUniqueHeaderWithExpectedValue(headers, additionalHeader1Name, additionalHeader1Value);
KafkaClientUnitTestHelper.assertUniqueHeaderWithExpectedValue(headers, additionalHeader2Name, additionalHeader2Value);
verify(span).finish();
});
ctx.completeNow();
}));
}
use of org.eclipse.hono.util.RegistrationAssertion in project hono by eclipse.
the class KafkaBasedCommandContext method sendDeliveryFailureCommandResponseMessage.
private Future<Void> sendDeliveryFailureCommandResponseMessage(final int status, final String error, final Span span, final Throwable cause) {
final JsonObject payloadJson = new JsonObject();
payloadJson.put("error", error != null ? error : "");
final String correlationId = getCorrelationId();
if (correlationId == null) {
TracingHelper.logError(span, "can't send command response message - no correlation id set");
return Future.failedFuture("missing correlation id");
}
final CommandResponse commandResponse = new CommandResponse(command.getTenant(), command.getDeviceId(), payloadJson.toBuffer(), CommandConstants.CONTENT_TYPE_DELIVERY_FAILURE_NOTIFICATION, status, correlationId, "", MessagingType.kafka);
commandResponse.setAdditionalProperties(Collections.unmodifiableMap(command.getDeliveryFailureNotificationProperties()));
return commandResponseSender.sendCommandResponse(// try to retrieve tenant configuration from context
Optional.ofNullable(get(KEY_TENANT_CONFIG)).filter(TenantObject.class::isInstance).map(TenantObject.class::cast).orElseGet(() -> TenantObject.from(command.getTenant())), new RegistrationAssertion(command.getDeviceId()), commandResponse, span.context()).onFailure(thr -> {
LOG.debug("failed to publish command response [{}]", commandResponse, thr);
TracingHelper.logError(span, "failed to publish command response message", thr);
}).onSuccess(v -> {
LOG.debug("published error command response [{}, cause: {}]", commandResponse, cause != null ? cause.getMessage() : error);
span.log("published error command response");
});
}
use of org.eclipse.hono.util.RegistrationAssertion in project hono by eclipse.
the class AbstractProtocolAdapterBase method sendTtdEvent.
@Override
public final Future<Void> sendTtdEvent(final String tenant, final String deviceId, final Device authenticatedDevice, final Integer ttd, final SpanContext context) {
Objects.requireNonNull(tenant);
Objects.requireNonNull(deviceId);
Objects.requireNonNull(ttd);
final Future<RegistrationAssertion> tokenTracker = getRegistrationAssertion(tenant, deviceId, authenticatedDevice, context);
final Future<TenantObject> tenantConfigTracker = getTenantConfiguration(tenant, context);
return CompositeFuture.all(tokenTracker, tenantConfigTracker).compose(ok -> {
if (tenantConfigTracker.result().isAdapterEnabled(getTypeName())) {
final Map<String, Object> props = new HashMap<>();
props.put(MessageHelper.APP_PROPERTY_ORIG_ADAPTER, getTypeName());
props.put(MessageHelper.APP_PROPERTY_QOS, QoS.AT_LEAST_ONCE.ordinal());
props.put(MessageHelper.APP_PROPERTY_DEVICE_TTD, ttd);
return getEventSender(tenantConfigTracker.result()).sendEvent(tenantConfigTracker.result(), tokenTracker.result(), EventConstants.CONTENT_TYPE_EMPTY_NOTIFICATION, null, props, context).onSuccess(s -> log.debug("successfully sent TTD notification [tenant: {}, device-id: {}, TTD: {}]", tenant, deviceId, ttd)).onFailure(t -> log.debug("failed to send TTD notification [tenant: {}, device-id: {}, TTD: {}]", tenant, deviceId, ttd, t));
} else {
// this adapter is not enabled for the tenant
return Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_FORBIDDEN));
}
});
}
use of org.eclipse.hono.util.RegistrationAssertion in project hono by eclipse.
the class ProtonBasedCommandResponseSenderTest method testCommandResponseMessageHasCreationTimeAndTtl.
/**
* Verifies that command response messages being sent downstream contain a creation-time
* and a time-to-live as defined at the tenant level.
*/
@Test
public void testCommandResponseMessageHasCreationTimeAndTtl() {
final var now = Instant.now();
final TenantObject tenant = TenantObject.from(TENANT_ID);
tenant.setResourceLimits(new ResourceLimits().setMaxTtlCommandResponse(10L));
when(protonSender.sendQueueFull()).thenReturn(Boolean.FALSE);
when(protonSender.send(any(Message.class), VertxMockSupport.anyHandler())).thenReturn(mock(ProtonDelivery.class));
// WHEN sending a command response message
final CommandResponse commandResponse = CommandResponse.fromRequestId(Commands.encodeRequestIdParameters(CORRELATION_ID, REPLY_TO_ID, DEVICE_ID, MessagingType.amqp), TENANT_ID, DEVICE_ID, null, null, HttpURLConnection.HTTP_OK);
sender.sendCommandResponse(tenant, new RegistrationAssertion(DEVICE_ID), commandResponse, span.context());
final ArgumentCaptor<Message> downstreamMessage = ArgumentCaptor.forClass(Message.class);
verify(protonSender).send(downstreamMessage.capture(), VertxMockSupport.anyHandler());
// THEN the message being sent contains a creation-time
assertThat(downstreamMessage.getValue().getCreationTime()).isAtLeast(now.toEpochMilli());
// and a TTL
assertThat(downstreamMessage.getValue().getTtl()).isEqualTo(10_000L);
// and a 200 status code
assertThat(MessageHelper.getStatus(downstreamMessage.getValue())).isEqualTo(HttpURLConnection.HTTP_OK);
}
Aggregations