Search in sources :

Example 11 with MessageSender

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

the class AbstractVertxBasedMqttProtocolAdapterTest method givenAnEventSenderForOutcome.

private void givenAnEventSenderForOutcome(final Future<ProtonDelivery> outcome) {
    final MessageSender sender = mock(MessageSender.class);
    when(sender.getEndpoint()).thenReturn(EventConstants.EVENT_ENDPOINT);
    when(sender.send(any(Message.class))).thenReturn(outcome);
    when(messagingClient.getOrCreateEventSender(anyString())).thenReturn(Future.succeededFuture(sender));
}
Also used : MqttPublishMessage(io.vertx.mqtt.messages.MqttPublishMessage) Message(org.apache.qpid.proton.message.Message) MessageSender(org.eclipse.hono.client.MessageSender)

Example 12 with MessageSender

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

the class AbstractVertxBasedMqttProtocolAdapterTest method testUploadTelemetryMessageFailsForUnknownDevice.

/**
 * Verifies that the adapter does not forward a message published by a device
 * if the device's registration status cannot be asserted.
 *
 * @param ctx The vert.x test context.
 */
@Test
public void testUploadTelemetryMessageFailsForUnknownDevice(final TestContext ctx) {
    // GIVEN an adapter
    final MqttServer server = getMqttServer(false);
    final AbstractVertxBasedMqttProtocolAdapter<ProtocolAdapterProperties> adapter = getAdapter(server);
    givenATelemetrySenderForOutcome(Future.succeededFuture(mock(ProtonDelivery.class)));
    // WHEN an unknown device publishes a telemetry message
    when(regClient.assertRegistration(eq("unknown"), any())).thenReturn(Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_NOT_FOUND)));
    final MessageSender sender = mock(MessageSender.class);
    when(messagingClient.getOrCreateTelemetrySender(anyString())).thenReturn(Future.succeededFuture(sender));
    adapter.uploadTelemetryMessage(new MqttContext(mock(MqttPublishMessage.class), mock(MqttEndpoint.class)), "my-tenant", "unknown", Buffer.buffer("test")).setHandler(ctx.asyncAssertFailure(t -> {
        // THEN the message has not been sent downstream
        verify(sender, never()).send(any(Message.class));
        // because the device's registration status could not be asserted
        ctx.assertEquals(HttpURLConnection.HTTP_NOT_FOUND, ((ClientErrorException) t).getErrorCode());
    }));
}
Also used : CoreMatchers.is(org.hamcrest.CoreMatchers.is) HttpURLConnection(java.net.HttpURLConnection) TestContext(io.vertx.ext.unit.TestContext) Async(io.vertx.ext.unit.Async) MqttQoS(io.netty.handler.codec.mqtt.MqttQoS) ArgumentMatchers(org.mockito.ArgumentMatchers) ProtonDelivery(io.vertx.proton.ProtonDelivery) MqttConnectReturnCode(io.netty.handler.codec.mqtt.MqttConnectReturnCode) TenantConstants(org.eclipse.hono.util.TenantConstants) RunWith(org.junit.runner.RunWith) MqttEndpoint(io.vertx.mqtt.MqttEndpoint) MqttPublishMessage(io.vertx.mqtt.messages.MqttPublishMessage) ClientErrorException(org.eclipse.hono.client.ClientErrorException) Context(io.vertx.core.Context) MqttServer(io.vertx.mqtt.MqttServer) Assert.assertThat(org.junit.Assert.assertThat) TelemetryConstants(org.eclipse.hono.util.TelemetryConstants) ArgumentCaptor(org.mockito.ArgumentCaptor) TenantClient(org.eclipse.hono.client.TenantClient) MessageSender(org.eclipse.hono.client.MessageSender) BiConsumer(java.util.function.BiConsumer) Timeout(org.junit.rules.Timeout) Message(org.apache.qpid.proton.message.Message) RegistrationClient(org.eclipse.hono.client.RegistrationClient) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) JsonObject(io.vertx.core.json.JsonObject) AsyncResult(io.vertx.core.AsyncResult) HonoClient(org.eclipse.hono.client.HonoClient) Before(org.junit.Before) ProtocolAdapterProperties(org.eclipse.hono.config.ProtocolAdapterProperties) AfterClass(org.junit.AfterClass) UsernamePasswordCredentials(org.eclipse.hono.service.auth.device.UsernamePasswordCredentials) DeviceCredentials(org.eclipse.hono.service.auth.device.DeviceCredentials) Vertx(io.vertx.core.Vertx) RegistrationConstants(org.eclipse.hono.util.RegistrationConstants) Test(org.junit.Test) VertxUnitRunner(io.vertx.ext.unit.junit.VertxUnitRunner) EventConstants(org.eclipse.hono.util.EventConstants) Future(io.vertx.core.Future) TenantObject(org.eclipse.hono.util.TenantObject) TimeUnit(java.util.concurrent.TimeUnit) Mockito(org.mockito.Mockito) HonoClientBasedAuthProvider(org.eclipse.hono.service.auth.device.HonoClientBasedAuthProvider) Rule(org.junit.Rule) Buffer(io.vertx.core.buffer.Buffer) MqttAuth(io.vertx.mqtt.MqttAuth) Device(org.eclipse.hono.service.auth.device.Device) Handler(io.vertx.core.Handler) ProtocolAdapterProperties(org.eclipse.hono.config.ProtocolAdapterProperties) MqttPublishMessage(io.vertx.mqtt.messages.MqttPublishMessage) MqttEndpoint(io.vertx.mqtt.MqttEndpoint) MessageSender(org.eclipse.hono.client.MessageSender) MqttServer(io.vertx.mqtt.MqttServer) ClientErrorException(org.eclipse.hono.client.ClientErrorException) Test(org.junit.Test)

