use of org.eclipse.hono.util.ResourceIdentifier in project hono by eclipse.
the class CommandAndControlMqttIT method testSendOneWayCommandSucceeds.
/**
* Verifies that the adapter forwards on-way commands from
* an application to a device.
*
* @param endpointConfig The endpoints to use for sending/receiving commands.
* @param ctx The vert.x test context.
* @throws InterruptedException if not all commands and responses are exchanged in time.
*/
@ParameterizedTest(name = IntegrationTestSupport.PARAMETERIZED_TEST_NAME_PATTERN)
@MethodSource("allCombinations")
@Timeout(timeUnit = TimeUnit.SECONDS, value = 10)
public void testSendOneWayCommandSucceeds(final MqttCommandEndpointConfiguration endpointConfig, final VertxTestContext ctx) throws InterruptedException {
final String commandTargetDeviceId = endpointConfig.isSubscribeAsGateway() ? helper.setupGatewayDeviceBlocking(tenantId, deviceId, 5) : deviceId;
final Checkpoint commandsReceived = ctx.checkpoint(COMMANDS_TO_SEND);
final AtomicInteger counter = new AtomicInteger();
testSendCommandSucceeds(ctx, commandTargetDeviceId, msg -> {
LOGGER.trace("received one-way command [topic: {}]", msg.topicName());
final ResourceIdentifier topic = ResourceIdentifier.fromString(msg.topicName());
ctx.verify(() -> {
endpointConfig.assertCommandPublishTopicStructure(topic, commandTargetDeviceId, true, "setValue");
});
commandsReceived.flag();
}, payload -> {
counter.incrementAndGet();
return helper.sendOneWayCommand(tenantId, commandTargetDeviceId, "setValue", "text/plain", payload, helper.getSendCommandTimeout(counter.get() == 1));
}, endpointConfig, COMMANDS_TO_SEND, MqttQoS.AT_MOST_ONCE);
}
use of org.eclipse.hono.util.ResourceIdentifier in project hono by eclipse.
the class CommandAndControlMqttIT method testSendCommandSucceeds.
private void testSendCommandSucceeds(final VertxTestContext ctx, final MqttCommandEndpointConfiguration endpointConfig, final MqttQoS qos) throws InterruptedException {
final String commandTargetDeviceId = endpointConfig.isSubscribeAsGateway() ? helper.setupGatewayDeviceBlocking(tenantId, deviceId, 5) : deviceId;
final AtomicInteger counter = new AtomicInteger();
testSendCommandSucceeds(ctx, commandTargetDeviceId, msg -> {
LOGGER.trace("received command [{}]", msg.topicName());
final ResourceIdentifier topic = ResourceIdentifier.fromString(msg.topicName());
ctx.verify(() -> {
endpointConfig.assertCommandPublishTopicStructure(topic, commandTargetDeviceId, false, "setValue");
});
final String commandRequestId = topic.elementAt(4);
final String command = topic.elementAt(5);
// send response
mqttClient.publish(endpointConfig.getResponseTopic(commandTargetDeviceId, commandRequestId, HttpURLConnection.HTTP_OK), Buffer.buffer(command + ": ok"), qos, false, false);
}, payload -> {
final String contentType = payload != null ? "text/plain" : null;
counter.incrementAndGet();
return helper.sendCommand(tenantId, commandTargetDeviceId, "setValue", contentType, payload, helper.getSendCommandTimeout(counter.get() == 1)).map(response -> {
ctx.verify(() -> {
assertThat(response.getDeviceId()).isEqualTo(commandTargetDeviceId);
assertThat(response.getTenantId()).isEqualTo(tenantId);
assertThat(response.getCreationTime()).isNotNull();
});
return (Void) null;
});
}, endpointConfig, COMMANDS_TO_SEND, qos);
}
use of org.eclipse.hono.util.ResourceIdentifier in project hono by eclipse.
the class HttpBasedMessageMapping method mapDownstreamMessageRequest.
private void mapDownstreamMessageRequest(final MqttContext ctx, final ResourceIdentifier targetAddress, final RegistrationAssertion registrationInfo, final MapperEndpoint mapperEndpoint, final Handler<AsyncResult<MappedMessage>> resultHandler) {
final MultiMap headers = MultiMap.caseInsensitiveMultiMap();
JsonObject.mapFrom(registrationInfo).forEach(property -> {
final Object value = property.getValue();
if (value instanceof String) {
// prevent strings from being enclosed in quotes
headers.add(property.getKey(), (String) value);
} else {
headers.add(property.getKey(), Json.encode(value));
}
});
headers.add(MessageHelper.APP_PROPERTY_ORIG_ADDRESS, ctx.message().topicName());
if (ctx.contentType() != null) {
headers.add(HttpHeaders.CONTENT_TYPE.toString(), ctx.contentType());
}
final Promise<MappedMessage> result = Promise.promise();
webClient.post(mapperEndpoint.getPort(), mapperEndpoint.getHost(), mapperEndpoint.getUri()).putHeaders(headers).ssl(mapperEndpoint.isTlsEnabled()).sendBuffer(ctx.message().payload(), httpResponseAsyncResult -> {
if (httpResponseAsyncResult.failed()) {
LOG.debug("failed to map message [origin: {}] using mapping service [host: {}, port: {}, URI: {}]", ctx.authenticatedDevice(), mapperEndpoint.getHost(), mapperEndpoint.getPort(), mapperEndpoint.getUri(), httpResponseAsyncResult.cause());
result.fail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, httpResponseAsyncResult.cause()));
} else {
final HttpResponse<Buffer> httpResponse = httpResponseAsyncResult.result();
if (httpResponse.statusCode() == HttpURLConnection.HTTP_OK) {
final Map<String, String> additionalProperties = new HashMap<>();
httpResponse.headers().forEach(entry -> additionalProperties.put(entry.getKey(), entry.getValue()));
final String mappedDeviceId = Optional.ofNullable(additionalProperties.remove(MessageHelper.APP_PROPERTY_DEVICE_ID)).map(id -> {
LOG.debug("original {} has been mapped to [device-id: {}]", ctx.authenticatedDevice(), id);
return id;
}).orElseGet(() -> targetAddress.getResourceId());
result.complete(new MappedMessage(ResourceIdentifier.from(targetAddress.getEndpoint(), targetAddress.getTenantId(), mappedDeviceId), httpResponse.bodyAsBuffer(), additionalProperties));
} else {
LOG.debug("mapping service [host: {}, port: {}, URI: {}] returned unexpected status code: {}", mapperEndpoint.getHost(), mapperEndpoint.getPort(), mapperEndpoint.getUri(), httpResponse.statusCode());
result.fail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "could not invoke configured mapping service"));
}
}
resultHandler.handle(result.future());
});
}
use of org.eclipse.hono.util.ResourceIdentifier in project hono by eclipse.
the class AbstractVertxBasedMqttProtocolAdapterTest method testUploadEmptyCommandResponseSucceeds.
/**
* Verifies that the adapter accepts a command response message with an empty body.
*
* @param ctx The vert.x test context.
*/
@Test
public void testUploadEmptyCommandResponseSucceeds(final VertxTestContext ctx) {
// GIVEN an adapter with a command response consumer
final CommandResponseSender sender = givenACommandResponseSenderForAnyTenant();
// WHEN forwarding a command response that has been published
givenAnAdapter(properties);
final MqttEndpoint endpoint = mockEndpoint();
when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
final MqttPublishMessage messageFromDevice = mock(MqttPublishMessage.class);
when(messageFromDevice.qosLevel()).thenReturn(MqttQoS.AT_MOST_ONCE);
when(messageFromDevice.messageId()).thenReturn(5555555);
when(messageFromDevice.topicName()).thenReturn("command/my-tenant/4712/res/1010f8ab0b53-bd96-4d99-9d9c-56b868474a6a/200");
// ... with an empty payload
when(messageFromDevice.payload()).thenReturn(null);
final ResourceIdentifier address = ResourceIdentifier.fromString("command/my-tenant/4712/res/1010f8ab0b53-bd96-4d99-9d9c-56b868474a6a/200");
adapter.uploadCommandResponseMessage(newMqttContext(messageFromDevice, endpoint, span), address).onComplete(ctx.succeeding(result -> {
ctx.verify(() -> {
verify(sender).sendCommandResponse(any(TenantObject.class), any(RegistrationAssertion.class), any(CommandResponse.class), any());
// then it is forwarded successfully
verify(metrics).reportCommand(eq(MetricsTags.Direction.RESPONSE), eq("my-tenant"), any(TenantObject.class), eq(MetricsTags.ProcessingOutcome.FORWARDED), eq(0), any());
ctx.completeNow();
});
}));
}
use of org.eclipse.hono.util.ResourceIdentifier in project hono by eclipse.
the class AbstractVertxBasedMqttProtocolAdapterTest method getAdapter.
private AbstractVertxBasedMqttProtocolAdapter<MqttProtocolAdapterProperties> getAdapter(final MqttServer server, final MqttProtocolAdapterProperties configuration) {
final AbstractVertxBasedMqttProtocolAdapter<MqttProtocolAdapterProperties> adapter = new AbstractVertxBasedMqttProtocolAdapter<>() {
@Override
public String getTypeName() {
return ADAPTER_TYPE;
}
@Override
protected Future<Void> onPublishedMessage(final MqttContext ctx) {
final ResourceIdentifier topic = ResourceIdentifier.fromString(ctx.message().topicName());
return uploadTelemetryMessage(ctx, topic.getTenantId(), topic.getResourceId(), ctx.message().payload());
}
};
adapter.setConfig(configuration);
adapter.setMetrics(metrics);
adapter.setAuthHandler(authHandler);
adapter.setResourceLimitChecks(resourceLimitChecks);
setServiceClients(adapter);
if (server != null) {
adapter.setMqttInsecureServer(server);
adapter.init(vertx, context);
}
return adapter;
}
Aggregations