org.eclipse.californium.core.coap.OptionSet Java Examples

The following examples show how to use org.eclipse.californium.core.coap.OptionSet. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: CoapTestBase.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that a number of messages uploaded to Hono's CoAP adapter using TLS_PSK based authentication can be
 * successfully consumed via the AMQP Messaging Network.
 *
 * @param ctx The test context.
 * @throws InterruptedException if the test fails.
 */
@Test
public void testUploadMessagesUsingPsk(final VertxTestContext ctx) throws InterruptedException {

    final Tenant tenant = new Tenant();

    final VertxTestContext setup = new VertxTestContext();
    helper.registry.addPskDeviceForTenant(tenantId, tenant, deviceId, SECRET)
    .onComplete(setup.completing());
    ctx.verify(() -> assertThat(setup.awaitCompletion(5, TimeUnit.SECONDS)).isTrue());

    final CoapClient client = getCoapsClient(deviceId, tenantId, SECRET);

    testUploadMessages(ctx, tenantId,
            () -> warmUp(client, createCoapsRequest(Code.POST, getPostResource(), 0)),
            count -> {
                final Promise<OptionSet> result = Promise.promise();
                final Request request = createCoapsRequest(Code.POST, getPostResource(), count);
                client.advanced(getHandler(result), request);
                return result.future();
            });
}
 
Example #2
Source File: CoapTestBase.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
private void assertResponseContainsOneWayCommand(
        final CoapCommandEndpointConfiguration endpointConfiguration,
        final OptionSet responseOptions,
        final String expectedCommand,
        final String tenantId,
        final String commandTargetDeviceId) {

    assertThat(responseOptions.getLocationQuery())
        .as("response doesn't contain command")
        .contains(expectedCommand);
    assertThat(responseOptions.getContentFormat()).isEqualTo(MediaTypeRegistry.APPLICATION_JSON);
    assertThat(responseOptions.getLocationPath()).contains(CommandConstants.COMMAND_ENDPOINT, Index.atIndex(0));
    if (endpointConfiguration.isSubscribeAsGateway()) {
        assertThat(responseOptions.getLocationPath()).contains(tenantId, Index.atIndex(1));
        assertThat(responseOptions.getLocationPath()).contains(commandTargetDeviceId, Index.atIndex(2));
    }
}
 
Example #3
Source File: CoapTestBase.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
private void assertResponseContainsCommand(
        final CoapCommandEndpointConfiguration endpointConfiguration,
        final OptionSet responseOptions,
        final String expectedCommand,
        final String tenantId,
        final String commandTargetDeviceId) {

    assertThat(responseOptions.getLocationQuery())
        .as("location query must contain parameter [%s]", expectedCommand)
        .contains(expectedCommand);
    assertThat(responseOptions.getContentFormat()).isEqualTo(MediaTypeRegistry.APPLICATION_JSON);
    int idx = 0;
    assertThat(responseOptions.getLocationPath()).contains(CommandConstants.COMMAND_RESPONSE_ENDPOINT, Index.atIndex(idx++));
    if (endpointConfiguration.isSubscribeAsGateway()) {
        assertThat(responseOptions.getLocationPath()).contains(tenantId, Index.atIndex(idx++));
        assertThat(responseOptions.getLocationPath()).contains(commandTargetDeviceId, Index.atIndex(idx++));
    }
    // request ID
    assertThat(responseOptions.getLocationPath().get(idx))
        .as("location path must contain command request ID")
        .isNotNull();
}
 
Example #4
Source File: CoapTestBase.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that the CoAP adapter rejects messages from a gateway for a device that it is not authorized for with a
 * 403.
 *
 * @param ctx The test context
 */
@Test
@Timeout(value = 10, timeUnit = TimeUnit.SECONDS)
public void testUploadMessageFailsForUnauthorizedGateway(final VertxTestContext ctx) {

    // GIVEN a device that is connected via gateway "not-the-created-gateway"
    final Tenant tenant = new Tenant();
    final String gatewayId = helper.getRandomDeviceId(tenantId);
    final Device deviceData = new Device();
    deviceData.setVia(Collections.singletonList("not-the-created-gateway"));

    helper.registry.addPskDeviceForTenant(tenantId, tenant, gatewayId, SECRET)
    .compose(ok -> helper.registry.registerDevice(tenantId, deviceId, deviceData))
    .compose(ok -> {

        // WHEN another gateway tries to upload a message for the device
        final Promise<OptionSet> result = Promise.promise();
        final CoapClient client = getCoapsClient(gatewayId, tenantId, SECRET);
        client.advanced(getHandler(result, ResponseCode.FORBIDDEN),
                createCoapsRequest(Code.PUT, getPutResource(tenantId, deviceId), 0));
        return result.future();
    })
    .onComplete(ctx.completing());
}
 
Example #5
Source File: CoapTestBase.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that the CoAP adapter rejects messages from a disabled gateway
 * for an enabled device with a 403.
 *
 * @param ctx The test context
 */
