use of io.vertx.junit5.Timeout in project hono by eclipse.
the class RequestResponseClientTest method testCreateAndSendRequestReturnsCorrespondingResponseMessage.
/**
* Verifies that the client returns the service's response message that correlates with the request.
*
* @param ctx The vert.x test context.
*/
@Test
public void testCreateAndSendRequestReturnsCorrespondingResponseMessage(final VertxTestContext ctx) {
// WHEN sending a request message to the peer
client.compose(c -> c.createAndSendRequest("request", null, Buffer.buffer("hello"), "text/plain", SimpleRequestResponseResult::from, span)).onComplete(ctx.succeeding(s -> {
ctx.verify(() -> {
// THEN the response is passed to the handler registered with the request
assertEquals(200, s.getStatus());
assertEquals("payload", s.getPayload().toString());
verify(sample).completed(isA(Accepted.class));
// and a timer has been set to time out the request
final ArgumentCaptor<Handler<Long>> timeoutHandlerCaptor = VertxMockSupport.argumentCaptorHandler();
verify(vertx).setTimer(eq(clientConfig.getRequestTimeout()), timeoutHandlerCaptor.capture());
// triggering the timer now that the request has been handled should not invoke the sampler timeout method
timeoutHandlerCaptor.getValue().handle(1L);
verify(sample, never()).timeout();
});
ctx.completeNow();
}));
// WHEN a response is received for the request
final Message request = verifySenderSendAndUpdateDelivery(new Accepted());
final ProtonMessageHandler responseHandler = verifyResponseHandlerSet();
final Message response = ProtonHelper.message("payload");
response.setCorrelationId(request.getMessageId());
MessageHelper.addProperty(response, MessageHelper.APP_PROPERTY_STATUS, 200);
final ProtonDelivery delivery = mock(ProtonDelivery.class);
responseHandler.handle(delivery, response);
}
use of io.vertx.junit5.Timeout in project hono by eclipse.
the class RequestResponseClientTest method testCreateAndSendRequestFailsOnRejectedMessage.
private void testCreateAndSendRequestFailsOnRejectedMessage(final VertxTestContext ctx, final Symbol errorCondition, final Consumer<Throwable> failureAssertions) {
// WHEN sending a request message with some headers and payload
final JsonObject payload = new JsonObject().put("key", "value");
client.compose(c -> c.createAndSendRequest("get", null, payload.toBuffer(), "application/json", SimpleRequestResponseResult::from, span)).onComplete(ctx.failing(t -> {
ctx.verify(() -> {
// THEN the result handler is failed with the expected error
failureAssertions.accept(t);
verify(sample).completed(isA(Rejected.class));
// and a timer has been set to time out the request
final ArgumentCaptor<Handler<Long>> timeoutHandlerCaptor = VertxMockSupport.argumentCaptorHandler();
verify(vertx).setTimer(eq(clientConfig.getRequestTimeout()), timeoutHandlerCaptor.capture());
// triggering the timer now that the request has been handled should not invoke the sampler timeout method
timeoutHandlerCaptor.getValue().handle(1L);
verify(sample, never()).timeout();
});
ctx.completeNow();
}));
// and the peer rejects the message
final Rejected rejected = new Rejected();
rejected.setError(ProtonHelper.condition(errorCondition, "request message cannot be processed"));
final ProtonDelivery delivery = mock(ProtonDelivery.class);
when(delivery.getRemoteState()).thenReturn(rejected);
final ArgumentCaptor<Handler<ProtonDelivery>> dispositionHandlerCaptor = VertxMockSupport.argumentCaptorHandler();
verify(sender).send(any(Message.class), dispositionHandlerCaptor.capture());
dispositionHandlerCaptor.getValue().handle(delivery);
}
use of io.vertx.junit5.Timeout in project hono by eclipse.
the class KafkaBasedCommandSenderTest method testSendCommandAndReceiveResponseTimesOut.
/**
* Verifies that
* {@link org.eclipse.hono.application.client.CommandSender#sendCommand(String, String, String, String, Buffer, String, Map, Duration, io.opentracing.SpanContext)}
* fails as the timeout is reached.
*
* @param ctx The vert.x test context.
*/
@Test
public void testSendCommandAndReceiveResponseTimesOut(final VertxTestContext ctx) {
final Context context = vertx.getOrCreateContext();
commandSender.setKafkaConsumerSupplier(() -> mockConsumer);
context.runOnContext(v -> {
commandSender.sendCommand(tenantId, deviceId, "testCommand", "text/plain", Buffer.buffer("data"), null, null, Duration.ofMillis(5), null).onComplete(ctx.failing(error -> {
ctx.verify(() -> {
// VERIFY that the error is caused due to time out.
assertThat(error).isInstanceOf(SendMessageTimeoutException.class);
verify(span).finish();
});
ctx.completeNow();
}));
});
}
use of io.vertx.junit5.Timeout in project hono by eclipse.
the class CommandAndControlAmqpIT method testSendAsyncCommandsSucceeds.
/**
* Verifies that the adapter forwards commands and responses hence and forth between
* an application and a device that have been sent using the async API.
*
* @param endpointConfig The endpoints to use for sending/receiving commands.
* @param ctx The vert.x test context.
* @throws InterruptedException if not all commands and responses are exchanged in time.
*/
@ParameterizedTest(name = IntegrationTestSupport.PARAMETERIZED_TEST_NAME_PATTERN)
@MethodSource("allCombinations")
public void testSendAsyncCommandsSucceeds(final AmqpCommandEndpointConfiguration endpointConfig, final VertxTestContext ctx) throws InterruptedException {
final String commandTargetDeviceId = endpointConfig.isSubscribeAsGateway() ? helper.setupGatewayDeviceBlocking(tenantId, deviceId, 5) : deviceId;
final int totalNoOfCommandsToSend = 60;
connectAndSubscribe(ctx, commandTargetDeviceId, endpointConfig, (cmdReceiver, cmdResponseSender) -> createCommandConsumer(ctx, cmdReceiver, cmdResponseSender), totalNoOfCommandsToSend);
if (ctx.failed()) {
return;
}
final String replyId = "reply-id";
final CountDownLatch commandsSucceeded = new CountDownLatch(totalNoOfCommandsToSend);
final AtomicInteger commandsSent = new AtomicInteger(0);
final AtomicLong lastReceivedTimestamp = new AtomicLong();
final VertxTestContext setup = new VertxTestContext();
final Future<MessageConsumer> asyncResponseConsumer = helper.applicationClient.createCommandResponseConsumer(tenantId, replyId, response -> {
lastReceivedTimestamp.set(System.currentTimeMillis());
commandsSucceeded.countDown();
if (commandsSucceeded.getCount() % 20 == 0) {
log.info("command responses received: {}", totalNoOfCommandsToSend - commandsSucceeded.getCount());
}
}, null);
asyncResponseConsumer.onComplete(setup.succeedingThenComplete());
assertWithMessage("setup of command response consumer finished within %s seconds", IntegrationTestSupport.getTestSetupTimeout()).that(setup.awaitCompletion(IntegrationTestSupport.getTestSetupTimeout(), TimeUnit.SECONDS)).isTrue();
if (setup.failed()) {
ctx.failNow(setup.causeOfFailure());
return;
}
final long start = System.currentTimeMillis();
while (commandsSent.get() < totalNoOfCommandsToSend) {
final CountDownLatch commandSent = new CountDownLatch(1);
context.runOnContext(go -> {
final String correlationId = String.valueOf(commandsSent.getAndIncrement());
final Buffer msg = Buffer.buffer("value: " + correlationId);
helper.applicationClient.sendAsyncCommand(tenantId, commandTargetDeviceId, "setValue", "text/plain", msg, correlationId, replyId, null).onComplete(sendAttempt -> {
if (sendAttempt.failed()) {
log.debug("error sending command {}", correlationId, sendAttempt.cause());
}
if (commandsSent.get() % 20 == 0) {
log.info("commands sent: " + commandsSent.get());
}
commandSent.countDown();
});
});
commandSent.await();
}
final long timeToWait = totalNoOfCommandsToSend * 200;
if (!commandsSucceeded.await(timeToWait, TimeUnit.MILLISECONDS)) {
log.info("Timeout of {} milliseconds reached, stop waiting for command responses", timeToWait);
}
final long commandsCompleted = totalNoOfCommandsToSend - commandsSucceeded.getCount();
log.info("commands sent: {}, responses received: {} after {} milliseconds", commandsSent.get(), commandsCompleted, lastReceivedTimestamp.get() - start);
asyncResponseConsumer.result().close().onComplete(ar -> {
if (commandsCompleted == commandsSent.get()) {
ctx.completeNow();
} else {
ctx.failNow(new IllegalStateException("did not complete all commands sent"));
}
});
}
use of io.vertx.junit5.Timeout in project hono by eclipse.
the class CommandAndControlAmqpIT method testSendCommandViaKafkaFailsForMalformedMessage.
/**
* Verifies that the adapter rejects malformed command messages sent by applications.
* <p>
* This test is applicable only if the messaging network type is Kafka.
*
* @param endpointConfig The endpoints to use for sending/receiving commands.
* @param ctx The vert.x test context.
* @throws InterruptedException if not all commands and responses are exchanged in time.
*/
@ParameterizedTest(name = IntegrationTestSupport.PARAMETERIZED_TEST_NAME_PATTERN)
@MethodSource("allCombinations")
@Timeout(timeUnit = TimeUnit.SECONDS, value = 10)
@AssumeMessagingSystem(type = MessagingType.kafka)
public void testSendCommandViaKafkaFailsForMalformedMessage(final AmqpCommandEndpointConfiguration endpointConfig, final VertxTestContext ctx) throws InterruptedException {
final String commandTargetDeviceId = endpointConfig.isSubscribeAsGateway() ? helper.setupGatewayDeviceBlocking(tenantId, deviceId, 5) : deviceId;
final AtomicReference<GenericKafkaSender> kafkaSenderRef = new AtomicReference<>();
final CountDownLatch expectedCommandResponses = new CountDownLatch(1);
final VertxTestContext setup = new VertxTestContext();
final Checkpoint setupDone = setup.checkpoint();
final Checkpoint ttdReceivedPrecondition = setup.checkpoint();
final Future<MessageConsumer> kafkaAsyncErrorResponseConsumer = helper.createDeliveryFailureCommandResponseConsumer(ctx, tenantId, HttpURLConnection.HTTP_BAD_REQUEST, response -> {
ctx.verify(() -> {
DownstreamMessageAssertions.assertMessageContainsTimeToLive(response, TTL_COMMAND_RESPONSE);
});
expectedCommandResponses.countDown();
}, null);
connectToAdapter(tenantId, deviceId, password, () -> createEventConsumer(tenantId, msg -> {
// expect empty notification with TTD -1
setup.verify(() -> assertThat(msg.getContentType()).isEqualTo(EventConstants.CONTENT_TYPE_EMPTY_NOTIFICATION));
final TimeUntilDisconnectNotification notification = msg.getTimeUntilDisconnectNotification().orElse(null);
log.debug("received notification [{}]", notification);
setup.verify(() -> assertThat(notification).isNotNull());
if (notification.getTtd() == -1) {
ttdReceivedPrecondition.flag();
}
})).compose(con -> subscribeToCommands(endpointConfig, tenantId, commandTargetDeviceId).onSuccess(recv -> recv.handler((delivery, msg) -> ctx.failNow(new IllegalStateException("should not have received command"))))).compose(ok -> helper.createGenericKafkaSender().onSuccess(kafkaSenderRef::set).mapEmpty()).compose(v -> kafkaAsyncErrorResponseConsumer).onComplete(setup.succeeding(v -> setupDone.flag()));
assertWithMessage("setup of adapter finished within %s seconds", IntegrationTestSupport.getTestSetupTimeout()).that(setup.awaitCompletion(IntegrationTestSupport.getTestSetupTimeout(), TimeUnit.SECONDS)).isTrue();
if (setup.failed()) {
ctx.failNow(setup.causeOfFailure());
return;
}
final String commandTopic = new HonoTopic(HonoTopic.Type.COMMAND, tenantId).toString();
log.debug("sending command message lacking subject and correlation ID - no failure response expected here");
final Map<String, Object> properties1 = Map.of(MessageHelper.APP_PROPERTY_DEVICE_ID, deviceId, MessageHelper.SYS_PROPERTY_CONTENT_TYPE, MessageHelper.CONTENT_TYPE_OCTET_STREAM, KafkaRecordHelper.HEADER_RESPONSE_REQUIRED, true);
kafkaSenderRef.get().sendAndWaitForOutcome(commandTopic, tenantId, deviceId, Buffer.buffer(), properties1).onComplete(ctx.succeeding(ok -> {
}));
log.debug("sending command message lacking subject");
final String correlationId = "1";
final Map<String, Object> properties2 = Map.of(MessageHelper.SYS_PROPERTY_CORRELATION_ID, correlationId, MessageHelper.APP_PROPERTY_DEVICE_ID, deviceId, MessageHelper.SYS_PROPERTY_CONTENT_TYPE, MessageHelper.CONTENT_TYPE_OCTET_STREAM, KafkaRecordHelper.HEADER_RESPONSE_REQUIRED, true);
kafkaSenderRef.get().sendAndWaitForOutcome(commandTopic, tenantId, deviceId, Buffer.buffer(), properties2).onComplete(ctx.succeeding(ok -> {
}));
final long timeToWait = 2500;
if (!expectedCommandResponses.await(timeToWait, TimeUnit.MILLISECONDS)) {
log.info("Timeout of {} milliseconds reached, stop waiting for command response", timeToWait);
}
kafkaAsyncErrorResponseConsumer.result().close().onComplete(ar -> {
if (expectedCommandResponses.getCount() == 0) {
ctx.completeNow();
} else {
ctx.failNow(new IllegalStateException("did not receive command response"));
}
});
}
Aggregations