Search in sources :

Example 11 with HonoConnection

use of org.eclipse.hono.client.HonoConnection in project hono by eclipse.

the class ProtonBasedNotificationSenderTest method setUp.

/**
 * Sets up the fixture.
 */
@BeforeEach
void setUp() {
    final var vertx = mock(Vertx.class);
    when(vertx.eventBus()).thenReturn(mock(EventBus.class));
    final HonoConnection connection = AmqpClientUnitTestHelper.mockHonoConnection(vertx);
    final ProtonReceiver receiver = AmqpClientUnitTestHelper.mockProtonReceiver();
    when(connection.createReceiver(anyString(), any(ProtonQoS.class), any(ProtonMessageHandler.class), anyInt(), anyBoolean(), VertxMockSupport.anyHandler())).thenReturn(Future.succeededFuture(receiver));
    protonDelivery = mock(ProtonDelivery.class);
    when(protonDelivery.remotelySettled()).thenReturn(true);
    when(protonDelivery.getRemoteState()).thenReturn(new Accepted());
    sender = AmqpClientUnitTestHelper.mockProtonSender();
    when(sender.send(any(Message.class), VertxMockSupport.anyHandler())).thenReturn(protonDelivery);
    when(connection.createSender(anyString(), any(), any())).thenReturn(Future.succeededFuture(sender));
    notificationSender = new ProtonBasedNotificationSender(connection);
}
Also used : ProtonReceiver(io.vertx.proton.ProtonReceiver) ProtonQoS(io.vertx.proton.ProtonQoS) HonoConnection(org.eclipse.hono.client.HonoConnection) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) ProtonDelivery(io.vertx.proton.ProtonDelivery) Message(org.apache.qpid.proton.message.Message) EventBus(io.vertx.core.eventbus.EventBus) Accepted(org.apache.qpid.proton.amqp.messaging.Accepted) BeforeEach(org.junit.jupiter.api.BeforeEach)

Example 12 with HonoConnection

use of org.eclipse.hono.client.HonoConnection in project hono by eclipse.

the class HonoConnectionImpl method createSender.

/**
 * Creates a sender link.
 *
 * @param targetAddress The target address of the link. If the address is {@code null}, the
 *                      sender link will be established to the 'anonymous relay' and each
 *                      message must specify its destination address.
 * @param qos The quality of service to use for the link.
 * @param closeHook The handler to invoke when the link is closed by the peer (may be {@code null}).
 * @return A future for the created link. The future will be completed once the link is open.
 *         The future will fail with a {@link ServiceInvocationException} if the link cannot be opened.
 * @throws NullPointerException if qos is {@code null}.
 */