@Test
@Timeout(value = 10, timeUnit = TimeUnit.SECONDS)
public void testUploadMessageFailsForDisabledGateway(final VertxTestContext ctx) {

    // GIVEN a device that is connected via a disabled gateway
    final Tenant tenant = new Tenant();
    final String gatewayId = helper.getRandomDeviceId(tenantId);
    final Device gatewayData = new Device();
    gatewayData.setEnabled(false);
    final Device deviceData = new Device();
    deviceData.setVia(Collections.singletonList(gatewayId));

    helper.registry.addPskDeviceForTenant(tenantId, tenant, gatewayId, gatewayData, SECRET)
    .compose(ok -> helper.registry.registerDevice(tenantId, deviceId, deviceData))
    .compose(ok -> {

        // WHEN the gateway tries to upload a message for the device
        final Promise<OptionSet> result = Promise.promise();
        final CoapClient client = getCoapsClient(gatewayId, tenantId, SECRET);
        client.advanced(getHandler(result, ResponseCode.FORBIDDEN), createCoapsRequest(Code.PUT, getPutResource(tenantId, deviceId), 0));
        return result.future();
    })
    .onComplete(ctx.completing());
}
 
Example #6
Source File: CoapTestBase.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that the CoAP adapter rejects messages from a disabled device.
 *
 * @param ctx The test context
 */
@Test
@Timeout(value = 10, timeUnit = TimeUnit.SECONDS)
public void testUploadMessageFailsForDisabledDevice(final VertxTestContext ctx) {

    // GIVEN a disabled device
    final Tenant tenant = new Tenant();
    final Device deviceData = new Device();
    deviceData.setEnabled(false);

    helper.registry.addPskDeviceForTenant(tenantId, tenant, deviceId, deviceData, SECRET)
    .compose(ok -> {

        // WHEN the device tries to upload a message
        final CoapClient client = getCoapsClient(deviceId, tenantId, SECRET);
        final Promise<OptionSet> result = Promise.promise();
        client.advanced(getHandler(result, ResponseCode.NOT_FOUND), createCoapsRequest(Code.POST, getPostResource(), 0));
        return result.future();
    })
    .onComplete(ctx.completing());
}
 
Example #7
Source File: CoapTestBase.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that the CoAP adapter rejects messages from a device that belongs to a tenant for which the CoAP adapter
 * has been disabled.
 *
 * @param ctx The test context
 */
@Test
@Timeout(value = 10, timeUnit = TimeUnit.SECONDS)
public void testUploadMessageFailsForDisabledTenant(final VertxTestContext ctx) {

    // GIVEN a tenant for which the CoAP adapter is disabled
    final Tenant tenant = new Tenant();
    tenant.addAdapterConfig(new Adapter(Constants.PROTOCOL_ADAPTER_TYPE_COAP).setEnabled(false));

    helper.registry.addPskDeviceForTenant(tenantId, tenant, deviceId, SECRET)
    .compose(ok -> {

        // WHEN a device that belongs to the tenant uploads a message
        final CoapClient client = getCoapsClient(deviceId, tenantId, SECRET);
        final Promise<OptionSet> result = Promise.promise();
        client.advanced(getHandler(result, ResponseCode.FORBIDDEN), createCoapsRequest(Code.POST, getPostResource(), 0));
        return result.future();
    })
    .onComplete(ctx.completing());
}
 
Example #8
Source File: CoapTestBase.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that the adapter fails to authenticate a device if the shared key registered
 * for the device does not match the key used by the device in the DTLS handshake.
 *
 * @param ctx The vert.x test context.
 */
@Test
@Timeout(value = 10, timeUnit = TimeUnit.SECONDS)
public void testUploadFailsForNonMatchingSharedKey(final VertxTestContext ctx) {

    final Tenant tenant = new Tenant();

    // GIVEN a device for which PSK credentials have been registered
    helper.registry.addPskDeviceForTenant(tenantId, tenant, deviceId, "NOT" + SECRET)
    .compose(ok -> {
        // WHEN a device tries to upload data and authenticate using the PSK
        // identity for which the server has a different shared secret on record
        final CoapClient client = getCoapsClient(deviceId, tenantId, SECRET);
        final Promise<OptionSet> result = Promise.promise();
        client.advanced(getHandler(result), createCoapsRequest(Code.POST, getPostResource(), 0));
        return result.future();
    })
    .onComplete(ctx.failing(t -> {
        // THEN the request fails because the DTLS handshake cannot be completed
        assertStatus(ctx, HttpURLConnection.HTTP_UNAVAILABLE, t);
        ctx.completeNow();
    }));
}
 
Example #9
Source File: CoapTestBase.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Gets a handler for CoAP responses.
 *
 * @param responseHandler The handler to invoke with the outcome of the request. the handler will be invoked with a
 *            succeeded result if the response contains the expected code. Otherwise it will be invoked with a
 *            result that is failed with a {@link CoapResultException}.
 * @param expectedStatusCode The status code that is expected in the response.
 * @return The handler.
 */
protected final CoapHandler getHandler(final Handler<AsyncResult<OptionSet>> responseHandler, final ResponseCode expectedStatusCode) {
    return new CoapHandler() {

        @Override
        public void onLoad(final CoapResponse response) {
            if (response.getCode() == expectedStatusCode) {
                logger.debug("=> received {}", Utils.prettyPrint(response));
                responseHandler.handle(Future.succeededFuture(response.getOptions()));
            } else {
                logger.warn("expected {} => received {}", expectedStatusCode, Utils.prettyPrint(response));
                responseHandler.handle(Future.failedFuture(
                        new CoapResultException(toHttpStatusCode(response.getCode()), response.getResponseText())));
            }
        }

        @Override
        public void onError() {
            responseHandler
                    .handle(Future.failedFuture(new CoapResultException(HttpURLConnection.HTTP_UNAVAILABLE)));
        }
    };
}
 
Example #10
Source File: TelemetryCoapIT.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that a number of telemetry messages uploaded to Hono's CoAP adapter
 * using QoS 1 can be successfully consumed via the AMQP Messaging Network.
 *
 * @param ctx The test context.
 * @throws InterruptedException if the test fails.
 */
