use of org.eclipse.hono.commandrouter.CommandTargetMapper in project hono by eclipse.
the class KafkaBasedCommandConsumerFactoryImplIT method getKafkaBasedCommandConsumerFactory.
private KafkaBasedCommandConsumerFactoryImpl getKafkaBasedCommandConsumerFactory(final Supplier<Future<Void>> targetAdapterInstanceGetterCompletionFutureSupplier, final String tenantToHandleCommandsFor) {
final KafkaProducerFactory<String, Buffer> producerFactory = CachingKafkaProducerFactory.sharedFactory(vertx);
final TenantClient tenantClient = getTenantClient();
final CommandTargetMapper commandTargetMapper = new CommandTargetMapper() {
@Override
public Future<JsonObject> getTargetGatewayAndAdapterInstance(final String tenantId, final String deviceId, final SpanContext context) {
final JsonObject jsonObject = new JsonObject();
jsonObject.put(DeviceConnectionConstants.FIELD_ADAPTER_INSTANCE_ID, adapterInstanceId);
jsonObject.put(DeviceConnectionConstants.FIELD_PAYLOAD_DEVICE_ID, deviceId);
if (!tenantId.equals(tenantToHandleCommandsFor)) {
return Future.failedFuture("ignoring command for other tenant " + tenantId);
}
if (targetAdapterInstanceGetterCompletionFutureSupplier == null) {
return Future.succeededFuture(jsonObject);
}
return targetAdapterInstanceGetterCompletionFutureSupplier.get().map(jsonObject);
}
};
final Span span = TracingMockSupport.mockSpan();
final Tracer tracer = TracingMockSupport.mockTracer(span);
final MessagingKafkaConsumerConfigProperties kafkaConsumerConfig = new MessagingKafkaConsumerConfigProperties();
kafkaConsumerConfig.setConsumerConfig(Map.of(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, IntegrationTestSupport.DOWNSTREAM_BOOTSTRAP_SERVERS));
final CommandRouterMetrics metrics = mock(CommandRouterMetrics.class);
when(metrics.startTimer()).thenReturn(Timer.start());
final var kafkaBasedCommandConsumerFactoryImpl = new KafkaBasedCommandConsumerFactoryImpl(vertx, tenantClient, commandTargetMapper, producerFactory, IntegrationTestSupport.getKafkaProducerConfig(), IntegrationTestSupport.getKafkaProducerConfig(), kafkaConsumerConfig, metrics, NoopKafkaClientMetricsSupport.INSTANCE, tracer, null);
kafkaBasedCommandConsumerFactoryImpl.setGroupId(commandRouterGroupId);
componentsToStopAfterTest.add(kafkaBasedCommandConsumerFactoryImpl);
return kafkaBasedCommandConsumerFactoryImpl;
}
use of org.eclipse.hono.commandrouter.CommandTargetMapper in project hono by eclipse.
the class KafkaBasedMappingAndDelegatingCommandHandlerTest method testCommandDelegationOrderWithMappingFailedForFirstEntry.
/**
* Verifies the behaviour of the
* {@link KafkaBasedMappingAndDelegatingCommandHandler#mapAndDelegateIncomingCommandMessage(KafkaConsumerRecord)}
* method in a scenario where the rather long-running processing of a command delays subsequent, already mapped
* commands from getting delegated to the target adapter instance. After the processing of the first command finally
* resulted in an error, the subsequent commands shall get delegated in the correct order.
*
* @param ctx The vert.x test context
*/
@Test
public void testCommandDelegationOrderWithMappingFailedForFirstEntry(final VertxTestContext ctx) {
final String deviceId1 = "device1";
final String deviceId2 = "device2";
final String deviceId3 = "device3";
final String deviceId4 = "device4";
// GIVEN valid command records
final KafkaConsumerRecord<String, Buffer> commandRecord1 = getCommandRecord(tenantId, deviceId1, "subject1", 0, 1);
final KafkaConsumerRecord<String, Buffer> commandRecord2 = getCommandRecord(tenantId, deviceId2, "subject2", 0, 2);
final KafkaConsumerRecord<String, Buffer> commandRecord3 = getCommandRecord(tenantId, deviceId3, "subject3", 0, 3);
final KafkaConsumerRecord<String, Buffer> commandRecord4 = getCommandRecord(tenantId, deviceId4, "subject4", 0, 4);
// WHEN getting the target adapter instances for the commands results in different delays for each command
// so that the invocations are completed with the order: commandRecord3, commandRecord2, commandRecord1 (failed), commandRecord4
// with command 1 getting failed
final Promise<JsonObject> resultForCommand1 = Promise.promise();
when(commandTargetMapper.getTargetGatewayAndAdapterInstance(eq(tenantId), eq(deviceId1), any())).thenReturn(resultForCommand1.future());
final Promise<JsonObject> resultForCommand2 = Promise.promise();
when(commandTargetMapper.getTargetGatewayAndAdapterInstance(eq(tenantId), eq(deviceId2), any())).thenReturn(resultForCommand2.future());
final Promise<JsonObject> resultForCommand3 = Promise.promise();
when(commandTargetMapper.getTargetGatewayAndAdapterInstance(eq(tenantId), eq(deviceId3), any())).thenReturn(resultForCommand3.future());
doAnswer(invocation -> {
resultForCommand3.complete(createTargetAdapterInstanceJson(deviceId3, adapterInstanceId));
resultForCommand2.complete(createTargetAdapterInstanceJson(deviceId2, adapterInstanceId));
resultForCommand1.fail("mapping of command 1 failed for some reason");
return Future.succeededFuture(createTargetAdapterInstanceJson(deviceId4, adapterInstanceId));
}).when(commandTargetMapper).getTargetGatewayAndAdapterInstance(eq(tenantId), eq(deviceId4), any());
// WHEN mapping and delegating the commands
final Future<Void> cmd1Future = cmdHandler.mapAndDelegateIncomingCommandMessage(commandRecord1);
final Future<Void> cmd2Future = cmdHandler.mapAndDelegateIncomingCommandMessage(commandRecord2);
final Future<Void> cmd3Future = cmdHandler.mapAndDelegateIncomingCommandMessage(commandRecord3);
final Future<Void> cmd4Future = cmdHandler.mapAndDelegateIncomingCommandMessage(commandRecord4);
// THEN the messages are delegated in the original order, with command 1 left out because it timed out
CompositeFuture.all(cmd2Future, cmd3Future, cmd4Future).onComplete(ctx.succeeding(r -> {
ctx.verify(() -> {
assertThat(cmd1Future.failed()).isTrue();
final ArgumentCaptor<CommandContext> commandContextCaptor = ArgumentCaptor.forClass(CommandContext.class);
verify(internalCommandSender, times(3)).sendCommand(commandContextCaptor.capture(), anyString());
final List<CommandContext> capturedCommandContexts = commandContextCaptor.getAllValues();
assertThat(capturedCommandContexts.get(0).getCommand().getDeviceId()).isEqualTo(deviceId2);
assertThat(capturedCommandContexts.get(1).getCommand().getDeviceId()).isEqualTo(deviceId3);
assertThat(capturedCommandContexts.get(2).getCommand().getDeviceId()).isEqualTo(deviceId4);
});
ctx.completeNow();
}));
}
use of org.eclipse.hono.commandrouter.CommandTargetMapper in project hono by eclipse.
the class ProtonBasedMappingAndDelegatingCommandHandlerTest method setUp.
/**
* Sets up fixture.
*/
@BeforeEach
public void setUp() {
final Vertx vertx = mock(Vertx.class);
final Context context = VertxMockSupport.mockContext(vertx);
when(vertx.getOrCreateContext()).thenReturn(context);
doAnswer(invocation -> {
final Handler<Void> handler = invocation.getArgument(1);
handler.handle(null);
return null;
}).when(vertx).setTimer(anyLong(), VertxMockSupport.anyHandler());
final EventBus eventBus = mock(EventBus.class);
when(vertx.eventBus()).thenReturn(eventBus);
final ClientConfigProperties props = new ClientConfigProperties();
props.setSendMessageTimeout(0);
final HonoConnection connection = mockHonoConnection(vertx, props);
when(connection.isConnected(anyLong())).thenReturn(Future.succeededFuture());
sender = mockProtonSender();
when(connection.createSender(anyString(), any(), any())).thenReturn(Future.succeededFuture(sender));
tenantId = UUID.randomUUID().toString();
tenantClient = mock(TenantClient.class);
when(tenantClient.get(eq(tenantId), any())).thenReturn(Future.succeededFuture(TenantObject.from(tenantId)));
commandTargetMapper = mock(CommandTargetMapper.class);
final CommandRouterMetrics metrics = mock(CommandRouterMetrics.class);
when(metrics.startTimer()).thenReturn(Timer.start());
mappingAndDelegatingCommandHandler = new ProtonBasedMappingAndDelegatingCommandHandler(tenantClient, connection, commandTargetMapper, metrics);
}
use of org.eclipse.hono.commandrouter.CommandTargetMapper in project hono by eclipse.
the class Application method commandRouterService.
private CommandRouterService commandRouterService() {
final DeviceRegistrationClient registrationClient = registrationClient();
final TenantClient tenantClient = tenantClient();
final CommandTargetMapper commandTargetMapper = CommandTargetMapper.create(registrationClient, deviceConnectionInfo, tracer);
return new CommandRouterServiceImpl(amqpServerProperties, registrationClient, tenantClient, deviceConnectionInfo, commandConsumerFactoryProvider(tenantClient, commandTargetMapper), adapterInstanceStatusService, tracer);
}
use of org.eclipse.hono.commandrouter.CommandTargetMapper in project hono by eclipse.
the class KafkaBasedMappingAndDelegatingCommandHandlerTest method setUp.
/**
* Sets up fixture.
*/
@BeforeEach
public void setUp() {
tenantId = UUID.randomUUID().toString();
deviceId = UUID.randomUUID().toString();
adapterInstanceId = UUID.randomUUID().toString();
final TenantClient tenantClient = mock(TenantClient.class);
when(tenantClient.get(eq(tenantId), any())).thenReturn(Future.succeededFuture(TenantObject.from(tenantId)));
commandTargetMapper = mock(CommandTargetMapper.class);
when(commandTargetMapper.getTargetGatewayAndAdapterInstance(eq(tenantId), eq(deviceId), any())).thenReturn(Future.succeededFuture(createTargetAdapterInstanceJson(deviceId, adapterInstanceId)));
internalCommandSender = mock(KafkaBasedInternalCommandSender.class);
when(internalCommandSender.sendCommand(any(CommandContext.class), anyString())).thenReturn(Future.succeededFuture());
final KafkaBasedCommandResponseSender kafkaBasedCommandResponseSender = mock(KafkaBasedCommandResponseSender.class);
vertx = mock(Vertx.class);
final Context context = VertxMockSupport.mockContext(vertx);
final KafkaCommandProcessingQueue commandQueue = new KafkaCommandProcessingQueue(context);
final CommandRouterMetrics metrics = mock(CommandRouterMetrics.class);
when(metrics.startTimer()).thenReturn(Timer.start());
final Tracer tracer = TracingMockSupport.mockTracer(TracingMockSupport.mockSpan());
cmdHandler = new KafkaBasedMappingAndDelegatingCommandHandler(vertx, tenantClient, commandQueue, commandTargetMapper, internalCommandSender, kafkaBasedCommandResponseSender, metrics, tracer);
}
Aggregations