@Override
public final Future<ProtonSender> createSender(final String targetAddress, final ProtonQoS qos, final Handler<String> closeHook) {
    Objects.requireNonNull(qos);
    return executeOnContext(result -> {
        checkConnected().compose(v -> {
            if (targetAddress == null && !supportsCapability(Constants.CAP_ANONYMOUS_RELAY)) {
                // before a client can use anonymous terminus
                return Future.failedFuture(new ServerErrorException(HttpURLConnection.HTTP_NOT_IMPLEMENTED, "server does not support anonymous terminus"));
            }
            final Promise<ProtonSender> senderPromise = Promise.promise();
            final ProtonSender sender = session.createSender(targetAddress);
            sender.setQoS(qos);
            sender.setAutoSettle(true);
            final DisconnectListener<HonoConnection> disconnectBeforeOpenListener = (con) -> {
                log.debug("opening sender [{}] failed: got disconnected", targetAddress);
                senderPromise.tryFail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "not connected"));
            };
            oneTimeDisconnectListeners.add(disconnectBeforeOpenListener);
            sender.openHandler(senderOpen -> {
                oneTimeDisconnectListeners.remove(disconnectBeforeOpenListener);
                // the result future may have already been completed here in case of a link establishment timeout
                if (senderPromise.future().isComplete()) {
                    log.debug("ignoring server response for opening sender [{}]: sender creation already timed out", targetAddress);
                } else if (senderOpen.failed()) {
                    // this means that we have received the peer's attach
                    // and the subsequent detach frame in one TCP read
                    final ErrorCondition error = sender.getRemoteCondition();
                    if (error == null) {
                        log.debug("opening sender [{}] failed", targetAddress, senderOpen.cause());
                        senderPromise.tryFail(new ClientErrorException(HttpURLConnection.HTTP_NOT_FOUND, "cannot open sender", senderOpen.cause()));
                    } else {
                        log.debug("opening sender [{}] failed: {} - {}", targetAddress, error.getCondition(), error.getDescription());
                        senderPromise.tryFail(StatusCodeMapper.fromAttachError(error));
                    }
                } else if (HonoProtonHelper.isLinkEstablished(sender)) {
                    log.debug("sender open [target: {}, sendQueueFull: {}, remote max-message-size: {}]", targetAddress, sender.sendQueueFull(), sender.getRemoteMaxMessageSize());
                    final long remoteMaxMessageSize = Optional.ofNullable(sender.getRemoteMaxMessageSize()).map(UnsignedLong::longValue).orElse(0L);
                    if (remoteMaxMessageSize > 0 && remoteMaxMessageSize < clientConfigProperties.getMinMaxMessageSize()) {
                        // peer won't accept our (biggest) messages
                        sender.close();
                        final String msg = String.format("peer does not support minimum max-message-size [required: %d, supported: %d", clientConfigProperties.getMinMaxMessageSize(), remoteMaxMessageSize);
                        log.debug(msg);
                        senderPromise.tryFail(new ClientErrorException(HttpURLConnection.HTTP_PRECON_FAILED, msg));
                    } else if (sender.getCredit() <= 0) {
                        // wait on credits a little time, if not already given
                        final long waitOnCreditsTimerId = vertx.setTimer(clientConfigProperties.getFlowLatency(), timerID -> {
                            log.debug("sender [target: {}] has {} credits after grace period of {}ms", targetAddress, sender.getCredit(), clientConfigProperties.getFlowLatency());
                            sender.sendQueueDrainHandler(null);
                            senderPromise.tryComplete(sender);
                        });
                        sender.sendQueueDrainHandler(replenishedSender -> {
                            log.debug("sender [target: {}] has received {} initial credits", targetAddress, replenishedSender.getCredit());
                            if (vertx.cancelTimer(waitOnCreditsTimerId)) {
                                result.tryComplete(replenishedSender);
                                replenishedSender.sendQueueDrainHandler(null);
                            }
                        // otherwise the timer has already completed the future and cleaned up
                        // sendQueueDrainHandler
                        });
                    } else {
                        senderPromise.tryComplete(sender);
                    }
                } else {
                    // this means that the peer did not create a local terminus for the link
                    // and will send a detach frame for closing the link very shortly
                    // see AMQP 1.0 spec section 2.6.3
                    log.debug("peer did not create terminus for target [{}] and will detach the link", targetAddress);
                    senderPromise.tryFail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE));
                }
            });
            HonoProtonHelper.setDetachHandler(sender, remoteDetached -> onRemoteDetach(sender, connection.getRemoteContainer(), false, closeHook));
            HonoProtonHelper.setCloseHandler(sender, remoteClosed -> onRemoteDetach(sender, connection.getRemoteContainer(), true, closeHook));
            sender.open();
            vertx.setTimer(clientConfigProperties.getLinkEstablishmentTimeout(), tid -> {
                final boolean notOpenedAndNotDisconnectedYet = oneTimeDisconnectListeners.remove(disconnectBeforeOpenListener);
                if (notOpenedAndNotDisconnectedYet) {
                    onLinkEstablishmentTimeout(sender, clientConfigProperties, senderPromise);
                }
            });
            return senderPromise.future();
        }).onComplete(result);
    });
}
Also used : HttpURLConnection(java.net.HttpURLConnection) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonReceiver(io.vertx.proton.ProtonReceiver) Arrays(java.util.Arrays) LoggerFactory(org.slf4j.LoggerFactory) Context(io.vertx.core.Context) HonoProtonHelper(org.eclipse.hono.util.HonoProtonHelper) ConnectionFactory(org.eclipse.hono.connection.ConnectionFactory) SaslSystemException(io.vertx.proton.sasl.SaslSystemException) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) DisconnectListener(org.eclipse.hono.client.DisconnectListener) ClientConfigProperties(org.eclipse.hono.config.ClientConfigProperties) MechanismMismatchException(io.vertx.proton.sasl.MechanismMismatchException) ProtonQoS(io.vertx.proton.ProtonQoS) UUID(java.util.UUID) Future(io.vertx.core.Future) Objects(java.util.Objects) CountDownLatch(java.util.concurrent.CountDownLatch) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) ReconnectListener(org.eclipse.hono.client.ReconnectListener) List(java.util.List) SSLException(javax.net.ssl.SSLException) Optional(java.util.Optional) ProtonSender(io.vertx.proton.ProtonSender) AuthenticationException(javax.security.sasl.AuthenticationException) ProtonLink(io.vertx.proton.ProtonLink) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ClientErrorException(org.eclipse.hono.client.ClientErrorException) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) AtomicReference(java.util.concurrent.atomic.AtomicReference) Constants(org.eclipse.hono.util.Constants) ArrayList(java.util.ArrayList) ProtonSession(io.vertx.proton.ProtonSession) ProtonClientOptions(io.vertx.proton.ProtonClientOptions) Symbol(org.apache.qpid.proton.amqp.Symbol) StatusCodeMapper(org.eclipse.hono.client.StatusCodeMapper) ThreadLocalRandom(java.util.concurrent.ThreadLocalRandom) UnsignedLong(org.apache.qpid.proton.amqp.UnsignedLong) AsyncResult(io.vertx.core.AsyncResult) HonoConnection(org.eclipse.hono.client.HonoConnection) Logger(org.slf4j.Logger) VertxInternal(io.vertx.core.impl.VertxInternal) Iterator(java.util.Iterator) Tracer(io.opentracing.Tracer) NoopTracerFactory(io.opentracing.noop.NoopTracerFactory) Promise(io.vertx.core.Promise) Vertx(io.vertx.core.Vertx) ServerErrorException(org.eclipse.hono.client.ServerErrorException) ProtonHelper(io.vertx.proton.ProtonHelper) TimeUnit(java.util.concurrent.TimeUnit) Handler(io.vertx.core.Handler) Collections(java.util.Collections) Promise(io.vertx.core.Promise) ProtonSender(io.vertx.proton.ProtonSender) DisconnectListener(org.eclipse.hono.client.DisconnectListener) UnsignedLong(org.apache.qpid.proton.amqp.UnsignedLong) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) ClientErrorException(org.eclipse.hono.client.ClientErrorException) ServerErrorException(org.eclipse.hono.client.ServerErrorException)