@Test
public void testUploadUsingQoS1(final VertxTestContext ctx) throws InterruptedException {

    final Tenant tenant = new Tenant();

    final VertxTestContext setup = new VertxTestContext();
    helper.registry.addPskDeviceForTenant(tenantId, tenant, deviceId, SECRET)
    .onComplete(setup.completing());
    ctx.verify(() -> assertThat(setup.awaitCompletion(5, TimeUnit.SECONDS)).isTrue());

    final CoapClient client = getCoapsClient(deviceId, tenantId, SECRET);

    testUploadMessages(ctx, tenantId,
            () -> warmUp(client, createCoapsRequest(Code.POST, Type.CON, getPostResource(), 0)),
            count -> {
        final Promise<OptionSet> result = Promise.promise();
        final Request request = createCoapsRequest(Code.POST, Type.CON, getPostResource(), count);
        client.advanced(getHandler(result), request);
        return result.future();
    });
}
 
Example #11
Source File: TelemetryCoapIT.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that the upload of a telemetry message containing a payload that
 * exceeds the CoAP adapter's configured max payload size fails with a 4.13
 * response code.
 *
 * @param ctx The test context.
 * @throws IOException if the CoAP request cannot be sent to the adapter.
 * @throws ConnectorException  if the CoAP request cannot be sent to the adapter.
 */
@Test
@Timeout(value = 10, timeUnit = TimeUnit.SECONDS)
public void testUploadFailsForLargePayload(final VertxTestContext ctx) throws ConnectorException, IOException {

    final Tenant tenant = new Tenant();

    helper.registry.addPskDeviceForTenant(tenantId, tenant, deviceId, SECRET)
    .compose(ok -> {
        final CoapClient client = getCoapsClient(deviceId, tenantId, SECRET);
        final Request request = createCoapsRequest(Code.POST, Type.CON, getPostResource(), IntegrationTestSupport.getPayload(4096));
        final Promise<OptionSet> result = Promise.promise();
        client.advanced(getHandler(result, ResponseCode.REQUEST_ENTITY_TOO_LARGE), request);
        return result.future();
    })
    .onComplete(ctx.completing());
}
 
Example #12
Source File: CoapTestBase.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Verifies that a number of messages uploaded to Hono's CoAP adapter
 * can be successfully consumed via the AMQP Messaging Network.
 *
 * @param ctx The test context.
 * @throws InterruptedException if the test fails.
 */
@Test
public void testUploadMessagesAnonymously(final VertxTestContext ctx) throws InterruptedException {

    final Tenant tenant = new Tenant();

    final VertxTestContext setup = new VertxTestContext();
    helper.registry.addDeviceForTenant(tenantId, tenant, deviceId, SECRET)
    .onComplete(setup.completing());
    ctx.verify(() -> assertThat(setup.awaitCompletion(5, TimeUnit.SECONDS)).isTrue());

    final CoapClient client = getCoapClient();
    testUploadMessages(ctx, tenantId,
            () -> warmUp(client, createCoapRequest(Code.PUT, getPutResource(tenantId, deviceId), 0)),
            count -> {
                final Promise<OptionSet> result = Promise.promise();
                final Request request = createCoapRequest(Code.PUT, getPutResource(tenantId, deviceId), count);
                client.advanced(getHandler(result), request);
                return result.future();
            });
}
 
Example #13
Source File: AbstractVertxBasedCoapAdapterTest.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
private static CoapExchange newCoapExchange(final Buffer payload, final Type requestType, final OptionSet options) {

        final Request request = mock(Request.class);
        when(request.getType()).thenReturn(requestType);
        when(request.isConfirmable()).thenReturn(requestType == Type.CON);
        when(request.getOptions()).thenReturn(options);
        final Exchange echange = new Exchange(request, Origin.REMOTE, mock(Executor.class));
        final CoapExchange coapExchange = mock(CoapExchange.class);
        when(coapExchange.advanced()).thenReturn(echange);
        Optional.ofNullable(payload).ifPresent(b -> when(coapExchange.getRequestPayload()).thenReturn(b.getBytes()));
        when(coapExchange.getRequestOptions()).thenReturn(options);
        when(coapExchange.getQueryParameter(anyString())).thenAnswer(invocation -> {
            final String key = invocation.getArgument(0);
            return options.getUriQuery().stream()
                    .map(param -> param.split("=", 2))
                    .filter(keyValue -> key.equals(keyValue[0]))
                    .findFirst()
                    .map(keyValue -> keyValue.length < 2 ? Boolean.TRUE.toString() : keyValue[1])
                    .orElse(null);
        });
        return coapExchange;
    }
 
Example #14
Source File: BlockwiseLayer.java    From SI with BSD 2-Clause "Simplified" License 6 votes vote down vote up
private Request getNextRequestBlock(Request request, BlockwiseStatus status) {
	int num = status.getCurrentNum();
	int szx = status.getCurrentSzx();
	Request block = new Request(request.getCode());
	// do not enforce CON, since NON could make sense over SMS or similar transports
	block.setType(request.getType());
	block.setDestination(request.getDestination());
	block.setDestinationPort(request.getDestinationPort());
	// copy options
	block.setOptions(new OptionSet(request.getOptions()));
	
	int currentSize = 1 << (4 + szx);
	int from = num * currentSize;
	int to = Math.min((num + 1) * currentSize, request.getPayloadSize());
	int length = to - from;
	byte[] blockPayload = new byte[length];
	System.arraycopy(request.getPayload(), from, blockPayload, 0, length);
	block.setPayload(blockPayload);
	
	boolean m = (to < request.getPayloadSize());
	block.getOptions().setBlock1(szx, m, num);
	
	status.setComplete(!m);
	return block;
}
 