Example 13 with MessageSender

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

the class HonoClientImpl method getOrCreateSender.

Future<MessageSender> getOrCreateSender(final String key, final Supplier<Future<MessageSender>> newSenderSupplier) {
    final Future<MessageSender> result = Future.future();
    context.runOnContext(get -> {
        final MessageSender sender = activeSenders.get(key);
        if (sender != null && sender.isOpen()) {
            LOG.debug("reusing existing message sender [target: {}, credit: {}]", key, sender.getCredit());
            result.complete(sender);
        } else if (!creationLocks.computeIfAbsent(key, k -> Boolean.FALSE)) {
            // register a handler to be notified if the underlying connection to the server fails
            // so that we can fail the result handler passed in
            final Handler<Void> connectionFailureHandler = connectionLost -> {
                // remove lock so that next attempt to open a sender doesn't fail
                creationLocks.remove(key);
                result.tryFail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "no connection to service"));
            };
            creationRequests.add(connectionFailureHandler);
            creationLocks.put(key, Boolean.TRUE);
            LOG.debug("creating new message sender for {}", key);
            newSenderSupplier.get().setHandler(creationAttempt -> {
                creationLocks.remove(key);
                creationRequests.remove(connectionFailureHandler);
                if (creationAttempt.succeeded()) {
                    MessageSender newSender = creationAttempt.result();
                    LOG.debug("successfully created new message sender for {}", key);
                    activeSenders.put(key, newSender);
                    result.tryComplete(newSender);
                } else {
                    LOG.debug("failed to create new message sender for {}", key, creationAttempt.cause());
                    activeSenders.remove(key);
                    result.tryFail(creationAttempt.cause());
                }
            });
        } else {
            LOG.debug("already trying to create a message sender for {}", key);
            result.fail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "no connection to service"));
        }
    });
    return result;
}
Also used : HttpURLConnection(java.net.HttpURLConnection) RequestResponseClient(org.eclipse.hono.client.RequestResponseClient) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonDelivery(io.vertx.proton.ProtonDelivery) LoggerFactory(org.slf4j.LoggerFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) MessageConsumer(org.eclipse.hono.client.MessageConsumer) ClientErrorException(org.eclipse.hono.client.ClientErrorException) Supplier(java.util.function.Supplier) Constants(org.eclipse.hono.util.Constants) Context(io.vertx.core.Context) ArrayList(java.util.ArrayList) ConnectionFactory(org.eclipse.hono.connection.ConnectionFactory) CredentialsClient(org.eclipse.hono.client.CredentialsClient) ProtonClientOptions(io.vertx.proton.ProtonClientOptions) TenantClient(org.eclipse.hono.client.TenantClient) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ConnectionFactoryBuilder(org.eclipse.hono.connection.ConnectionFactoryImpl.ConnectionFactoryBuilder) Map(java.util.Map) MessageSender(org.eclipse.hono.client.MessageSender) BiConsumer(java.util.function.BiConsumer) Message(org.apache.qpid.proton.message.Message) RegistrationClient(org.eclipse.hono.client.RegistrationClient) AsyncResult(io.vertx.core.AsyncResult) HonoClient(org.eclipse.hono.client.HonoClient) ClientConfigProperties(org.eclipse.hono.config.ClientConfigProperties) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) Vertx(io.vertx.core.Vertx) ServerErrorException(org.eclipse.hono.client.ServerErrorException) CacheProvider(org.eclipse.hono.cache.CacheProvider) Future(io.vertx.core.Future) Objects(java.util.Objects) TimeUnit(java.util.concurrent.TimeUnit) Consumer(java.util.function.Consumer) CountDownLatch(java.util.concurrent.CountDownLatch) List(java.util.List) Handler(io.vertx.core.Handler) MessageSender(org.eclipse.hono.client.MessageSender) Handler(io.vertx.core.Handler) ServerErrorException(org.eclipse.hono.client.ServerErrorException)

Example 14 with MessageSender

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

the class EventSenderImplTest method testSendMessageWaitsForAcceptedOutcome.