Example 13 with HonoConnection

use of org.eclipse.hono.client.HonoConnection in project hono by eclipse.

the class HonoConnectionImplTest method testIsConnectedWithTimeoutFailsAfterConcurrentReconnectFailed.

/**
 * Verifies that {@link HonoConnectionImpl#isConnected(long)} only completes once a concurrent
 * connection attempt (which eventually fails here) is finished.
 *
 * @param ctx The vert.x test client.
 */
@Test
public void testIsConnectedWithTimeoutFailsAfterConcurrentReconnectFailed(final VertxTestContext ctx) {
    final long isConnectedTimeout = 44444L;
    // let the vertx timer for the isConnectedTimeout do nothing
    when(vertx.setTimer(eq(isConnectedTimeout), VertxMockSupport.anyHandler())).thenAnswer(invocation -> 0L);
    final AtomicBoolean isConnectedInvocationsDone = new AtomicBoolean(false);
    final AtomicReference<Future<Void>> isConnected1FutureRef = new AtomicReference<>();
    final AtomicReference<Future<Void>> isConnected2FutureRef = new AtomicReference<>();
    // GIVEN a client that is configured to connect to a peer
    // to which the connection can be established on the third attempt only
    connectionFactory = new DisconnectHandlerProvidingConnectionFactory(con) {

        @Override
        public void connect(final ProtonClientOptions options, final String username, final String password, final String containerId, final Handler<AsyncResult<ProtonConnection>> closeHandler, final Handler<ProtonConnection> disconnectHandler, final Handler<AsyncResult<ProtonConnection>> connectionResultHandler) {
            // and GIVEN "isConnected" invocations done while the "connect" invocation is still in progress
            if (isConnectedInvocationsDone.compareAndSet(false, true)) {
                isConnected1FutureRef.set(honoConnection.isConnected(isConnectedTimeout));
                isConnected2FutureRef.set(honoConnection.isConnected(isConnectedTimeout));
                // assert "isConnected" invocations have not completed yet
                ctx.verify(() -> {
                    assertThat(isConnected1FutureRef.get().isComplete()).isFalse();
                    assertThat(isConnected2FutureRef.get().isComplete()).isFalse();
                });
            }
            super.connect(options, username, password, containerId, closeHandler, disconnectHandler, connectionResultHandler);
        }
    };
    connectionFactory.setExpectedFailingConnectionAttempts(3);
    props.setReconnectAttempts(2);
    props.setConnectTimeout(10);
    honoConnection = new HonoConnectionImpl(vertx, connectionFactory, props);
    // WHEN the client tries to connect
    honoConnection.connect().onComplete(ctx.failing(t -> {
        ctx.verify(() -> {
            // THEN the connection attempt fails and the "isConnected" futures fail as well
            assertThat(((ServerErrorException) t).getErrorCode()).isEqualTo(HttpURLConnection.HTTP_UNAVAILABLE);
            assertThat(isConnected1FutureRef.get().failed()).isTrue();
            assertThat(((ServerErrorException) isConnected1FutureRef.get().cause()).getErrorCode()).isEqualTo(HttpURLConnection.HTTP_UNAVAILABLE);
            assertThat(isConnected2FutureRef.get().failed()).isTrue();
            assertThat(((ServerErrorException) isConnected2FutureRef.get().cause()).getErrorCode()).isEqualTo(HttpURLConnection.HTTP_UNAVAILABLE);
        });
    }));
    // and the client has indeed tried three times in total before giving up
    ctx.verify(() -> assertThat(connectionFactory.awaitFailure()).isTrue());
    ctx.completeNow();
}
Also used : HttpURLConnection(java.net.HttpURLConnection) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonReceiver(io.vertx.proton.ProtonReceiver) BeforeEach(org.junit.jupiter.api.BeforeEach) ArgumentMatchers.eq(org.mockito.ArgumentMatchers.eq) Context(io.vertx.core.Context) Timeout(io.vertx.junit5.Timeout) ConnectionFactory(org.eclipse.hono.connection.ConnectionFactory) SaslSystemException(io.vertx.proton.sasl.SaslSystemException) ExtendWith(org.junit.jupiter.api.extension.ExtendWith) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) Mockito.doAnswer(org.mockito.Mockito.doAnswer) DisconnectListener(org.eclipse.hono.client.DisconnectListener) AmqpError(org.apache.qpid.proton.amqp.transport.AmqpError) ClientConfigProperties(org.eclipse.hono.config.ClientConfigProperties) Predicate(java.util.function.Predicate) ProtonQoS(io.vertx.proton.ProtonQoS) VertxExtension(io.vertx.junit5.VertxExtension) Future(io.vertx.core.Future) AdditionalAnswers(org.mockito.AdditionalAnswers) Test(org.junit.jupiter.api.Test) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) VertxMockSupport(org.eclipse.hono.test.VertxMockSupport) ProtonSender(io.vertx.proton.ProtonSender) Mockito.mock(org.mockito.Mockito.mock) ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) VertxTestContext(io.vertx.junit5.VertxTestContext) ArgumentMatchers.anyLong(org.mockito.ArgumentMatchers.anyLong) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Target(org.apache.qpid.proton.amqp.messaging.Target) ClientErrorException(org.eclipse.hono.client.ClientErrorException) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) AtomicReference(java.util.concurrent.atomic.AtomicReference) Supplier(java.util.function.Supplier) CompositeFuture(io.vertx.core.CompositeFuture) ProtonSession(io.vertx.proton.ProtonSession) TelemetryConstants(org.eclipse.hono.util.TelemetryConstants) ArgumentCaptor(org.mockito.ArgumentCaptor) ProtonClientOptions(io.vertx.proton.ProtonClientOptions) Symbol(org.apache.qpid.proton.amqp.Symbol) BiConsumer(java.util.function.BiConsumer) UnsignedLong(org.apache.qpid.proton.amqp.UnsignedLong) AsyncResult(io.vertx.core.AsyncResult) HonoConnection(org.eclipse.hono.client.HonoConnection) Promise(io.vertx.core.Promise) Vertx(io.vertx.core.Vertx) ServerErrorException(org.eclipse.hono.client.ServerErrorException) Mockito.times(org.mockito.Mockito.times) Mockito.when(org.mockito.Mockito.when) Truth.assertThat(com.google.common.truth.Truth.assertThat) Mockito.verify(org.mockito.Mockito.verify) TimeUnit(java.util.concurrent.TimeUnit) Mockito.never(org.mockito.Mockito.never) Source(org.apache.qpid.proton.amqp.transport.Source) Handler(io.vertx.core.Handler) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) AtomicReference(java.util.concurrent.atomic.AtomicReference) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ProtonConnection(io.vertx.proton.ProtonConnection) Future(io.vertx.core.Future) CompositeFuture(io.vertx.core.CompositeFuture) ProtonClientOptions(io.vertx.proton.ProtonClientOptions) AsyncResult(io.vertx.core.AsyncResult) Test(org.junit.jupiter.api.Test)