Example #15
Source File: BlockwiseLayer.java    From SI with BSD 2-Clause "Simplified" License 6 votes vote down vote up
private Request getNextRequestBlock(Request request, BlockwiseStatus status) {
	int num = status.getCurrentNum();
	int szx = status.getCurrentSzx();
	Request block = new Request(request.getCode());
	// do not enforce CON, since NON could make sense over SMS or similar transports
	block.setType(request.getType());
	block.setDestination(request.getDestination());
	block.setDestinationPort(request.getDestinationPort());
	// copy options
	block.setOptions(new OptionSet(request.getOptions()));
	
	int currentSize = 1 << (4 + szx);
	int from = num * currentSize;
	int to = Math.min((num + 1) * currentSize, request.getPayloadSize());
	int length = to - from;
	byte[] blockPayload = new byte[length];
	System.arraycopy(request.getPayload(), from, blockPayload, 0, length);
	block.setPayload(blockPayload);
	
	boolean m = (to < request.getPayloadSize());
	block.getOptions().setBlock1(szx, m, num);
	
	status.setComplete(!m);
	return block;
}
 
Example #16
Source File: CoapTestBase.java    From hono with Eclipse Public License 2.0 5 votes vote down vote up
/**
 * Verifies that a number of messages uploaded to the CoAP adapter via a gateway
 * using TLS_PSK can be successfully consumed via the AMQP Messaging Network.
 *
 * @param ctx The test context.
 * @throws InterruptedException if the test fails.
 */
@Test
public void testUploadMessagesViaGateway(final VertxTestContext ctx) throws InterruptedException {

    // GIVEN a device that is connected via two gateways
    final Tenant tenant = new Tenant();
    final String gatewayOneId = helper.getRandomDeviceId(tenantId);
    final String gatewayTwoId = helper.getRandomDeviceId(tenantId);
    final Device deviceData = new Device();
    deviceData.setVia(Arrays.asList(gatewayOneId, gatewayTwoId));

    final VertxTestContext setup = new VertxTestContext();
    helper.registry.addPskDeviceForTenant(tenantId, tenant, gatewayOneId, SECRET)
    .compose(ok -> helper.registry.addPskDeviceToTenant(tenantId, gatewayTwoId, SECRET))
    .compose(ok -> helper.registry.registerDevice(tenantId, deviceId, deviceData))
    .onComplete(setup.completing());
    ctx.verify(() -> assertThat(setup.awaitCompletion(5, TimeUnit.SECONDS)).isTrue());

    final CoapClient gatewayOne = getCoapsClient(gatewayOneId, tenantId, SECRET);
    final CoapClient gatewayTwo = getCoapsClient(gatewayTwoId, tenantId, SECRET);

    testUploadMessages(ctx, tenantId,
            () -> warmUp(gatewayOne, createCoapsRequest(Code.PUT, getPutResource(tenantId, deviceId), 0)),
            count -> {
                final CoapClient client = (count.intValue() & 1) == 0 ? gatewayOne : gatewayTwo;
                final Promise<OptionSet> result = Promise.promise();
                final Request request = createCoapsRequest(Code.PUT, getPutResource(tenantId, deviceId), count);
                client.advanced(getHandler(result), request);
                return result.future();
            });
}
 
Example #17
Source File: AbstractVertxBasedCoapAdapterTest.java    From hono with Eclipse Public License 2.0 5 votes vote down vote up
/**
 * Verifies that the adapter fails the upload of a command response with a 4.03
 * if the adapter is disabled for the device's tenant.
 */
@Test
public void testUploadCommandResponseFailsForDisabledTenant() {

    // GIVEN an adapter that is not enabled for a device's tenant
    final TenantObject to = TenantObject.from("tenant", true);
    to.addAdapter(new Adapter(Constants.PROTOCOL_ADAPTER_TYPE_COAP).setEnabled(Boolean.FALSE));
    when(tenantClient.get(eq("tenant"), (SpanContext) any())).thenReturn(Future.succeededFuture(to));

    final Promise<ProtonDelivery> outcome = Promise.promise();
    final CommandResponseSender sender = givenACommandResponseSender(outcome);
    final CoapServer server = getCoapServer(false);
    final AbstractVertxBasedCoapAdapter<CoapAdapterProperties> adapter = getAdapter(server, true, null);

    // WHEN a device publishes an command response
    final String reqId = Command.getRequestId("correlation", "replyToId", "device");
    final Buffer payload = Buffer.buffer("some payload");
    final OptionSet options = new OptionSet();
    options.addUriPath(CommandConstants.COMMAND_RESPONSE_ENDPOINT).addUriPath(reqId);
    options.addUriQuery(String.format("%s=%d", Constants.HEADER_COMMAND_RESPONSE_STATUS, 200));
    options.setContentFormat(MediaTypeRegistry.TEXT_PLAIN);
    final CoapExchange coapExchange = newCoapExchange(payload, Type.CON, options);
    final Device authenticatedDevice = new Device("tenant", "device");
    final CoapContext context = CoapContext.fromRequest(coapExchange);

    adapter.uploadCommandResponseMessage(context, authenticatedDevice, authenticatedDevice);

    // THEN the command response not been forwarded downstream
    verify(sender, never()).sendCommandResponse(any(CommandResponse.class), any(SpanContext.class));
    // and the device gets a 4.03 response
    verify(coapExchange).respond(argThat((Response res) -> ResponseCode.FORBIDDEN.equals(res.getCode())));
    // and the response has not been reported as forwarded
    verify(metrics, never()).reportCommand(
            eq(Direction.RESPONSE),
            eq("tenant"),
            any(),
            eq(ProcessingOutcome.FORWARDED),
            anyInt(),
            any());
}
 