/**
 * Verifies that the sender waits for the peer to settle and
 * accept a message before succeeding the returned future.
 *
 * @param ctx The vert.x test context.
 */
@SuppressWarnings({ "unchecked" })
@Test
public void testSendMessageWaitsForAcceptedOutcome(final TestContext ctx) {
    // GIVEN a sender that has credit
    when(sender.sendQueueFull()).thenReturn(Boolean.FALSE);
    MessageSender messageSender = new EventSenderImpl(config, sender, "tenant", "telemetry/tenant", context);
    final AtomicReference<Handler<ProtonDelivery>> handlerRef = new AtomicReference<>();
    doAnswer(invocation -> {
        handlerRef.set(invocation.getArgument(1));
        return mock(ProtonDelivery.class);
    }).when(sender).send(any(Message.class), any(Handler.class));
    // WHEN trying to send a message
    final Future<ProtonDelivery> result = messageSender.send("device", "some payload", "application/text", "token");
    // THEN the message has been sent
    // and the result is not completed yet
    verify(sender).send(any(Message.class), eq(handlerRef.get()));
    assertFalse(result.isComplete());
    // until it gets accepted by the peer
    ProtonDelivery accepted = mock(ProtonDelivery.class);
    when(accepted.remotelySettled()).thenReturn(Boolean.TRUE);
    when(accepted.getRemoteState()).thenReturn(new Accepted());
    handlerRef.get().handle(accepted);
    assertTrue(result.succeeded());
}
Also used : Message(org.apache.qpid.proton.message.Message) ProtonDelivery(io.vertx.proton.ProtonDelivery) MessageSender(org.eclipse.hono.client.MessageSender) Handler(io.vertx.core.Handler) AtomicReference(java.util.concurrent.atomic.AtomicReference) Accepted(org.apache.qpid.proton.amqp.messaging.Accepted) Test(org.junit.Test)

Example 15 with MessageSender

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

the class EventSenderImplTest method testSendMessageFailsForRejectedOutcome.

/**
 * Verifies that the sender fails if the peer does not accept a message.
 *
 * @param ctx The vert.x test context.
 */
@SuppressWarnings({ "unchecked" })
@Test
public void testSendMessageFailsForRejectedOutcome(final TestContext ctx) {
    // GIVEN a sender that has credit
    when(sender.sendQueueFull()).thenReturn(Boolean.FALSE);
    MessageSender messageSender = new EventSenderImpl(config, sender, "tenant", "telemetry/tenant", context);
    final AtomicReference<Handler<ProtonDelivery>> handlerRef = new AtomicReference<>();
    doAnswer(invocation -> {
        handlerRef.set(invocation.getArgument(1));
        return mock(ProtonDelivery.class);
    }).when(sender).send(any(Message.class), any(Handler.class));
    // WHEN trying to send a message
    final Future<ProtonDelivery> result = messageSender.send("device", "some payload", "application/text", "token");
    // THEN the message has been sent
    // and the result is not completed yet
    verify(sender).send(any(Message.class), eq(handlerRef.get()));
    assertFalse(result.isComplete());
    // and the result fails once the peer rejects the message
    ProtonDelivery rejected = mock(ProtonDelivery.class);
    when(rejected.remotelySettled()).thenReturn(Boolean.TRUE);
    when(rejected.getRemoteState()).thenReturn(new Rejected());
    handlerRef.get().handle(rejected);
    assertFalse(result.succeeded());
}
Also used : Message(org.apache.qpid.proton.message.Message) ProtonDelivery(io.vertx.proton.ProtonDelivery) MessageSender(org.eclipse.hono.client.MessageSender) Handler(io.vertx.core.Handler) AtomicReference(java.util.concurrent.atomic.AtomicReference) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) Test(org.junit.Test)

Aggregations

MessageSender (org.eclipse.hono.client.MessageSender)17 Message (org.apache.qpid.proton.message.Message)16 Test (org.junit.Test)11 Handler (io.vertx.core.Handler)8 ProtonDelivery (io.vertx.proton.ProtonDelivery)8 Future (io.vertx.core.Future)7 Vertx (io.vertx.core.Vertx)6 TestContext (io.vertx.ext.unit.TestContext)5 TimeUnit (java.util.concurrent.TimeUnit)5 AtomicReference (java.util.concurrent.atomic.AtomicReference)5 ClientErrorException (org.eclipse.hono.client.ClientErrorException)5 HonoClient (org.eclipse.hono.client.HonoClient)5 Constants (org.eclipse.hono.util.Constants)5 Buffer (io.vertx.core.buffer.Buffer)4 JsonObject (io.vertx.core.json.JsonObject)4 Async (io.vertx.ext.unit.Async)4 MqttPublishMessage (io.vertx.mqtt.messages.MqttPublishMessage)4 HttpURLConnection (java.net.HttpURLConnection)4 RegistrationClient (org.eclipse.hono.client.RegistrationClient)4 TenantObject (org.eclipse.hono.util.TenantObject)4