use of org.eclipse.hono.client.command.CommandResponseSender in project hono by eclipse.
the class CommandResponseResourceTest method testUploadCommandResponseWaitsForAcceptedOutcome.
/**
* Verifies that the adapter waits for a command response being successfully sent
* downstream before responding with a 2.04 status to the device.
*
* @param ctx The vert.x test context.
*/
@Test
public void testUploadCommandResponseWaitsForAcceptedOutcome(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);
// THEN the command response is being forwarded downstream
verify(sender).sendCommandResponse(any(TenantObject.class), any(RegistrationAssertion.class), any(CommandResponse.class), any(SpanContext.class));
// but the device does not get a response
verify(coapExchange, never()).respond(any(Response.class));
// and the response has not been reported as forwarded
verify(metrics, never()).reportCommand(eq(Direction.RESPONSE), eq("tenant"), any(), eq(ProcessingOutcome.FORWARDED), anyInt(), any());
// until the message has been accepted
outcome.complete();
result.onComplete(ctx.succeeding(code -> {
ctx.verify(() -> {
verify(coapExchange).respond(argThat((Response res) -> res.getCode() == ResponseCode.CHANGED));
verify(metrics).reportCommand(eq(Direction.RESPONSE), eq("tenant"), any(), eq(ProcessingOutcome.FORWARDED), eq(payload.length()), any());
});
ctx.completeNow();
}));
}
use of org.eclipse.hono.client.command.CommandResponseSender in project hono by eclipse.
the class VertxBasedAmqpProtocolAdapterTest method testUploadCommandResponseSucceeds.
/**
* Verify that the AMQP adapter forwards command responses downstream.
*
* @param ctx The vert.x test context.
*/
@Test
public void testUploadCommandResponseSucceeds(final VertxTestContext ctx) {
// GIVEN an AMQP adapter
givenAnAdapter(properties);
final CommandResponseSender responseSender = givenACommandResponseSenderForAnyTenant();
when(responseSender.sendCommandResponse(any(TenantObject.class), any(RegistrationAssertion.class), any(CommandResponse.class), (SpanContext) any())).thenReturn(Future.succeededFuture());
// which is enabled for the test tenant
final TenantObject tenantObject = givenAConfiguredTenant(TEST_TENANT_ID, true);
// WHEN an unauthenticated device publishes a command response
final String replyToAddress = String.format("%s/%s/%s", getCommandResponseEndpoint(), TEST_TENANT_ID, Commands.getDeviceFacingReplyToId("test-reply-id", TEST_DEVICE, MessagingType.amqp));
final Map<String, Object> propertyMap = new HashMap<>();
propertyMap.put(MessageHelper.APP_PROPERTY_STATUS, 200);
final ApplicationProperties props = new ApplicationProperties(propertyMap);
final Buffer payload = Buffer.buffer("some payload");
final Message message = getFakeMessage(replyToAddress, payload);
message.setCorrelationId("correlation-id");
message.setApplicationProperties(props);
final ProtonDelivery delivery = mock(ProtonDelivery.class);
adapter.onMessageReceived(AmqpContext.fromMessage(delivery, message, span, null)).onComplete(ctx.succeeding(ok -> {
ctx.verify(() -> {
// THEN the adapter forwards the command response message downstream
verify(responseSender).sendCommandResponse(eq(tenantObject), any(RegistrationAssertion.class), any(CommandResponse.class), (SpanContext) any());
// and reports the forwarded message
verify(metrics).reportCommand(eq(Direction.RESPONSE), eq(TEST_TENANT_ID), eq(tenantObject), eq(ProcessingOutcome.FORWARDED), eq(payload.length()), any());
});
ctx.completeNow();
}));
}
use of org.eclipse.hono.client.command.CommandResponseSender in project hono by eclipse.
the class AbstractProtocolAdapterBaseTest method setup.
/**
* Sets up the fixture.
*/
@BeforeEach
public void setup() {
tenantClient = mock(TenantClient.class);
when(tenantClient.start()).thenReturn(Future.succeededFuture());
registrationClient = mock(DeviceRegistrationClient.class);
when(registrationClient.start()).thenReturn(Future.succeededFuture());
credentialsClient = mock(CredentialsClient.class);
when(credentialsClient.start()).thenReturn(Future.succeededFuture());
amqpTelemetrySender = mockMessagingClient(TelemetrySender.class, MessagingType.amqp);
when(amqpTelemetrySender.start()).thenReturn(Future.succeededFuture());
kafkaTelemetrySender = mockMessagingClient(TelemetrySender.class, MessagingType.kafka);
when(kafkaTelemetrySender.start()).thenReturn(Future.succeededFuture());
amqpEventSender = mockMessagingClient(EventSender.class, MessagingType.amqp);
when(amqpEventSender.start()).thenReturn(Future.succeededFuture());
kafkaEventSender = mockMessagingClient(EventSender.class, MessagingType.kafka);
when(kafkaEventSender.start()).thenReturn(Future.succeededFuture());
commandConsumerFactory = mock(CommandConsumerFactory.class);
when(commandConsumerFactory.start()).thenReturn(Future.succeededFuture());
amqpCommandResponseSender = mockMessagingClient(CommandResponseSender.class, MessagingType.amqp);
when(amqpCommandResponseSender.start()).thenReturn(Future.succeededFuture());
kafkaCommandResponseSender = mockMessagingClient(CommandResponseSender.class, MessagingType.kafka);
when(kafkaCommandResponseSender.start()).thenReturn(Future.succeededFuture());
final var telemetrySenderProvider = new MessagingClientProvider<TelemetrySender>().setClient(amqpTelemetrySender).setClient(kafkaTelemetrySender);
final var eventSenderProvider = new MessagingClientProvider<EventSender>().setClient(amqpEventSender).setClient(kafkaEventSender);
final var commandResponseSenderProvider = new MessagingClientProvider<CommandResponseSender>().setClient(amqpCommandResponseSender).setClient(kafkaCommandResponseSender);
messagingClientProviders = new MessagingClientProviders(telemetrySenderProvider, eventSenderProvider, commandResponseSenderProvider);
commandRouterClient = mock(CommandRouterClient.class);
when(commandRouterClient.start()).thenReturn(Future.succeededFuture());
properties = new ProtocolAdapterProperties();
adapter = newProtocolAdapter(properties, ADAPTER_NAME);
setCollaborators(adapter);
vertx = mock(Vertx.class);
VertxMockSupport.runTimersImmediately(vertx);
context = mock(Context.class);
adapter.init(vertx, context);
}
use of org.eclipse.hono.client.command.CommandResponseSender in project hono by eclipse.
the class AbstractVertxBasedMqttProtocolAdapterTest method testUploadEmptyCommandResponseSucceeds.
/**
* Verifies that the adapter accepts a command response message with an empty body.
*
* @param ctx The vert.x test context.
*/
@Test
public void testUploadEmptyCommandResponseSucceeds(final VertxTestContext ctx) {
// GIVEN an adapter with a command response consumer
final CommandResponseSender sender = givenACommandResponseSenderForAnyTenant();
// WHEN forwarding a command response that has been published
givenAnAdapter(properties);
final MqttEndpoint endpoint = mockEndpoint();
when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
final MqttPublishMessage messageFromDevice = mock(MqttPublishMessage.class);
when(messageFromDevice.qosLevel()).thenReturn(MqttQoS.AT_MOST_ONCE);
when(messageFromDevice.messageId()).thenReturn(5555555);
when(messageFromDevice.topicName()).thenReturn("command/my-tenant/4712/res/1010f8ab0b53-bd96-4d99-9d9c-56b868474a6a/200");
// ... with an empty payload
when(messageFromDevice.payload()).thenReturn(null);
final ResourceIdentifier address = ResourceIdentifier.fromString("command/my-tenant/4712/res/1010f8ab0b53-bd96-4d99-9d9c-56b868474a6a/200");
adapter.uploadCommandResponseMessage(newMqttContext(messageFromDevice, endpoint, span), address).onComplete(ctx.succeeding(result -> {
ctx.verify(() -> {
verify(sender).sendCommandResponse(any(TenantObject.class), any(RegistrationAssertion.class), any(CommandResponse.class), any());
// then it is forwarded successfully
verify(metrics).reportCommand(eq(MetricsTags.Direction.RESPONSE), eq("my-tenant"), any(TenantObject.class), eq(MetricsTags.ProcessingOutcome.FORWARDED), eq(0), any());
ctx.completeNow();
});
}));
}
Aggregations