Example 14 with HonoConnection

use of org.eclipse.hono.client.HonoConnection in project hono by eclipse.

the class HonoConnectionImplTest method testIsConnectedWithTimeoutSucceedsAfterConcurrentReconnectSucceeded.

/**
 * Verifies that {@link HonoConnectionImpl#isConnected(long)} only completes once a concurrent
 * connection attempt (which eventually succeeds here) is finished.
 *
 * @param ctx The test execution context.
 */
@Test
public void testIsConnectedWithTimeoutSucceedsAfterConcurrentReconnectSucceeded(final VertxTestContext ctx) {
    final long isConnectedTimeout = 44444L;
    // let the vertx timer for the isConnectedTimeout do nothing
    when(vertx.setTimer(eq(isConnectedTimeout), VertxMockSupport.anyHandler())).thenAnswer(invocation -> 0L);
    final AtomicBoolean isConnectedInvocationsDone = new AtomicBoolean(false);
    final AtomicReference<Future<Void>> isConnected1FutureRef = new AtomicReference<>();
    final AtomicReference<Future<Void>> isConnectedTimeoutForcedFutureRef = new AtomicReference<>();
    final AtomicReference<Future<Void>> isConnected2FutureRef = new AtomicReference<>();
    // GIVEN a client that is configured to connect to a peer
    // to which the connection can be established on the third attempt only
    connectionFactory = new DisconnectHandlerProvidingConnectionFactory(con) {

        @Override
        public void connect(final ProtonClientOptions options, final String username, final String password, final String containerId, final Handler<AsyncResult<ProtonConnection>> closeHandler, final Handler<ProtonConnection> disconnectHandler, final Handler<AsyncResult<ProtonConnection>> connectionResultHandler) {
            // and GIVEN "isConnected" invocations done while the "connect" invocation is still in progress
            if (isConnectedInvocationsDone.compareAndSet(false, true)) {
                isConnected1FutureRef.set(honoConnection.isConnected(isConnectedTimeout));
                isConnectedTimeoutForcedFutureRef.set(honoConnection.isConnected(1L));
                isConnected2FutureRef.set(honoConnection.isConnected(isConnectedTimeout));
                // assert "isConnected" invocations have not completed yet, apart from the one with the forced timeout
                ctx.verify(() -> {
                    assertThat(isConnected1FutureRef.get().isComplete()).isFalse();
                    assertThat(isConnectedTimeoutForcedFutureRef.get().failed()).isTrue();
                    assertThat(isConnected2FutureRef.get().isComplete()).isFalse();
                });
            }
            super.connect(options, username, password, containerId, closeHandler, disconnectHandler, connectionResultHandler);
        }
    };
    connectionFactory.setExpectedFailingConnectionAttempts(2);
    props.setReconnectAttempts(2);
    props.setConnectTimeout(10);
    honoConnection = new HonoConnectionImpl(vertx, connectionFactory, props);
    // WHEN trying to connect
    honoConnection.connect().compose(v -> CompositeFuture.all(isConnected1FutureRef.get(), isConnected2FutureRef.get())).onFailure(ctx::failNow);
    ctx.verify(() -> {
        // and the client fails twice to connect
        assertThat(connectionFactory.awaitFailure()).isTrue();
        // and succeeds to connect on the third attempt
        assertThat(connectionFactory.await()).isTrue();
    });
    ctx.completeNow();
}
Also used : HttpURLConnection(java.net.HttpURLConnection) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonReceiver(io.vertx.proton.ProtonReceiver) BeforeEach(org.junit.jupiter.api.BeforeEach) ArgumentMatchers.eq(org.mockito.ArgumentMatchers.eq) Context(io.vertx.core.Context) Timeout(io.vertx.junit5.Timeout) ConnectionFactory(org.eclipse.hono.connection.ConnectionFactory) SaslSystemException(io.vertx.proton.sasl.SaslSystemException) ExtendWith(org.junit.jupiter.api.extension.ExtendWith) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) Mockito.doAnswer(org.mockito.Mockito.doAnswer) DisconnectListener(org.eclipse.hono.client.DisconnectListener) AmqpError(org.apache.qpid.proton.amqp.transport.AmqpError) ClientConfigProperties(org.eclipse.hono.config.ClientConfigProperties) Predicate(java.util.function.Predicate) ProtonQoS(io.vertx.proton.ProtonQoS) VertxExtension(io.vertx.junit5.VertxExtension) Future(io.vertx.core.Future) AdditionalAnswers(org.mockito.AdditionalAnswers) Test(org.junit.jupiter.api.Test) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) VertxMockSupport(org.eclipse.hono.test.VertxMockSupport) ProtonSender(io.vertx.proton.ProtonSender) Mockito.mock(org.mockito.Mockito.mock) ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) VertxTestContext(io.vertx.junit5.VertxTestContext) ArgumentMatchers.anyLong(org.mockito.ArgumentMatchers.anyLong) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Target(org.apache.qpid.proton.amqp.messaging.Target) ClientErrorException(org.eclipse.hono.client.ClientErrorException) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) AtomicReference(java.util.concurrent.atomic.AtomicReference) Supplier(java.util.function.Supplier) CompositeFuture(io.vertx.core.CompositeFuture) ProtonSession(io.vertx.proton.ProtonSession) TelemetryConstants(org.eclipse.hono.util.TelemetryConstants) ArgumentCaptor(org.mockito.ArgumentCaptor) ProtonClientOptions(io.vertx.proton.ProtonClientOptions) Symbol(org.apache.qpid.proton.amqp.Symbol) BiConsumer(java.util.function.BiConsumer) UnsignedLong(org.apache.qpid.proton.amqp.UnsignedLong) AsyncResult(io.vertx.core.AsyncResult) HonoConnection(org.eclipse.hono.client.HonoConnection) Promise(io.vertx.core.Promise) Vertx(io.vertx.core.Vertx) ServerErrorException(org.eclipse.hono.client.ServerErrorException) Mockito.times(org.mockito.Mockito.times) Mockito.when(org.mockito.Mockito.when) Truth.assertThat(com.google.common.truth.Truth.assertThat) Mockito.verify(org.mockito.Mockito.verify) TimeUnit(java.util.concurrent.TimeUnit) Mockito.never(org.mockito.Mockito.never) Source(org.apache.qpid.proton.amqp.transport.Source) Handler(io.vertx.core.Handler) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) AtomicReference(java.util.concurrent.atomic.AtomicReference) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ProtonConnection(io.vertx.proton.ProtonConnection) Future(io.vertx.core.Future) CompositeFuture(io.vertx.core.CompositeFuture) ProtonClientOptions(io.vertx.proton.ProtonClientOptions) AsyncResult(io.vertx.core.AsyncResult) Test(org.junit.jupiter.api.Test)