Example #18
Source File: AbstractVertxBasedCoapAdapterTest.java    From hono with Eclipse Public License 2.0 5 votes vote down vote up
/**
 * Verifies that the adapter fails the upload of a command response with a 4.00
 * response code if it is rejected by the downstream peer.
 */
@Test
public void testUploadCommandResponseFailsForRejectedOutcome() {

    // GIVEN an adapter with a downstream application attached
    final Promise<ProtonDelivery> outcome = Promise.promise();
    final CommandResponseSender sender = givenACommandResponseSender(outcome);
    final CoapServer server = getCoapServer(false);

    final AbstractVertxBasedCoapAdapter<CoapAdapterProperties> adapter = getAdapter(server, true, null);

    // WHEN a device publishes an command response
    final String reqId = Command.getRequestId("correlation", "replyToId", "device");
    final Buffer payload = Buffer.buffer("some payload");
    final OptionSet options = new OptionSet();
    options.addUriPath(CommandConstants.COMMAND_RESPONSE_ENDPOINT).addUriPath(reqId);
    options.addUriQuery(String.format("%s=%d", Constants.HEADER_COMMAND_RESPONSE_STATUS, 200));
    options.setContentFormat(MediaTypeRegistry.TEXT_PLAIN);
    final CoapExchange coapExchange = newCoapExchange(payload, Type.CON, options);
    final Device authenticatedDevice = new Device("tenant", "device");
    final CoapContext context = CoapContext.fromRequest(coapExchange);

    adapter.uploadCommandResponseMessage(context, authenticatedDevice, authenticatedDevice);
    outcome.fail(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "malformed message"));

    // THEN the command response is being forwarded downstream
    verify(sender).sendCommandResponse(any(CommandResponse.class), any(SpanContext.class));
    // and the device gets a 4.00 response
    verify(coapExchange).respond(argThat((Response res) -> ResponseCode.BAD_REQUEST.equals(res.getCode())));
    // and the response has not been reported as forwarded
    verify(metrics, never()).reportCommand(
            eq(Direction.RESPONSE),
            eq("tenant"),
            any(),
            eq(ProcessingOutcome.FORWARDED),
            anyInt(),
            any());
}
 
Example #19
Source File: AbstractVertxBasedCoapAdapterTest.java    From hono with Eclipse Public License 2.0 5 votes vote down vote up
/**
 * Verifies that the adapter forwards an empty notification downstream.
 */
@Test
public void testUploadEmptyNotificationSucceeds() {

    // GIVEN an adapter
    final DownstreamSender sender = givenATelemetrySender(Promise.promise());
    final CoapServer server = getCoapServer(false);
    final AbstractVertxBasedCoapAdapter<CoapAdapterProperties> adapter = getAdapter(server, true, null);

    // WHEN a device publishes an empty message that is marked as an empty notification
    final OptionSet options = new OptionSet();
    options.addUriQuery(CoapContext.PARAM_EMPTY_CONTENT);
    final CoapExchange coapExchange = newCoapExchange(null, Type.NON, options);
    final Device authenticatedDevice = new Device("my-tenant", "the-device");
    final CoapContext context = CoapContext.fromRequest(coapExchange);

    adapter.uploadTelemetryMessage(context, authenticatedDevice, authenticatedDevice);

    // THEN the device gets a response indicating success
    verify(coapExchange).respond(argThat((Response res) -> ResponseCode.CHANGED.equals(res.getCode())));
    // and the message has been forwarded downstream
    verify(sender).send(argThat(msg -> EventConstants.isEmptyNotificationType(msg.getContentType())), any(SpanContext.class));
    verify(metrics).reportTelemetry(
            eq(MetricsTags.EndpointType.TELEMETRY),
            eq("my-tenant"),
            any(),
            eq(MetricsTags.ProcessingOutcome.FORWARDED),
            eq(MetricsTags.QoS.AT_MOST_ONCE),
            eq(0),
            eq(TtdStatus.NONE),
            any());
}
 
Example #20
Source File: AbstractVertxBasedCoapAdapter.java    From hono with Eclipse Public License 2.0 5 votes vote down vote up
/**
 * Adds a command to a CoAP response.
 * <p>
 * This default implementation adds the command name, content format and response URI to the
 * CoAP response options and puts the command's input data (if any) to the response body.
 *
 * @param response The CoAP response.
 * @param commandContext The context containing the command to add.
 * @param currentSpan The Open Tracing span used for tracking the CoAP request.
 */
