diff --git a/client-device-connection-infinispan/src/main/java/org/eclipse/hono/deviceconnection/infinispan/client/CacheBasedDeviceConnectionClient.java b/client-device-connection-infinispan/src/main/java/org/eclipse/hono/deviceconnection/infinispan/client/CacheBasedDeviceConnectionClient.java index 365ce8c873..386c421630 100644 --- a/client-device-connection-infinispan/src/main/java/org/eclipse/hono/deviceconnection/infinispan/client/CacheBasedDeviceConnectionClient.java +++ b/client-device-connection-infinispan/src/main/java/org/eclipse/hono/deviceconnection/infinispan/client/CacheBasedDeviceConnectionClient.java @@ -122,7 +122,7 @@ public Future setCommandHandlingAdapterInstance(final String deviceId, fin } @Override - public Future removeCommandHandlingAdapterInstance(final String deviceId, final String adapterInstanceId, + public Future removeCommandHandlingAdapterInstance(final String deviceId, final String adapterInstanceId, final SpanContext context) { return cache.removeCommandHandlingAdapterInstance(tenantId, deviceId, adapterInstanceId, context); } diff --git a/client-device-connection-infinispan/src/main/java/org/eclipse/hono/deviceconnection/infinispan/client/CacheBasedDeviceConnectionInfo.java b/client-device-connection-infinispan/src/main/java/org/eclipse/hono/deviceconnection/infinispan/client/CacheBasedDeviceConnectionInfo.java index cbe253fbe2..9d7d3ae951 100644 --- a/client-device-connection-infinispan/src/main/java/org/eclipse/hono/deviceconnection/infinispan/client/CacheBasedDeviceConnectionInfo.java +++ b/client-device-connection-infinispan/src/main/java/org/eclipse/hono/deviceconnection/infinispan/client/CacheBasedDeviceConnectionInfo.java @@ -162,7 +162,7 @@ public Future setCommandHandlingAdapterInstance(final String tenantId, fin } @Override - public Future removeCommandHandlingAdapterInstance(final String tenantId, final String deviceId, + public Future removeCommandHandlingAdapterInstance(final String tenantId, final String deviceId, final String adapterInstanceId, final SpanContext context) { Objects.requireNonNull(tenantId); Objects.requireNonNull(deviceId); @@ -177,16 +177,15 @@ public Future removeCommandHandlingAdapterInstance(final String tenantId, tenantId, deviceId, adapterInstanceId, t); return Future.failedFuture(new ServerErrorException(HttpURLConnection.HTTP_INTERNAL_ERROR, t)); }) - .compose(removed -> { + .map(removed -> { if (!removed) { LOG.debug("command handling adapter instance was not removed, key not mapped or value didn't match [tenant: {}, device-id: {}, adapter-instance: {}]", tenantId, deviceId, adapterInstanceId); - return Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_NOT_FOUND)); } else { LOG.debug("removed command handling adapter instance [tenant: {}, device-id: {}, adapter-instance: {}]", tenantId, deviceId, adapterInstanceId); - return Future.succeededFuture(); } + return removed; }); } diff --git a/client-device-connection-infinispan/src/main/java/org/eclipse/hono/deviceconnection/infinispan/client/DeviceConnectionInfo.java b/client-device-connection-infinispan/src/main/java/org/eclipse/hono/deviceconnection/infinispan/client/DeviceConnectionInfo.java index 823741275e..59a29ed4ed 100644 --- a/client-device-connection-infinispan/src/main/java/org/eclipse/hono/deviceconnection/infinispan/client/DeviceConnectionInfo.java +++ b/client-device-connection-infinispan/src/main/java/org/eclipse/hono/deviceconnection/infinispan/client/DeviceConnectionInfo.java @@ -99,13 +99,14 @@ Future setCommandHandlingAdapterInstance(String tenantId, String deviceId, * @param context The currently active OpenTracing span context or {@code null} if no span is currently active. * Implementing classes should use this as the parent for any span they create for tracing * the execution of this operation. - * @return A future indicating the outcome of the operation. + * @return A future indicating the outcome of the operation, with its value indicating whether the protocol + * adapter instance value was removed or not. *

- * The future will be succeeded if the entry was successfully removed. - * Otherwise the future will be failed with a {@link org.eclipse.hono.client.ServiceInvocationException}. + * The future will be failed with a {@link org.eclipse.hono.client.ServiceInvocationException} if there + * was an error removing the value. * @throws NullPointerException if any of the parameters except context is {@code null}. */ - Future removeCommandHandlingAdapterInstance(String tenantId, String deviceId, String adapterInstanceId, SpanContext context); + Future removeCommandHandlingAdapterInstance(String tenantId, String deviceId, String adapterInstanceId, SpanContext context); /** * Gets information about the adapter instances that can handle a command for the given device. diff --git a/client-device-connection-infinispan/src/test/java/org/eclipse/hono/deviceconnection/infinispan/client/CacheBasedDeviceConnectionInfoTest.java b/client-device-connection-infinispan/src/test/java/org/eclipse/hono/deviceconnection/infinispan/client/CacheBasedDeviceConnectionInfoTest.java index ce05e2c777..397a31e622 100644 --- a/client-device-connection-infinispan/src/test/java/org/eclipse/hono/deviceconnection/infinispan/client/CacheBasedDeviceConnectionInfoTest.java +++ b/client-device-connection-infinispan/src/test/java/org/eclipse/hono/deviceconnection/infinispan/client/CacheBasedDeviceConnectionInfoTest.java @@ -227,11 +227,14 @@ public void testRemoveCommandHandlingAdapterInstanceSucceeds(final VertxTestCont info.setCommandHandlingAdapterInstance(Constants.DEFAULT_TENANT, deviceId, adapterInstance, null, spanContext) .compose(v -> info.removeCommandHandlingAdapterInstance(Constants.DEFAULT_TENANT, deviceId, adapterInstance, spanContext)) - .setHandler(ctx.succeeding(result -> ctx.completeNow())); + .setHandler(ctx.succeeding(result -> ctx.verify(() -> { + assertThat(result).isTrue(); + ctx.completeNow(); + }))); } /** - * Verifies that the removeCommandHandlingAdapterInstance operation fails with a NOT_FOUND status if + * Verifies that the removeCommandHandlingAdapterInstance operation result is false if * no entry was registered for the device. Only an adapter instance for another device of the tenant was * registered. * @@ -244,16 +247,15 @@ public void testRemoveCommandHandlingAdapterInstanceFailsForOtherDevice(final Ve info.setCommandHandlingAdapterInstance(Constants.DEFAULT_TENANT, deviceId, adapterInstance, null, spanContext) .compose(v -> { return info.removeCommandHandlingAdapterInstance(Constants.DEFAULT_TENANT, "otherDevice", adapterInstance, spanContext); - }).setHandler(ctx.failing(t -> ctx.verify(() -> { - assertThat(t).isInstanceOf(ServiceInvocationException.class); - assertThat(((ServiceInvocationException) t).getErrorCode()).isEqualTo(HttpURLConnection.HTTP_NOT_FOUND); + }).setHandler(ctx.succeeding(result -> ctx.verify(() -> { + assertThat(result).isFalse(); ctx.completeNow(); }))); } /** - * Verifies that the removeCommandHandlingAdapterInstance operation fails with a NOT_FOUND status - * if the given adapter instance parameter doesn't match the one of the entry registered for the given device. + * Verifies that the removeCommandHandlingAdapterInstance operation result is false if + * the given adapter instance parameter doesn't match the one of the entry registered for the given device. * * @param ctx The vert.x context. */ @@ -264,9 +266,8 @@ public void testRemoveCommandHandlingAdapterInstanceFailsForOtherAdapterInstance info.setCommandHandlingAdapterInstance(Constants.DEFAULT_TENANT, deviceId, adapterInstance, null, spanContext) .compose(v -> { return info.removeCommandHandlingAdapterInstance(Constants.DEFAULT_TENANT, deviceId, "otherAdapterInstance", spanContext); - }).setHandler(ctx.failing(t -> ctx.verify(() -> { - assertThat(t).isInstanceOf(ServiceInvocationException.class); - assertThat(((ServiceInvocationException) t).getErrorCode()).isEqualTo(HttpURLConnection.HTTP_NOT_FOUND); + }).setHandler(ctx.succeeding(result -> ctx.verify(() -> { + assertThat(result).isFalse(); ctx.completeNow(); }))); } diff --git a/client/src/main/java/org/eclipse/hono/client/DeviceConnectionClient.java b/client/src/main/java/org/eclipse/hono/client/DeviceConnectionClient.java index ab5e4a91ee..65ac1df056 100644 --- a/client/src/main/java/org/eclipse/hono/client/DeviceConnectionClient.java +++ b/client/src/main/java/org/eclipse/hono/client/DeviceConnectionClient.java @@ -95,13 +95,14 @@ Future setCommandHandlingAdapterInstance(String deviceId, String adapterIn * @param context The currently active OpenTracing span context or {@code null} if no span is currently active. * An implementation should use this as the parent for any span it creates for tracing * the execution of this operation. - * @return A future indicating the outcome of the operation. + * @return A future indicating the outcome of the operation, with its value indicating whether the protocol + * adapter instance value was removed or not. *

- * The future will be succeeded if the entry was successfully removed. - * Otherwise the future will be failed with a {@link org.eclipse.hono.client.ServiceInvocationException}. + * The future will be failed with a {@link org.eclipse.hono.client.ServiceInvocationException} if there + * was an error removing the value. * @throws NullPointerException if device id or adapter instance id is {@code null}. */ - Future removeCommandHandlingAdapterInstance(String deviceId, String adapterInstanceId, SpanContext context); + Future removeCommandHandlingAdapterInstance(String deviceId, String adapterInstanceId, SpanContext context); /** * Gets information about the adapter instances that can handle a command for the given device. diff --git a/client/src/main/java/org/eclipse/hono/client/impl/DeviceConnectionClientImpl.java b/client/src/main/java/org/eclipse/hono/client/impl/DeviceConnectionClientImpl.java index 42a77ade8c..09f8f963b1 100644 --- a/client/src/main/java/org/eclipse/hono/client/impl/DeviceConnectionClientImpl.java +++ b/client/src/main/java/org/eclipse/hono/client/impl/DeviceConnectionClientImpl.java @@ -232,7 +232,7 @@ public Future getLastKnownGatewayForDevice(final String deviceId, fi } @Override - public Future removeCommandHandlingAdapterInstance(final String deviceId, final String adapterInstanceId, final SpanContext context) { + public Future removeCommandHandlingAdapterInstance(final String deviceId, final String adapterInstanceId, final SpanContext context) { Objects.requireNonNull(deviceId); Objects.requireNonNull(adapterInstanceId); @@ -252,7 +252,9 @@ public Future removeCommandHandlingAdapterInstance(final String deviceId, return mapResultAndFinishSpan(resultTracker.future(), result -> { switch (result.getStatus()) { case HttpURLConnection.HTTP_NO_CONTENT: - return null; + return Boolean.TRUE; + case HttpURLConnection.HTTP_NOT_FOUND: + return Boolean.FALSE; default: throw StatusCodeMapper.from(result); } diff --git a/client/src/main/java/org/eclipse/hono/client/impl/ProtocolAdapterCommandConsumerFactoryImpl.java b/client/src/main/java/org/eclipse/hono/client/impl/ProtocolAdapterCommandConsumerFactoryImpl.java index eda0cd53b7..60628e3e31 100644 --- a/client/src/main/java/org/eclipse/hono/client/impl/ProtocolAdapterCommandConsumerFactoryImpl.java +++ b/client/src/main/java/org/eclipse/hono/client/impl/ProtocolAdapterCommandConsumerFactoryImpl.java @@ -15,7 +15,6 @@ import java.net.HttpURLConnection; import java.time.Duration; -import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -30,7 +29,6 @@ import org.eclipse.hono.client.MessageConsumer; import org.eclipse.hono.client.ProtocolAdapterCommandConsumerFactory; import org.eclipse.hono.client.ServerErrorException; -import org.eclipse.hono.client.ServiceInvocationException; import org.eclipse.hono.util.CommandConstants; import org.eclipse.hono.util.Constants; import org.eclipse.hono.util.ResourceIdentifier; @@ -173,9 +171,8 @@ private Future doCreateCommandConsumer(final String tenantId, f return setCommandHandlingAdapterInstance(tenantId, deviceId, sanitizedLifespan, context); }) .map(res -> { - final Instant lifespanStart = Instant.now(); final Supplier> onCloseAction = () -> removeCommandConsumer(tenantId, deviceId, - sanitizedLifespan, lifespanStart, context); + sanitizedLifespan, context); return (MessageConsumer) new DeviceSpecificCommandConsumer(onCloseAction); }) .setHandler(result); @@ -197,34 +194,23 @@ private Future setCommandHandlingAdapterInstance(final String tenantId, fi } private Future removeCommandConsumer(final String tenantId, final String deviceId, final Duration lifespan, - final Instant lifespanStart, final SpanContext createCommandConsumerSpanContext) { + final SpanContext createCommandConsumerSpanContext) { log.trace("remove command consumer [tenant-id: {}, device-id: {}]", tenantId, deviceId); adapterInstanceCommandHandler.removeDeviceSpecificCommandHandler(tenantId, deviceId); - final boolean lifespanReached = !lifespan.isNegative() && Instant.now().isAfter(lifespanStart.plus(lifespan)); - // TODO when making handling of the lifespan property mandatory for implementors of the Device Connection API, - // removing the adapter instance can be skipped here if 'lifespanReached' is true return deviceConnectionClientFactory.getOrCreateDeviceConnectionClient(tenantId) .compose(client -> { // The given span context from the createCommandConsumer invocation is only used here if a non-unlimited lifespan is set // meaning creating and removing the consumer will probably happen in a timespan short enough for one overall trace. - // The span context isn't used however if lifespanReached is true since the below 'remove' operation will usually (but not necessarily) - // result in a "not found" error in that case, which is expected and should not cause the overall trace to be marked with an error. - final SpanContext context = !lifespan.isNegative() && !lifespanReached ? createCommandConsumerSpanContext : null; + final SpanContext context = !lifespan.isNegative() ? createCommandConsumerSpanContext : null; return client.removeCommandHandlingAdapterInstance(deviceId, adapterInstanceId, context); - }).recover(thr -> { - if (lifespanReached && thr instanceof ServiceInvocationException - && ((ServiceInvocationException) thr).getErrorCode() == HttpURLConnection.HTTP_NOT_FOUND) { - // entry was not found, meaning it has expired - log.trace("ignoring 404 error when removing command handling adapter instance; entry has already expired [tenant: {}, device: {}]", - tenantId, deviceId); - return Future.succeededFuture(); - } else { - log.info("error removing command handling adapter instance [tenant: {}, device: {}]", tenantId, - deviceId, thr); - return Future.failedFuture(thr); - } - }); + }) + .recover(thr -> { + log.warn("error removing command handling adapter instance [tenant: {}, device: {}]", tenantId, + deviceId, thr); + return Future.failedFuture(thr); + }) + .mapEmpty(); } private Future getOrCreateMappingAndDelegatingCommandConsumer(final String tenantId) { diff --git a/client/src/test/java/org/eclipse/hono/client/impl/DeviceConnectionClientImplTest.java b/client/src/test/java/org/eclipse/hono/client/impl/DeviceConnectionClientImplTest.java index f74d4ee5a1..ea01e4c861 100644 --- a/client/src/test/java/org/eclipse/hono/client/impl/DeviceConnectionClientImplTest.java +++ b/client/src/test/java/org/eclipse/hono/client/impl/DeviceConnectionClientImplTest.java @@ -183,9 +183,10 @@ public void testRemoveCommandHandlingAdapterInstance(final VertxTestContext ctx) // WHEN removing the command handling adapter instance client.removeCommandHandlingAdapterInstance("deviceId", "gatewayId", span.context()) - .setHandler(ctx.succeeding(r -> { + .setHandler(ctx.succeeding(result -> { ctx.verify(() -> { // THEN the response has been handled and the span is finished + assertThat(result).isTrue(); verify(span).finish(); }); ctx.completeNow(); @@ -334,6 +335,34 @@ public void testRemoveCommandHandlingAdapterInstanceFailsWithSendError(final Ver })); } + /** + * Verifies that a client invocation of the remove-cmd-handling-adapter-instance operation + * returns a Boolean.FALSE value if a NOT_FOUND response was returned. + * + * @param ctx The vert.x test context. + */ + @Test + public void testRemoveCommandHandlingAdapterInstanceForNotFoundEntry(final VertxTestContext ctx) { + + // WHEN removing the command handling adapter instance + client.removeCommandHandlingAdapterInstance("deviceId", "gatewayId", span.context()) + .setHandler(ctx.succeeding(result -> { + ctx.verify(() -> { + // THEN the response has been handled and the span is finished + assertThat(result).isFalse(); + verify(span).finish(); + }); + ctx.completeNow(); + })); + + final Message sentMessage = verifySenderSend(); + final Message response = ProtonHelper.message(); + MessageHelper.addProperty(response, MessageHelper.APP_PROPERTY_STATUS, HttpURLConnection.HTTP_NOT_FOUND); + MessageHelper.addCacheDirective(response, CacheDirective.maxAgeDirective(60)); + response.setCorrelationId(sentMessage.getMessageId()); + client.handleResponse(mock(ProtonDelivery.class), response); + } + /** * Verifies that a client invocation of the get-cmd-handling-adapter-instances operation fails * if the device connection service cannot be reached. diff --git a/client/src/test/java/org/eclipse/hono/client/impl/ProtocolAdapterCommandConsumerFactoryImplTest.java b/client/src/test/java/org/eclipse/hono/client/impl/ProtocolAdapterCommandConsumerFactoryImplTest.java index f1adb6787a..9b93615fee 100644 --- a/client/src/test/java/org/eclipse/hono/client/impl/ProtocolAdapterCommandConsumerFactoryImplTest.java +++ b/client/src/test/java/org/eclipse/hono/client/impl/ProtocolAdapterCommandConsumerFactoryImplTest.java @@ -135,8 +135,10 @@ public void setUp() { when(deviceConnectionClientFactory.connect()).thenReturn(Future.succeededFuture(mock(HonoConnection.class))); when(deviceConnectionClientFactory.getOrCreateDeviceConnectionClient(anyString())) .thenReturn(Future.succeededFuture(devConClient)); - when(devConClient.setCommandHandlingAdapterInstance(anyString(), anyString(), any(), any())).thenReturn(Future.succeededFuture()); - when(devConClient.removeCommandHandlingAdapterInstance(anyString(), anyString(), any())).thenReturn(Future.succeededFuture()); + when(devConClient.setCommandHandlingAdapterInstance(anyString(), anyString(), any(), any())) + .thenReturn(Future.succeededFuture()); + when(devConClient.removeCommandHandlingAdapterInstance(anyString(), anyString(), any())) + .thenReturn(Future.succeededFuture(Boolean.TRUE)); commandConsumerFactory = new ProtocolAdapterCommandConsumerFactoryImpl(connection); commandConsumerFactory.initialize(commandTargetMapper, deviceConnectionClientFactory); diff --git a/tests/src/test/java/org/eclipse/hono/tests/jms/JmsBasedDeviceConnectionClient.java b/tests/src/test/java/org/eclipse/hono/tests/jms/JmsBasedDeviceConnectionClient.java index da40182901..09d42c8e95 100644 --- a/tests/src/test/java/org/eclipse/hono/tests/jms/JmsBasedDeviceConnectionClient.java +++ b/tests/src/test/java/org/eclipse/hono/tests/jms/JmsBasedDeviceConnectionClient.java @@ -23,14 +23,14 @@ import javax.jms.JMSException; import javax.jms.Message; -import org.eclipse.hono.client.ClientErrorException; import org.eclipse.hono.client.DeviceConnectionClient; +import org.eclipse.hono.client.ServerErrorException; import org.eclipse.hono.client.ServiceInvocationException; -import org.eclipse.hono.client.StatusCodeMapper; import org.eclipse.hono.config.ClientConfigProperties; import org.eclipse.hono.util.CacheDirective; import org.eclipse.hono.util.DeviceConnectionConstants; import org.eclipse.hono.util.DeviceConnectionConstants.DeviceConnectionAction; +import org.eclipse.hono.util.DeviceConnectionResult; import org.eclipse.hono.util.MessageHelper; import org.eclipse.hono.util.RequestResponseResult; @@ -75,7 +75,7 @@ public static Future create( final JmsBasedDeviceConnectionClient client = new JmsBasedDeviceConnectionClient(connection, clientConfig, tenant); client.createLinks(); return Future.succeededFuture(client); - } catch (JMSException e) { + } catch (final JMSException e) { return Future.failedFuture(e); } } @@ -152,17 +152,39 @@ public Future getCommandHandlingAdapterInstances( * {@inheritDoc} */ @Override - public Future removeCommandHandlingAdapterInstance( + public Future removeCommandHandlingAdapterInstance( final String deviceId, final String adapterInstanceId, final SpanContext context) { - return sendRequest( + return createRequestMessage( DeviceConnectionAction.REMOVE_CMD_HANDLING_ADAPTER_INSTANCE.getSubject(), Map.of(MessageHelper.APP_PROPERTY_DEVICE_ID, deviceId, MessageHelper.APP_PROPERTY_ADAPTER_INSTANCE_ID, adapterInstanceId), null) - .mapEmpty(); + .compose(this::send) + .recover(thr -> { + if (thr instanceof ServiceInvocationException && ((ServiceInvocationException) thr) + .getErrorCode() == HttpURLConnection.HTTP_NOT_FOUND) { + return Future.succeededFuture(DeviceConnectionResult.from(HttpURLConnection.HTTP_NOT_FOUND)); + } + return Future.failedFuture(thr); + }).compose(devConResult -> { + final Promise result = Promise.promise(); + switch (devConResult.getStatus()) { + case HttpURLConnection.HTTP_OK: + case HttpURLConnection.HTTP_NO_CONTENT: + result.complete(Boolean.TRUE); + break; + case HttpURLConnection.HTTP_NOT_FOUND: + result.complete(Boolean.FALSE); + break; + default: + result.fail(new ServerErrorException(HttpURLConnection.HTTP_INTERNAL_ERROR, + "unsupported response status: " + devConResult.getStatus())); + } + return result.future(); + }); } /** @@ -180,6 +202,36 @@ public Future sendRequest( final Map applicationProperties, final Buffer payload) { + return createRequestMessage(operation, applicationProperties, payload) + .compose(this::send) + .compose(devConResult -> { + final Promise result = Promise.promise(); + switch (devConResult.getStatus()) { + case HttpURLConnection.HTTP_OK: + case HttpURLConnection.HTTP_NO_CONTENT: + result.complete(devConResult.getPayload()); + break; + default: + result.fail(new ServerErrorException(HttpURLConnection.HTTP_INTERNAL_ERROR, + "unsupported response status: " + devConResult.getStatus())); + } + return result.future(); + }); + } + + /** + * Creates a request message for the given parameters. + * + * @param operation The name of the operation to invoke or {@code null} if the message + * should not have a subject. + * @param applicationProperties Application properties to set on the request message or + * {@code null} if no properties should be set. + * @param payload Payload to include or {@code null} if the message should have no body. + * @return A succeeded future containing the created message or a failed future if there was an exception + * creating the message. + */ + protected Future createRequestMessage(final String operation, + final Map applicationProperties, final Buffer payload) { try { final Message request = createMessage(payload); @@ -188,7 +240,7 @@ public Future sendRequest( } if (applicationProperties != null) { - for (Map.Entry entry : applicationProperties.entrySet()) { + for (final Map.Entry entry : applicationProperties.entrySet()) { if (entry.getValue() instanceof String) { request.setStringProperty(entry.getKey(), (String) entry.getValue()); } else { @@ -196,24 +248,8 @@ public Future sendRequest( } } } - - return send(request) - .compose(devConResult -> { - final Promise result = Promise.promise(); - switch (devConResult.getStatus()) { - case HttpURLConnection.HTTP_OK: - case HttpURLConnection.HTTP_NO_CONTENT: - result.complete(devConResult.getPayload()); - break; - case HttpURLConnection.HTTP_NOT_FOUND: - result.fail(new ClientErrorException(devConResult.getStatus(), "no data found")); - break; - default: - result.fail(StatusCodeMapper.from(devConResult)); - } - return result.future(); - }); - } catch (JMSException e) { + return Future.succeededFuture(request); + } catch (final JMSException e) { return Future.failedFuture(getServiceInvocationException(e)); } } @@ -230,7 +266,7 @@ protected RequestResponseResult getResult(final int status, final Bu try { final JsonObject json = payload.toJsonObject(); return new RequestResponseResult<>(status, json, null, null); - } catch (DecodeException e) { + } catch (final DecodeException e) { LOGGER.warn("Device Connection service returned malformed payload", e); throw new ServiceInvocationException( HttpURLConnection.HTTP_INTERNAL_ERROR, diff --git a/tests/src/test/java/org/eclipse/hono/tests/registry/DeviceConnectionApiTests.java b/tests/src/test/java/org/eclipse/hono/tests/registry/DeviceConnectionApiTests.java index 9e32c5263d..b69902441c 100644 --- a/tests/src/test/java/org/eclipse/hono/tests/registry/DeviceConnectionApiTests.java +++ b/tests/src/test/java/org/eclipse/hono/tests/registry/DeviceConnectionApiTests.java @@ -187,8 +187,8 @@ public void testGetCommandHandlingAdapterInstancesFailsForNonExistingEntry(final } /** - * Verifies that a request to remove the command-handling adapter instance for a device fails if no - * adapter is registered for the device. + * Verifies that a request to remove the command-handling adapter instance for a device succeeds with + * a false value if no adapter is registered for the device. * * @param ctx The vert.x test context. */ @@ -200,8 +200,8 @@ public void testRemoveCommandHandlingAdapterInstanceFailsForNonExistingEntry(fin getClient(Constants.DEFAULT_TENANT) .compose(client -> client.removeCommandHandlingAdapterInstance(deviceId, "", null)) - .setHandler(ctx.failing(t -> { - ctx.verify(() -> assertErrorCode(t, HttpURLConnection.HTTP_NOT_FOUND)); + .setHandler(ctx.succeeding(result -> { + ctx.verify(() -> assertThat(result).isFalse()); ctx.completeNow(); })); }