Example 15 with HonoConnection

use of org.eclipse.hono.client.HonoConnection in project hono by eclipse.

the class HonoConnectionImplTest method testDisconnectAbortsConnectAttemptWaitingForReconnect.

/**
 * Verifies that if a client disconnects from the server, then an ongoing attempt to connect, currently waiting
 * for the next reconnect attempt, is cancelled.
 *
 * @param ctx The test execution context.
 */
@Test
public void testDisconnectAbortsConnectAttemptWaitingForReconnect(final VertxTestContext ctx) {
    final long reconnectTimerId = 32L;
    final long reconnectMinDelay = 20L;
    // GIVEN a client that is configured to connect to a peer
    // to which the connection is only getting established on the 2nd attempt, after some delay.
    // the reconnect timer handler will not get invoked, timer should get cancelled
    final AtomicBoolean reconnectTimerStarted = new AtomicBoolean();
    when(vertx.setTimer(eq(reconnectMinDelay), any())).thenAnswer(invocation -> {
        reconnectTimerStarted.set(true);
        return reconnectTimerId;
    });
    when(vertx.cancelTimer(eq(reconnectTimerId))).thenReturn(true);
    connectionFactory = new DisconnectHandlerProvidingConnectionFactory(con) {

        @Override
        public void connect(final ProtonClientOptions options, final String username, final String password, final String containerId, final Handler<AsyncResult<ProtonConnection>> closeHandler, final Handler<ProtonConnection> disconnectHandler, final Handler<AsyncResult<ProtonConnection>> connectionResultHandler) {
            super.connect(options, username, password, containerId, closeHandler, disconnectHandler, connectionResultHandler);
        }
    };
    connectionFactory.setExpectedFailingConnectionAttempts(1);
    props.setReconnectMinDelay(reconnectMinDelay);
    honoConnection = new HonoConnectionImpl(vertx, connectionFactory, props);
    // WHEN trying to connect
    final Future<HonoConnection> connectFuture = honoConnection.connect();
    assertThat(reconnectTimerStarted.get()).isTrue();
    // and disconnecting before the connection has been established
    honoConnection.disconnect();
    // THEN the reconnectTimer has been cancelled
    verify(vertx).cancelTimer(eq(reconnectTimerId));
    // AND the connect attempt is failed
    connectFuture.onComplete(ctx.failing(cause -> {
        ctx.verify(() -> assertThat(((ClientErrorException) cause).getErrorCode()).isEqualTo(HttpURLConnection.HTTP_CONFLICT));
        ctx.completeNow();
    }));
}
Also used : HttpURLConnection(java.net.HttpURLConnection) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonReceiver(io.vertx.proton.ProtonReceiver) BeforeEach(org.junit.jupiter.api.BeforeEach) ArgumentMatchers.eq(org.mockito.ArgumentMatchers.eq) Context(io.vertx.core.Context) Timeout(io.vertx.junit5.Timeout) ConnectionFactory(org.eclipse.hono.connection.ConnectionFactory) SaslSystemException(io.vertx.proton.sasl.SaslSystemException) ExtendWith(org.junit.jupiter.api.extension.ExtendWith) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) Mockito.doAnswer(org.mockito.Mockito.doAnswer) DisconnectListener(org.eclipse.hono.client.DisconnectListener) AmqpError(org.apache.qpid.proton.amqp.transport.AmqpError) ClientConfigProperties(org.eclipse.hono.config.ClientConfigProperties) Predicate(java.util.function.Predicate) ProtonQoS(io.vertx.proton.ProtonQoS) VertxExtension(io.vertx.junit5.VertxExtension) Future(io.vertx.core.Future) AdditionalAnswers(org.mockito.AdditionalAnswers) Test(org.junit.jupiter.api.Test) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) VertxMockSupport(org.eclipse.hono.test.VertxMockSupport) ProtonSender(io.vertx.proton.ProtonSender) Mockito.mock(org.mockito.Mockito.mock) ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) VertxTestContext(io.vertx.junit5.VertxTestContext) ArgumentMatchers.anyLong(org.mockito.ArgumentMatchers.anyLong) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Target(org.apache.qpid.proton.amqp.messaging.Target) ClientErrorException(org.eclipse.hono.client.ClientErrorException) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) AtomicReference(java.util.concurrent.atomic.AtomicReference) Supplier(java.util.function.Supplier) CompositeFuture(io.vertx.core.CompositeFuture) ProtonSession(io.vertx.proton.ProtonSession) TelemetryConstants(org.eclipse.hono.util.TelemetryConstants) ArgumentCaptor(org.mockito.ArgumentCaptor) ProtonClientOptions(io.vertx.proton.ProtonClientOptions) Symbol(org.apache.qpid.proton.amqp.Symbol) BiConsumer(java.util.function.BiConsumer) UnsignedLong(org.apache.qpid.proton.amqp.UnsignedLong) AsyncResult(io.vertx.core.AsyncResult) HonoConnection(org.eclipse.hono.client.HonoConnection) Promise(io.vertx.core.Promise) Vertx(io.vertx.core.Vertx) ServerErrorException(org.eclipse.hono.client.ServerErrorException) Mockito.times(org.mockito.Mockito.times) Mockito.when(org.mockito.Mockito.when) Truth.assertThat(com.google.common.truth.Truth.assertThat) Mockito.verify(org.mockito.Mockito.verify) TimeUnit(java.util.concurrent.TimeUnit) Mockito.never(org.mockito.Mockito.never) Source(org.apache.qpid.proton.amqp.transport.Source) Handler(io.vertx.core.Handler) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) HonoConnection(org.eclipse.hono.client.HonoConnection) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ProtonConnection(io.vertx.proton.ProtonConnection) ClientErrorException(org.eclipse.hono.client.ClientErrorException) ProtonClientOptions(io.vertx.proton.ProtonClientOptions) AsyncResult(io.vertx.core.AsyncResult) Test(org.junit.jupiter.api.Test)