protected void addCommandToResponse(
        final Response response,
        final CommandContext commandContext,
        final Span currentSpan) {

    final Command command = commandContext.getCommand();
    final OptionSet options = response.getOptions();
    options.addLocationQuery(Constants.HEADER_COMMAND + "=" + command.getName());
    if (command.isOneWay()) {
        options.setLocationPath(CommandConstants.COMMAND_ENDPOINT);
    } else {
        options.setLocationPath(CommandConstants.COMMAND_RESPONSE_ENDPOINT);
    }

    currentSpan.setTag(Constants.HEADER_COMMAND, command.getName());
    log.debug("adding command [name: {}, request-id: {}] to response for device [tenant-id: {}, device-id: {}]",
            command.getName(), command.getRequestId(), command.getTenant(), command.getDeviceId());
    commandContext.getCurrentSpan().log("forwarding command to device in CoAP response");

    if (command.isTargetedAtGateway()) {
        options.addLocationPath(command.getTenant());
        options.addLocationPath(command.getOriginalDeviceId());
        currentSpan.setTag(Constants.HEADER_COMMAND_TARGET_DEVICE, command.getOriginalDeviceId());
    }
    if (!command.isOneWay()) {
        options.addLocationPath(command.getRequestId());
        currentSpan.setTag(Constants.HEADER_COMMAND_REQUEST_ID, command.getRequestId());
    }
    final int formatCode = MediaTypeRegistry.parse(command.getContentType());
    if (formatCode != MediaTypeRegistry.UNDEFINED) {
        options.setContentFormat(formatCode);
    } else {
        currentSpan.log("ignoring unknown content type [" + command.getContentType() + "] of command");
    }
    Optional.ofNullable(command.getPayload()).ifPresent(b -> response.setPayload(b.getBytes()));
}
 
Example #21
Source File: CoapOptionInjectExtractAdapter.java    From hono with Eclipse Public License 2.0 5 votes vote down vote up
/**
 * Creates a new carrier for extracting a trace context from CoAP options.
 *
 * @param options The CoAP options to extract the context from.
 * @throws NullPointerException if options is {@code null}.
 * @return The carrier to use for extraction.
 */
public static Optional<CoapOptionInjectExtractAdapter> forExtraction(final OptionSet options) {
    Objects.requireNonNull(options);
    return getTraceContextOption(options)
            .map(option -> {
                final CoapOptionInjectExtractAdapter adapter = new CoapOptionInjectExtractAdapter();
                adapter.optionToExtractFrom = option;
                return Optional.of(adapter);
            })
            .orElse(Optional.empty());
}
 
Example #22
Source File: CoAPWrapper.java    From gsn with GNU General Public License v3.0 4 votes vote down vote up
@Override
public void onLoad(CoapResponse response) {
	OptionSet os = response.getOptions();
	nextExpectedMessage = os.getMaxAge() * 2 + (System.currentTimeMillis() / 1000);
	postStreamElement(new Serializable[]{response.getPayload()});
}
 
Example #23
Source File: CoapMessage.java    From SI with BSD 2-Clause "Simplified" License 4 votes vote down vote up
private CoapMessage(boolean incoming, Type type, int mId, String token, OptionSet options, byte[] payload) {
    this.incoming = incoming;
    this.timestamp = System.currentTimeMillis();
    this.type = type.toString();
    this.mId = mId;
    this.token = token;

    if (options != null) {
        List<Option> opts = options.asSortedList();
        if (!opts.isEmpty()) {
            Map<String, List<String>> optMap = new HashMap<>();
            for (Option opt : opts) {
                String strOption = OptionNumberRegistry.toString(opt.getNumber());
                List<String> values = optMap.get(strOption);
                if (values == null) {
                    values = new ArrayList<>();
                    optMap.put(strOption, values);
                }
                values.add(opt.toValueString());
            }

            StringBuilder builder = new StringBuilder();
            for (Entry<String, List<String>> e : optMap.entrySet()) {
                if (builder.length() > 0) {
                    builder.append(" - ");
                }
                builder.append(e.getKey()).append(": ").append(StringUtils.join(e.getValue(), ", "));
            }
            this.options = builder.toString();

        }
    }
    if (payload != null && payload.length > 0) {
        String strPayload = new String(payload, Charsets.UTF_8);
        if (StringUtils.isAsciiPrintable(strPayload)) {
            this.payload = strPayload;
        } else {
            this.payload = "Hex:" + Hex.encodeHexString(payload);
        }
    }
}
 
Example #24
Source File: CoapMessage.java    From SI with BSD 2-Clause "Simplified" License 4 votes vote down vote up
private CoapMessage(boolean incoming, Type type, int mId, String token, OptionSet options, byte[] payload) {
    this.incoming = incoming;
    this.timestamp = System.currentTimeMillis();
    this.type = type.toString();
    this.mId = mId;
    this.token = token;

    if (options != null) {
        List<Option> opts = options.asSortedList();
        if (!opts.isEmpty()) {
            Map<String, List<String>> optMap = new HashMap<>();
            for (Option opt : opts) {
                String strOption = OptionNumberRegistry.toString(opt.getNumber());
                List<String> values = optMap.get(strOption);
                if (values == null) {
                    values = new ArrayList<>();
                    optMap.put(strOption, values);
                }
                values.add(opt.toValueString());
            }

            StringBuilder builder = new StringBuilder();
            for (Entry<String, List<String>> e : optMap.entrySet()) {
                if (builder.length() > 0) {
                    builder.append(" - ");
                }
                builder.append(e.getKey()).append(": ").append(StringUtils.join(e.getValue(), ", "));
            }
            this.options = builder.toString();

        }
    }
    if (payload != null && payload.length > 0) {
        String strPayload = new String(payload, Charsets.UTF_8);
        if (StringUtils.isAsciiPrintable(strPayload)) {
            this.payload = strPayload;
        } else {
            this.payload = "Hex:" + Hex.encodeHexString(payload);
        }
    }
}
 
Example #25
Source File: CoapTestBase.java    From hono with Eclipse Public License 2.0 4 votes vote down vote up
/**
 * Verifies that the CoAP adapter delivers a one-way command to a device.
 *
 * @param endpointConfig The endpoints to use for sending/receiving commands.
 * @param ctx The test context
 * @throws InterruptedException if the test fails.
 */