Aggregations

HonoConnection (org.eclipse.hono.client.HonoConnection)19 Vertx (io.vertx.core.Vertx)14 ProtonReceiver (io.vertx.proton.ProtonReceiver)13 Context (io.vertx.core.Context)12 Future (io.vertx.core.Future)12 ProtonMessageHandler (io.vertx.proton.ProtonMessageHandler)12 ProtonQoS (io.vertx.proton.ProtonQoS)12 BeforeEach (org.junit.jupiter.api.BeforeEach)12 AsyncResult (io.vertx.core.AsyncResult)11 Handler (io.vertx.core.Handler)11 Promise (io.vertx.core.Promise)11 ProtonSender (io.vertx.proton.ProtonSender)11 HttpURLConnection (java.net.HttpURLConnection)11 AtomicReference (java.util.concurrent.atomic.AtomicReference)11 ServerErrorException (org.eclipse.hono.client.ServerErrorException)11 ClientConfigProperties (org.eclipse.hono.config.ClientConfigProperties)11 ProtonClientOptions (io.vertx.proton.ProtonClientOptions)10 ProtonConnection (io.vertx.proton.ProtonConnection)10 ProtonSession (io.vertx.proton.ProtonSession)10 SaslSystemException (io.vertx.proton.sasl.SaslSystemException)10