@ParameterizedTest(name = IntegrationTestSupport.PARAMETERIZED_TEST_NAME_PATTERN)
@MethodSource("commandAndControlVariants")
@Timeout(value = 10, timeUnit = TimeUnit.SECONDS)
public void testUploadMessagesWithTtdThatReplyWithOneWayCommand(
        final CoapCommandEndpointConfiguration endpointConfig,
        final VertxTestContext ctx) throws InterruptedException {

    final Tenant tenant = new Tenant();
    final String expectedCommand = String.format("%s=%s", Constants.HEADER_COMMAND, COMMAND_TO_SEND);

    final VertxTestContext setup = new VertxTestContext();
    helper.registry.addPskDeviceForTenant(tenantId, tenant, deviceId, SECRET).onComplete(setup.completing());
    ctx.verify(() -> assertThat(setup.awaitCompletion(5, TimeUnit.SECONDS)).isTrue());

    final CoapClient client = getCoapsClient(deviceId, tenantId, SECRET);
    final AtomicInteger counter = new AtomicInteger();

    final String commandTargetDeviceId = endpointConfig.isSubscribeAsGateway()
            ? helper.setupGatewayDeviceBlocking(tenantId, deviceId, 5)
            : deviceId;
    final String subscribingDeviceId = endpointConfig.isSubscribeAsGatewayForSingleDevice() ? commandTargetDeviceId
            : deviceId;

    testUploadMessages(ctx, tenantId,
            () -> warmUp(client, createCoapsRequest(Code.POST, getPostResource(), 0)),
            msg -> {
                final Integer ttd = MessageHelper.getTimeUntilDisconnect(msg);
                logger.debug("north-bound-cmd received {}, ttd: {}", msg, ttd);
                TimeUntilDisconnectNotification.fromMessage(msg).ifPresent(notification -> {
                    ctx.verify(() -> {
                        assertThat(notification.getTenantId()).isEqualTo(tenantId);
                        assertThat(notification.getDeviceId()).isEqualTo(subscribingDeviceId);
                    });
                    logger.debug("send one-way-command");
                    final JsonObject inputData = new JsonObject().put(COMMAND_JSON_KEY, (int) (Math.random() * 100));
                    helper.sendOneWayCommand(
                            tenantId,
                            commandTargetDeviceId,
                            COMMAND_TO_SEND,
                            "application/json",
                            inputData.toBuffer(),
                            // set "forceCommandRerouting" message property so that half the command are rerouted via the AMQP network
                            IntegrationTestSupport.newCommandMessageProperties(() -> counter.getAndIncrement() >= MESSAGES_TO_SEND / 2),
                            notification.getMillisecondsUntilExpiry() / 2);
                });
            },
            count -> {
                final Promise<OptionSet> result = Promise.promise();
                final Request request = createCoapsRequest(endpointConfig, commandTargetDeviceId, count);
                request.getOptions().addUriQuery(String.format("%s=%d", Constants.HEADER_TIME_TILL_DISCONNECT, 4));
                logger.debug("south-bound send {}", request);
                client.advanced(getHandler(result, ResponseCode.CHANGED), request);
                return result.future()
                        .map(responseOptions -> {
                            ctx.verify(() -> {
                                assertResponseContainsOneWayCommand(
                                        endpointConfig,
                                        responseOptions,
                                        expectedCommand,
                                        tenantId,
                                        commandTargetDeviceId);
                            });
                            return responseOptions;
                        });
            });
}
 
Example #26
Source File: CoapTestBase.java    From hono with Eclipse Public License 2.0 4 votes vote down vote up
/**
 * Uploads messages to the CoAP endpoint.
 *
 * @param ctx The test context to run on.
 * @param tenantId The tenant that the device belongs to.
 * @param warmUp A sender of messages used to warm up the adapter before running the test itself or {@code null} if
 *            no warm up should be performed.
 * @param messageConsumer Consumer that is invoked when a message was received.
 * @param requestSender The test device that will publish the data.
 * @param numberOfMessages The number of messages that are uploaded.
 * @throws InterruptedException if the test is interrupted before it has finished.
 */
protected void testUploadMessages(
        final VertxTestContext ctx,
        final String tenantId,
        final Supplier<Future<?>> warmUp,
        final Consumer<Message> messageConsumer,
        final Function<Integer, Future<OptionSet>> requestSender,
        final int numberOfMessages) throws InterruptedException {

    final CountDownLatch received = new CountDownLatch(numberOfMessages);

    final VertxTestContext setup = new VertxTestContext();
    createConsumer(tenantId, msg -> {
        logger.trace("received {}", msg);
        assertMessageProperties(ctx, msg);
        if (messageConsumer != null) {
            messageConsumer.accept(msg);
        }
        received.countDown();
        if (received.getCount() % 20 == 0) {
            logger.info("messages received: {}", numberOfMessages - received.getCount());
        }
    })
    .compose(ok -> Optional.ofNullable(warmUp).map(w -> w.get()).orElse(Future.succeededFuture()))
    .onComplete(setup.completing());
    ctx.verify(() -> assertThat(setup.awaitCompletion(5, TimeUnit.SECONDS)).isTrue());

    final long start = System.currentTimeMillis();
    final AtomicInteger messageCount = new AtomicInteger(0);

    while (messageCount.get() < numberOfMessages) {

        final CountDownLatch sending = new CountDownLatch(1);
        requestSender.apply(messageCount.getAndIncrement()).compose(this::assertCoapResponse)
                .onComplete(attempt -> {
                    if (attempt.succeeded()) {
                        logger.debug("sent message {}", messageCount.get());
                    } else {
                        logger.info("failed to send message {}: {}", messageCount.get(),
                                attempt.cause().getMessage());
                        ctx.failNow(attempt.cause());
                    }
                    sending.countDown();;
                });

        if (messageCount.get() % 20 == 0) {
            logger.info("messages sent: {}", messageCount.get());
        }
        sending.await();
    }

    final long timeToWait = Math.max(TEST_TIMEOUT_MILLIS - 1000, Math.round(numberOfMessages * 20));
    if (received.await(timeToWait, TimeUnit.MILLISECONDS)) {
        logger.info("sent {} and received {} messages after {} milliseconds",
                messageCount, numberOfMessages - received.getCount(), System.currentTimeMillis() - start);
        ctx.completeNow();
    } else {
        logger.info("sent {} and received {} messages after {} milliseconds",
                messageCount, numberOfMessages - received.getCount(), System.currentTimeMillis() - start);
        ctx.failNow(new AssertionError("did not receive all messages sent"));
    }
}
 
Example #27
Source File: AbstractVertxBasedCoapAdapterTest.java    From hono with Eclipse Public License 2.0 4 votes vote down vote up
private static CoapExchange newCoapExchange(final Buffer payload, final Type requestType, final Integer contentFormat) {

        final OptionSet options = new OptionSet();
        Optional.ofNullable(contentFormat).ifPresent(options::setContentFormat);
        return newCoapExchange(payload, requestType, options);
    }
 
Example #28
Source File: AbstractVertxBasedCoapAdapterTest.java    From hono with Eclipse Public License 2.0 4 votes vote down vote up
/**
 * Verifies that the adapter waits for a command response being settled and accepted
 * by a downstream peer before responding with a 2.04 status to the device.
 */
@Test
public void testUploadCommandResponseWaitsForAcceptedOutcome() {

    // GIVEN an adapter with a downstream application attached
    final Promise<ProtonDelivery> outcome = Promise.promise();
    final CommandResponseSender sender = givenACommandResponseSender(outcome);
    final CoapServer server = getCoapServer(false);

    final AbstractVertxBasedCoapAdapter<CoapAdapterProperties> adapter = getAdapter(server, true, null);

    // WHEN a device publishes an command response
    final String reqId = Command.getRequestId("correlation", "replyToId", "device");
    final Buffer payload = Buffer.buffer("some payload");
    final OptionSet options = new OptionSet();
    options.addUriPath(CommandConstants.COMMAND_RESPONSE_ENDPOINT).addUriPath(reqId);
    options.addUriQuery(String.format("%s=%d", Constants.HEADER_COMMAND_RESPONSE_STATUS, 200));
    options.setContentFormat(MediaTypeRegistry.TEXT_PLAIN);
    final CoapExchange coapExchange = newCoapExchange(payload, Type.CON, options);
    final Device authenticatedDevice = new Device("tenant", "device");
    final CoapContext context = CoapContext.fromRequest(coapExchange);

    adapter.uploadCommandResponseMessage(context, authenticatedDevice, authenticatedDevice);

    // THEN the command response is being forwarded downstream
    verify(sender).sendCommandResponse(any(CommandResponse.class), any(SpanContext.class));
    // but the device does not get a response
    verify(coapExchange, never()).respond(any(Response.class));
    // and the response has not been reported as forwarded
    verify(metrics, never()).reportCommand(
            eq(Direction.RESPONSE),
            eq("tenant"),
            any(),
            eq(ProcessingOutcome.FORWARDED),
            anyInt(),
            any());

    // until the message has been accepted
    outcome.complete(mock(ProtonDelivery.class));

    verify(coapExchange).respond(argThat((Response res) -> ResponseCode.CHANGED.equals(res.getCode())));
    verify(metrics).reportCommand(
            eq(Direction.RESPONSE),
            eq("tenant"),
            any(),
            eq(ProcessingOutcome.FORWARDED),
            eq(payload.length()),
            any());
}
 
Example #29
Source File: TracingSupportingHonoResource.java    From hono with Eclipse Public License 2.0 4 votes vote down vote up
private SpanContext extractSpanContextFromRequest(final OptionSet requestOptions) {
    return CoapOptionInjectExtractAdapter.forExtraction(requestOptions)
            .map(carrier -> tracer.extract(Format.Builtin.BINARY, carrier))
            .orElse(null);
}
 
Example #30
Source File: CoapTestBase.java    From hono with Eclipse Public License 2.0 3 votes vote down vote up
/**
 * Uploads messages to the CoAP endpoint.
 *
 * @param ctx The test context to run on.
 * @param tenantId The tenant that the device belongs to.
 * @param messageConsumer Consumer that is invoked when a message was received.
 * @param warmUp A sender of messages used to warm up the adapter before
 *               running the test itself or {@code null} if no warm up should
 *               be performed. 
 * @param requestSender The test device that will publish the data.
 * @throws InterruptedException if the test is interrupted before it
 *              has finished.
 */
protected void testUploadMessages(
        final VertxTestContext ctx,
        final String tenantId,
        final Supplier<Future<?>> warmUp,
        final Consumer<Message> messageConsumer,
        final Function<Integer, Future<OptionSet>> requestSender) throws InterruptedException {
    testUploadMessages(ctx, tenantId, warmUp, messageConsumer, requestSender, MESSAGES_TO_SEND);
}