From 4770d81b5ff6909bcdb54ce039a7afdd7b34fdf2 Mon Sep 17 00:00:00 2001 From: pablo gonzalez granados Date: Wed, 8 Mar 2023 15:47:19 +0100 Subject: [PATCH 1/5] Add vanilla coverage to integrations tests --- .../hivemq-client-vanilla/pom.xml | 98 +++++++++++++++++++ .../test/vanilla/HttpBridgeApplication.java | 12 +++ .../test/vanilla/dto/MessageDto.java | 21 ++++ .../test/vanilla/dto/PublishMsgRespDto.java | 15 +++ .../resources/BrokerPushToTopicResources.java | 46 +++++++++ .../BrokerSubscribeToTopicResources.java | 33 +++++++ .../test/vanilla/services/HiveProxy.java | 80 +++++++++++++++ .../src/main/resources/application.properties | 4 + .../BrokerPushToTopicResourcesTest.java | 32 ++++++ .../BrokerSubscribeToTopicResourceTest.java | 70 +++++++++++++ .../test/vanilla/CommonsTestSuite.java | 26 +++++ .../test/vanilla/HivemqDefaultProfile.java | 13 +++ .../test/vanilla/HivemqResources.java | 30 ++++++ .../NativeBrokerPushToTopicResourcesIT.java | 7 ++ .../kitchensink}/.dockerignore | 0 .../kitchensink}/.gitignore | 0 .../.mvn/wrapper/MavenWrapperDownloader.java | 0 .../.mvn/wrapper/maven-wrapper.properties | 0 .../kitchensink}/mvnw | 0 .../kitchensink}/mvnw.cmd | 0 .../kitchensink}/pom.xml | 40 +------- .../src/main/docker/Dockerfile.jvm | 0 .../src/main/docker/Dockerfile.legacy-jar | 0 .../src/main/docker/Dockerfile.native | 0 .../main/docker/Dockerfile.native-distroless | 0 .../hivemqclient/GreetingResource.java | 0 .../resources/META-INF/resources/index.html | 0 .../src/main/resources/application.properties | 0 .../hivemqclient/GreetingResourceTest.java | 0 .../NativeGreetingResourceIT.java | 0 integration-tests/pom.xml | 69 +++++-------- .../hivemqclient/it/HiveMQClientResource.java | 32 ------ .../src/main/resources/application.properties | 0 .../it/HiveMQClientResourceTest.java | 21 ---- .../it/NativeHiveMQClientResourceIT.java | 7 -- pom.xml | 3 +- 36 files changed, 515 insertions(+), 144 deletions(-) create mode 100644 integration-tests/hivemq-client-vanilla/pom.xml create mode 100644 integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/HttpBridgeApplication.java create mode 100644 integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/dto/MessageDto.java create mode 100644 integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/dto/PublishMsgRespDto.java create mode 100644 integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/resources/BrokerPushToTopicResources.java create mode 100644 integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/resources/BrokerSubscribeToTopicResources.java create mode 100644 integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/services/HiveProxy.java create mode 100644 integration-tests/hivemq-client-vanilla/src/main/resources/application.properties create mode 100644 integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/BrokerPushToTopicResourcesTest.java create mode 100644 integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/BrokerSubscribeToTopicResourceTest.java create mode 100644 integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/CommonsTestSuite.java create mode 100644 integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/HivemqDefaultProfile.java create mode 100644 integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/HivemqResources.java create mode 100644 integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/NativeBrokerPushToTopicResourcesIT.java rename {kitchensink => integration-tests/kitchensink}/.dockerignore (100%) rename {kitchensink => integration-tests/kitchensink}/.gitignore (100%) rename {kitchensink => integration-tests/kitchensink}/.mvn/wrapper/MavenWrapperDownloader.java (100%) rename {kitchensink => integration-tests/kitchensink}/.mvn/wrapper/maven-wrapper.properties (100%) rename {kitchensink => integration-tests/kitchensink}/mvnw (100%) rename {kitchensink => integration-tests/kitchensink}/mvnw.cmd (100%) rename {kitchensink => integration-tests/kitchensink}/pom.xml (77%) rename {kitchensink => integration-tests/kitchensink}/src/main/docker/Dockerfile.jvm (100%) rename {kitchensink => integration-tests/kitchensink}/src/main/docker/Dockerfile.legacy-jar (100%) rename {kitchensink => integration-tests/kitchensink}/src/main/docker/Dockerfile.native (100%) rename {kitchensink => integration-tests/kitchensink}/src/main/docker/Dockerfile.native-distroless (100%) rename {kitchensink => integration-tests/kitchensink}/src/main/java/io/quarkiverse/hivemqclient/GreetingResource.java (100%) rename {kitchensink => integration-tests/kitchensink}/src/main/resources/META-INF/resources/index.html (100%) rename {kitchensink => integration-tests/kitchensink}/src/main/resources/application.properties (100%) rename {kitchensink => integration-tests/kitchensink}/src/test/java/io/quarkiverse/hivemqclient/GreetingResourceTest.java (100%) rename {kitchensink => integration-tests/kitchensink}/src/test/java/io/quarkiverse/hivemqclient/NativeGreetingResourceIT.java (100%) delete mode 100644 integration-tests/src/main/java/io/quarkiverse/hivemqclient/it/HiveMQClientResource.java delete mode 100644 integration-tests/src/main/resources/application.properties delete mode 100644 integration-tests/src/test/java/io/quarkiverse/hivemqclient/it/HiveMQClientResourceTest.java delete mode 100644 integration-tests/src/test/java/io/quarkiverse/hivemqclient/it/NativeHiveMQClientResourceIT.java diff --git a/integration-tests/hivemq-client-vanilla/pom.xml b/integration-tests/hivemq-client-vanilla/pom.xml new file mode 100644 index 0000000..9f6255c --- /dev/null +++ b/integration-tests/hivemq-client-vanilla/pom.xml @@ -0,0 +1,98 @@ + + + 4.0.0 + + io.quarkiverse.hivemqclient + quarkus-hivemq-client-integration-tests + 1.0.1-SNAPSHOT + + + quarkus-hivemq-client-integration-tests-minimal + Quarkus - Hivemq Client - Integration Tests Vanilla + + + 1.17.6 + **/*Native*IT.java + **/*Test.java + + + + + io.quarkus + quarkus-vertx + + + io.quarkus + quarkus-resteasy-reactive-jackson + + + io.quarkus + quarkus-smallrye-openapi + + + io.quarkiverse.hivemqclient + quarkus-hivemq-client + ${project.version} + + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + org.jboss.resteasy + resteasy-client + test + + + org.testcontainers + hivemq + ${hive.testcontainers.version} + test + + + + + + + io.quarkus + quarkus-maven-plugin + ${quarkus.version} + + + + build + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + ${failsafe-plugin.version} + + + + integration-test + verify + + + + ${exclude.quarkus.native.tests} + + + ${include.tests} + + + + + + + + \ No newline at end of file diff --git a/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/HttpBridgeApplication.java b/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/HttpBridgeApplication.java new file mode 100644 index 0000000..1db3e92 --- /dev/null +++ b/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/HttpBridgeApplication.java @@ -0,0 +1,12 @@ +package io.quarkiverse.hivemqclient.test.vanilla; + +import javax.ws.rs.core.Application; + +import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition; +import org.eclipse.microprofile.openapi.annotations.info.Contact; +import org.eclipse.microprofile.openapi.annotations.info.Info; +import org.eclipse.microprofile.openapi.annotations.info.License; + +@OpenAPIDefinition(info = @Info(title = "Http / HiveMQ bridge API example", version = "1.0.0", contact = @Contact(name = "Http / HiveMQ bridge API Support", url = "http://exampleurl.com/contact", email = "fake-support-examples@hivemq.com"), license = @License(name = "Apache 2.0", url = "https://www.apache.org/licenses/LICENSE-2.0.html"))) +public class HttpBridgeApplication extends Application { +} diff --git a/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/dto/MessageDto.java b/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/dto/MessageDto.java new file mode 100644 index 0000000..742f826 --- /dev/null +++ b/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/dto/MessageDto.java @@ -0,0 +1,21 @@ +package io.quarkiverse.hivemqclient.test.vanilla.dto; + +public class MessageDto { + + private String value; + + public MessageDto() { + } + + public MessageDto(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/dto/PublishMsgRespDto.java b/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/dto/PublishMsgRespDto.java new file mode 100644 index 0000000..6c65fe4 --- /dev/null +++ b/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/dto/PublishMsgRespDto.java @@ -0,0 +1,15 @@ +package io.quarkiverse.hivemqclient.test.vanilla.dto; + +public class PublishMsgRespDto { + + private final String topic; + + public PublishMsgRespDto(String topic) { + this.topic = topic; + } + + public String getTopic() { + return topic; + } + +} diff --git a/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/resources/BrokerPushToTopicResources.java b/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/resources/BrokerPushToTopicResources.java new file mode 100644 index 0000000..e75dc8e --- /dev/null +++ b/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/resources/BrokerPushToTopicResources.java @@ -0,0 +1,46 @@ +package io.quarkiverse.hivemqclient.test.vanilla.resources; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.jboss.resteasy.reactive.RestPath; + +import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5PublishResult; + +import io.quarkiverse.hivemqclient.test.vanilla.dto.MessageDto; +import io.quarkiverse.hivemqclient.test.vanilla.dto.PublishMsgRespDto; +import io.quarkiverse.hivemqclient.test.vanilla.services.HiveProxy; +import io.smallrye.mutiny.Uni; + +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("/mqtt/{brokerName}/push") +public class BrokerPushToTopicResources { + + private HiveProxy hiveProxy; + + BrokerPushToTopicResources(HiveProxy hiveProxy) { + this.hiveProxy = hiveProxy; + } + + @POST + @Path("/{topicName}") + public Uni pushMessage(@RestPath("brokerName") String brokerName, @RestPath("topicName") String topicName, + MessageDto message) { + return hiveProxy + .pushSimpleMsg(brokerName, topicName, message.getValue()) + .onItem().transform(payload -> makePushMsgResponse(topicName, payload)); + } + + private static Response makePushMsgResponse(String topicName, Mqtt5PublishResult payload) { + if (payload.getError().isPresent()) { + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(payload.getError().get().getMessage()).build(); + } + + return Response.status(Response.Status.CREATED).entity(new PublishMsgRespDto(topicName)).build(); + } +} diff --git a/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/resources/BrokerSubscribeToTopicResources.java b/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/resources/BrokerSubscribeToTopicResources.java new file mode 100644 index 0000000..368928b --- /dev/null +++ b/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/resources/BrokerSubscribeToTopicResources.java @@ -0,0 +1,33 @@ +package io.quarkiverse.hivemqclient.test.vanilla.resources; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.MediaType; + +import org.jboss.resteasy.reactive.RestPath; +import org.jboss.resteasy.reactive.RestStreamElementType; + +import io.quarkiverse.hivemqclient.test.vanilla.services.HiveProxy; +import io.smallrye.mutiny.Multi; +import io.vertx.mutiny.core.eventbus.EventBus; + +@Path("/mqtt/{brokerName}/subscribe") +public class BrokerSubscribeToTopicResources { + + private EventBus bus; + private HiveProxy hiveProxy; + + BrokerSubscribeToTopicResources(EventBus bus, HiveProxy hiveProxy) { + this.bus = bus; + this.hiveProxy = hiveProxy; + } + + @GET + @Path("/{topicName}") + @RestStreamElementType(MediaType.TEXT_PLAIN) + public Multi subscribeToTopic(@RestPath("brokerName") String brokerName, @RestPath("topicName") String topicName) { + return hiveProxy.subscribeTo(brokerName, topicName).toMulti() + .flatMap(topic -> bus. consumer(topic).bodyStream().toMulti()); + } + +} diff --git a/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/services/HiveProxy.java b/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/services/HiveProxy.java new file mode 100644 index 0000000..f5f6c85 --- /dev/null +++ b/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/services/HiveProxy.java @@ -0,0 +1,80 @@ +package io.quarkiverse.hivemqclient.test.vanilla.services; + +import static com.hivemq.client.mqtt.MqttGlobalPublishFilter.ALL; +import static java.nio.charset.StandardCharsets.UTF_8; + +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +import javax.inject.Singleton; + +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import com.hivemq.client.mqtt.MqttClient; +import com.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient; +import com.hivemq.client.mqtt.mqtt5.message.connect.connack.Mqtt5ConnAck; +import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5PublishResult; + +import io.smallrye.mutiny.Uni; +import io.vertx.mutiny.core.eventbus.EventBus; + +@Singleton +public class HiveProxy { + + private EventBus bus; + private String clusterHostName; + private int clusterPort; + private final Map connectionsPool = new ConcurrentHashMap<>(); + + HiveProxy( + EventBus bus, + @ConfigProperty(name = "hivemq.cluster.host", defaultValue = "localhost") String clusterHostName, + @ConfigProperty(name = "hivemq.cluster.port") int clusterPort) { + + this.bus = bus; + this.clusterHostName = clusterHostName; + this.clusterPort = clusterPort; + } + + public Uni pushSimpleMsg(final String brokerName, final String topic, final String msg) { + return getMqttClient(brokerName) + .flatMap(conn -> Uni.createFrom() + .completionStage(() -> conn.publishWith().topic(topic).payload(UTF_8.encode(msg)).send())); + } + + public Uni subscribeTo(final String brokerName, final String topic) { + String internalTopicName = getInternalSubscriptionTopicName(brokerName, topic); + return getMqttClient(brokerName) + .map(conn -> { + conn.subscribeWith().topicFilter(topic).send(); + conn.toAsync().publishes(ALL, + event -> bus.send(internalTopicName, UTF_8.decode(event.getPayload().get()).toString())); + return internalTopicName; + }); + } + + private Uni getMqttClient(final String brokerName) { + Mqtt5AsyncClient client = connectionsPool.get(brokerName); + if (Objects.isNull(client)) { + return newMQTTClient().invoke(asyncClient -> connectionsPool.put(brokerName, asyncClient)); + } + + return Uni.createFrom().item(client); + } + + private Uni newMQTTClient() { + Mqtt5AsyncClient asyncClient = MqttClient.builder() + .useMqttVersion5() + .serverHost(clusterHostName) + .serverPort(clusterPort) + .buildAsync(); + + Uni ack = Uni.createFrom().completionStage(asyncClient::connect); + return ack.map(completed -> asyncClient); + } + + private String getInternalSubscriptionTopicName(final String brokerName, final String topic) { + return brokerName + "_" + topic; + } +} diff --git a/integration-tests/hivemq-client-vanilla/src/main/resources/application.properties b/integration-tests/hivemq-client-vanilla/src/main/resources/application.properties new file mode 100644 index 0000000..282a529 --- /dev/null +++ b/integration-tests/hivemq-client-vanilla/src/main/resources/application.properties @@ -0,0 +1,4 @@ +# hiveMQ config +hivemq.cluster.host=localhost +hivemq.cluster.port=8883 + diff --git a/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/BrokerPushToTopicResourcesTest.java b/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/BrokerPushToTopicResourcesTest.java new file mode 100644 index 0000000..bcb6c64 --- /dev/null +++ b/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/BrokerPushToTopicResourcesTest.java @@ -0,0 +1,32 @@ +package io.quarkiverse.hivemqclient.test.vanilla; + +import javax.ws.rs.core.Response; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; + +@TestProfile(HivemqDefaultProfile.class) +@QuarkusTest +public class BrokerPushToTopicResourcesTest extends CommonsTestSuite { + + @Test + public void verifyMessageIsPushed() { + final String message = "helloWorld!"; + final String topicName = "hello"; + + pushMessage(DEFAULT_BROKER_NAME, topicName, message, Response.Status.CREATED); + } + + @Test + public void verifyMassivePush() { + final int amountOfEvents = 1000; + final String message = "helloWorld!"; + final String topicName = "hello"; + + for (int i = 0; i < amountOfEvents; i++) { + pushMessage(DEFAULT_BROKER_NAME, topicName, message, Response.Status.CREATED); + } + } +} diff --git a/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/BrokerSubscribeToTopicResourceTest.java b/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/BrokerSubscribeToTopicResourceTest.java new file mode 100644 index 0000000..bc91990 --- /dev/null +++ b/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/BrokerSubscribeToTopicResourceTest.java @@ -0,0 +1,70 @@ +package io.quarkiverse.hivemqclient.test.vanilla; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.testcontainers.shaded.org.awaitility.Awaitility.await; + +import java.net.URI; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.Response; +import javax.ws.rs.sse.SseEventSource; + +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; + +import io.quarkus.test.common.http.TestHTTPResource; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; + +@TestProfile(HivemqDefaultProfile.class) +@QuarkusTest +class BrokerSubscribeToTopicResourceTest extends CommonsTestSuite { + private final String message = "helloWorld!"; + private final String topicName = "hello"; + + @TestHTTPResource("/mqtt/") + private URI brokerSubscribeToTopicResource; + + @Test + void verifyServerSentEventSubscription() throws InterruptedException { + + // create a client for `BrokerSubscribeToTopicResources` and collect the consumed resources in a list + WebTarget target = ClientBuilder.newClient() + .target(brokerSubscribeToTopicResource + DEFAULT_BROKER_NAME + "/subscribe/hello"); + List received = new CopyOnWriteArrayList<>(); + SseEventSource source = SseEventSource.target(target).build(); + source.register(inboundSseEvent -> received.add(inboundSseEvent.readData())); + + // in a separate thread, feed the `BrokerPushToTopicResource` + ExecutorService msgSender = startSendingMsg(); + source.open(); + // check if, after at most 5 seconds, we have at least 'expectedMsgAmount' items collected, and they are what we expect + await().atMost(30, SECONDS).until(() -> received.size() >= 2); + assertThat(received, Matchers.hasItems("helloWorld!", "helloWorld!", "helloWorld!")); + source.close(); + + // shutdown the executor that is feeding the `BrokerPushToTopicResource` + msgSender.shutdown(); + msgSender.awaitTermination(5, SECONDS); + } + + private ExecutorService startSendingMsg() { + ExecutorService executorService = Executors.newSingleThreadExecutor(); + executorService.execute(() -> { + while (true) { + try { + pushMessage(DEFAULT_BROKER_NAME, topicName, message, Response.Status.CREATED); + } catch (Exception e) { + // Ignore errors when test is completed: Connection refused + } + } + }); + return executorService; + } +} diff --git a/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/CommonsTestSuite.java b/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/CommonsTestSuite.java new file mode 100644 index 0000000..c24513d --- /dev/null +++ b/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/CommonsTestSuite.java @@ -0,0 +1,26 @@ +package io.quarkiverse.hivemqclient.test.vanilla; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.equalTo; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import io.quarkiverse.hivemqclient.test.vanilla.dto.MessageDto; + +public abstract class CommonsTestSuite { + + protected final static String DEFAULT_BROKER_NAME = "test"; + + protected void pushMessage(final String brokerName, final String topic, final String msg, + final Response.Status ExpectedStatusCode) { + given() + .when() + .header("Content-Type", MediaType.APPLICATION_JSON) + .body(new MessageDto(msg)) + .post("/mqtt/" + brokerName + "/push/" + topic) + .then() + .statusCode(ExpectedStatusCode.getStatusCode()) + .body("topic", equalTo(topic)); + } +} diff --git a/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/HivemqDefaultProfile.java b/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/HivemqDefaultProfile.java new file mode 100644 index 0000000..093dcd0 --- /dev/null +++ b/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/HivemqDefaultProfile.java @@ -0,0 +1,13 @@ +package io.quarkiverse.hivemqclient.test.vanilla; + +import java.util.Collections; +import java.util.List; + +import io.quarkus.test.junit.QuarkusTestProfile; + +public class HivemqDefaultProfile implements QuarkusTestProfile { + @Override + public List testResources() { + return Collections.singletonList(new TestResourceEntry(HivemqResources.class)); + } +} diff --git a/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/HivemqResources.java b/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/HivemqResources.java new file mode 100644 index 0000000..717907d --- /dev/null +++ b/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/HivemqResources.java @@ -0,0 +1,30 @@ +package io.quarkiverse.hivemqclient.test.vanilla; + +import static org.testcontainers.utility.DockerImageName.parse; + +import java.util.HashMap; +import java.util.Map; + +import org.testcontainers.hivemq.HiveMQContainer; + +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; + +public class HivemqResources implements QuarkusTestResourceLifecycleManager { + + private final static HiveMQContainer hivemqContainer = new HiveMQContainer(parse("hivemq/hivemq-ce")); + + @Override + public Map start() { + hivemqContainer.start(); + Map config = new HashMap<>(); + config.put("hivemq.cluster.host", hivemqContainer.getHost()); + config.put("hivemq.cluster.port", "" + hivemqContainer.getMqttPort()); + + return config; + } + + @Override + public void stop() { + hivemqContainer.stop(); + } +} diff --git a/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/NativeBrokerPushToTopicResourcesIT.java b/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/NativeBrokerPushToTopicResourcesIT.java new file mode 100644 index 0000000..b68471e --- /dev/null +++ b/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/NativeBrokerPushToTopicResourcesIT.java @@ -0,0 +1,7 @@ +package io.quarkiverse.hivemqclient.test.vanilla; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +public class NativeBrokerPushToTopicResourcesIT extends BrokerPushToTopicResourcesTest { +} diff --git a/kitchensink/.dockerignore b/integration-tests/kitchensink/.dockerignore similarity index 100% rename from kitchensink/.dockerignore rename to integration-tests/kitchensink/.dockerignore diff --git a/kitchensink/.gitignore b/integration-tests/kitchensink/.gitignore similarity index 100% rename from kitchensink/.gitignore rename to integration-tests/kitchensink/.gitignore diff --git a/kitchensink/.mvn/wrapper/MavenWrapperDownloader.java b/integration-tests/kitchensink/.mvn/wrapper/MavenWrapperDownloader.java similarity index 100% rename from kitchensink/.mvn/wrapper/MavenWrapperDownloader.java rename to integration-tests/kitchensink/.mvn/wrapper/MavenWrapperDownloader.java diff --git a/kitchensink/.mvn/wrapper/maven-wrapper.properties b/integration-tests/kitchensink/.mvn/wrapper/maven-wrapper.properties similarity index 100% rename from kitchensink/.mvn/wrapper/maven-wrapper.properties rename to integration-tests/kitchensink/.mvn/wrapper/maven-wrapper.properties diff --git a/kitchensink/mvnw b/integration-tests/kitchensink/mvnw similarity index 100% rename from kitchensink/mvnw rename to integration-tests/kitchensink/mvnw diff --git a/kitchensink/mvnw.cmd b/integration-tests/kitchensink/mvnw.cmd similarity index 100% rename from kitchensink/mvnw.cmd rename to integration-tests/kitchensink/mvnw.cmd diff --git a/kitchensink/pom.xml b/integration-tests/kitchensink/pom.xml similarity index 77% rename from kitchensink/pom.xml rename to integration-tests/kitchensink/pom.xml index ef7f6df..2ef96fd 100644 --- a/kitchensink/pom.xml +++ b/integration-tests/kitchensink/pom.xml @@ -3,7 +3,7 @@ 4.0.0 io.quarkiverse.hivemqclient - quarkus-hivemq-client-parent + quarkus-hivemq-client-integration-tests 1.0.1-SNAPSHOT quarkus-hivemq-client-kitchensink @@ -92,6 +92,7 @@ + org.apache.maven.plugins maven-compiler-plugin ${compiler-plugin.version} @@ -99,6 +100,7 @@ + org.apache.maven.plugins maven-surefire-plugin ${surefire-plugin.version} @@ -110,40 +112,4 @@ - - - native - - - native - - - - - - maven-failsafe-plugin - ${surefire-plugin.version} - - - - integration-test - verify - - - - ${project.build.directory}/${project.build.finalName}-runner - org.jboss.logmanager.LogManager - ${maven.home} - - - - - - - - - native - - - diff --git a/kitchensink/src/main/docker/Dockerfile.jvm b/integration-tests/kitchensink/src/main/docker/Dockerfile.jvm similarity index 100% rename from kitchensink/src/main/docker/Dockerfile.jvm rename to integration-tests/kitchensink/src/main/docker/Dockerfile.jvm diff --git a/kitchensink/src/main/docker/Dockerfile.legacy-jar b/integration-tests/kitchensink/src/main/docker/Dockerfile.legacy-jar similarity index 100% rename from kitchensink/src/main/docker/Dockerfile.legacy-jar rename to integration-tests/kitchensink/src/main/docker/Dockerfile.legacy-jar diff --git a/kitchensink/src/main/docker/Dockerfile.native b/integration-tests/kitchensink/src/main/docker/Dockerfile.native similarity index 100% rename from kitchensink/src/main/docker/Dockerfile.native rename to integration-tests/kitchensink/src/main/docker/Dockerfile.native diff --git a/kitchensink/src/main/docker/Dockerfile.native-distroless b/integration-tests/kitchensink/src/main/docker/Dockerfile.native-distroless similarity index 100% rename from kitchensink/src/main/docker/Dockerfile.native-distroless rename to integration-tests/kitchensink/src/main/docker/Dockerfile.native-distroless diff --git a/kitchensink/src/main/java/io/quarkiverse/hivemqclient/GreetingResource.java b/integration-tests/kitchensink/src/main/java/io/quarkiverse/hivemqclient/GreetingResource.java similarity index 100% rename from kitchensink/src/main/java/io/quarkiverse/hivemqclient/GreetingResource.java rename to integration-tests/kitchensink/src/main/java/io/quarkiverse/hivemqclient/GreetingResource.java diff --git a/kitchensink/src/main/resources/META-INF/resources/index.html b/integration-tests/kitchensink/src/main/resources/META-INF/resources/index.html similarity index 100% rename from kitchensink/src/main/resources/META-INF/resources/index.html rename to integration-tests/kitchensink/src/main/resources/META-INF/resources/index.html diff --git a/kitchensink/src/main/resources/application.properties b/integration-tests/kitchensink/src/main/resources/application.properties similarity index 100% rename from kitchensink/src/main/resources/application.properties rename to integration-tests/kitchensink/src/main/resources/application.properties diff --git a/kitchensink/src/test/java/io/quarkiverse/hivemqclient/GreetingResourceTest.java b/integration-tests/kitchensink/src/test/java/io/quarkiverse/hivemqclient/GreetingResourceTest.java similarity index 100% rename from kitchensink/src/test/java/io/quarkiverse/hivemqclient/GreetingResourceTest.java rename to integration-tests/kitchensink/src/test/java/io/quarkiverse/hivemqclient/GreetingResourceTest.java diff --git a/kitchensink/src/test/java/io/quarkiverse/hivemqclient/NativeGreetingResourceIT.java b/integration-tests/kitchensink/src/test/java/io/quarkiverse/hivemqclient/NativeGreetingResourceIT.java similarity index 100% rename from kitchensink/src/test/java/io/quarkiverse/hivemqclient/NativeGreetingResourceIT.java rename to integration-tests/kitchensink/src/test/java/io/quarkiverse/hivemqclient/NativeGreetingResourceIT.java diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 712d777..db962f7 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -6,47 +6,19 @@ quarkus-hivemq-client-parent 1.0.1-SNAPSHOT + quarkus-hivemq-client-integration-tests - Quarkus - HiveMQ Client - Integration Tests - - - io.quarkus - quarkus-resteasy - - - io.quarkiverse.hivemqclient - quarkus-hivemq-client - ${project.version} - - - io.quarkus - quarkus-junit5 - test - - - io.rest-assured - rest-assured - test - - - - - - io.quarkus - quarkus-maven-plugin - - - - build - - - - - - + pom + Quarkus - Hivemq Client - Integration Tests + + + hivemq-client-vanilla + kitchensink + + - native-image + native native @@ -55,13 +27,9 @@ - maven-surefire-plugin - - ${native.surefire.skip} - - - + org.apache.maven.plugins maven-failsafe-plugin + ${failsafe-plugin.version} @@ -72,8 +40,13 @@ ${project.build.directory}/${project.build.finalName}-runner org.jboss.logmanager.LogManager - ${maven.home} + ${quarkus.package.type} + ${quarkus.native.container-build} + ${quarkus.native.native-image-xmx} + + ${include.tests} + @@ -81,8 +54,12 @@ + native native + true + 4g + **/*Native*IT.java - + \ No newline at end of file diff --git a/integration-tests/src/main/java/io/quarkiverse/hivemqclient/it/HiveMQClientResource.java b/integration-tests/src/main/java/io/quarkiverse/hivemqclient/it/HiveMQClientResource.java deleted file mode 100644 index 22f8b25..0000000 --- a/integration-tests/src/main/java/io/quarkiverse/hivemqclient/it/HiveMQClientResource.java +++ /dev/null @@ -1,32 +0,0 @@ -/* -* Licensed to the Apache Software Foundation (ASF) under one or more -* contributor license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright ownership. -* The ASF licenses this file to You under the Apache License, Version 2.0 -* (the "License"); you may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package io.quarkiverse.hivemqclient.it; - -import javax.enterprise.context.ApplicationScoped; -import javax.ws.rs.GET; -import javax.ws.rs.Path; - -@Path("/hivemq-client") -@ApplicationScoped -public class HiveMQClientResource { - // add some rest methods here - - @GET - public String hello() { - return "Hello hivemq-client"; - } -} diff --git a/integration-tests/src/main/resources/application.properties b/integration-tests/src/main/resources/application.properties deleted file mode 100644 index e69de29..0000000 diff --git a/integration-tests/src/test/java/io/quarkiverse/hivemqclient/it/HiveMQClientResourceTest.java b/integration-tests/src/test/java/io/quarkiverse/hivemqclient/it/HiveMQClientResourceTest.java deleted file mode 100644 index 908c8d6..0000000 --- a/integration-tests/src/test/java/io/quarkiverse/hivemqclient/it/HiveMQClientResourceTest.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.quarkiverse.hivemqclient.it; - -import static io.restassured.RestAssured.given; -import static org.hamcrest.Matchers.is; - -import org.junit.jupiter.api.Test; - -import io.quarkus.test.junit.QuarkusTest; - -@QuarkusTest -public class HiveMQClientResourceTest { - - @Test - public void testHelloEndpoint() { - given() - .when().get("/hivemq-client") - .then() - .statusCode(200) - .body(is("Hello hivemq-client")); - } -} diff --git a/integration-tests/src/test/java/io/quarkiverse/hivemqclient/it/NativeHiveMQClientResourceIT.java b/integration-tests/src/test/java/io/quarkiverse/hivemqclient/it/NativeHiveMQClientResourceIT.java deleted file mode 100644 index b11596c..0000000 --- a/integration-tests/src/test/java/io/quarkiverse/hivemqclient/it/NativeHiveMQClientResourceIT.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.quarkiverse.hivemqclient.it; - -import io.quarkus.test.junit.NativeImageTest; - -@NativeImageTest -public class NativeHiveMQClientResourceIT extends HiveMQClientResourceTest { -} diff --git a/pom.xml b/pom.xml index e50af9a..985b898 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ deployment runtime - kitchensink + integration-tests scm:git:git@github.com:quarkiverse/quarkus-hivemq-client.git @@ -31,6 +31,7 @@ UTF-8 2.16.2.Final 4.7.0 + 2.22.2 From a0956a97370987196914a005e3e9b0f6df360481 Mon Sep 17 00:00:00 2001 From: pablo gonzalez granados Date: Wed, 8 Mar 2023 16:29:00 +0100 Subject: [PATCH 2/5] Refactor Github CI actions Build job has been decopled into three jobs 'validate-format', 'linux-build-jvm' and 'linux-build-native' The last two jobs depends on 'validate-format', so once the project is validated, we will run both jobs in parallel. --- .github/dependabot.yml | 6 ++ .github/workflows/build.yml | 53 ------------------ .github/workflows/ci.yml | 106 ++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 53 deletions(-) delete mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/ci.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4b11d34..763fafa 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,9 +5,15 @@ version: 2 updates: + # Maintain dependencies for Maven - package-ecosystem: "maven" directory: "/" schedule: interval: "daily" ignore: - dependency-name: "org.apache.maven.plugins:maven-compiler-plugin" + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 3c39045..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Build - -on: - push: - branches: - - "main" - paths-ignore: - - '.gitignore' - - 'CODEOWNERS' - - 'LICENSE' - - '*.md' - - '*.adoc' - - '*.txt' - - '.all-contributorsrc' - pull_request: - paths-ignore: - - '.gitignore' - - 'CODEOWNERS' - - 'LICENSE' - - '*.md' - - '*.adoc' - - '*.txt' - - '.all-contributorsrc' - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Set up JDK 11 - uses: actions/setup-java@v1 - with: - java-version: 11 - - - name: Get Date - id: get-date - run: | - echo "::set-output name=date::$(/bin/date -u "+%Y-%m")" - shell: bash - - name: Cache Maven Repository - id: cache-maven - uses: actions/cache@v2 - with: - path: ~/.m2/repository - # refresh cache every month to avoid unlimited growth - key: maven-repo-${{ runner.os }}-${{ steps.get-date.outputs.date }} - - - name: Build with Maven - run: mvn -B formatter:validate verify --file pom.xml - diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..1ff3b25 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,106 @@ +name: "Pull Request CI" + +on: + push: + branches: + - "main" + paths-ignore: + - '.gitignore' + - 'CODEOWNERS' + - 'LICENSE' + - '*.md' + - '*.adoc' + - '*.txt' + - '.all-contributorsrc' + pull_request: + paths-ignore: + - '.gitignore' + - 'CODEOWNERS' + - 'LICENSE' + - '*.md' + - '*.adoc' + - '*.txt' + - '.all-contributorsrc' + +jobs: + validate-format: + runs-on: ubuntu-latest + strategy: + matrix: + java: [ 11 ] + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + distribution: 'temurin' + java-version: ${{ matrix.java }} + check-latest: true + - name: format + run: mvn -V -B formatter:validate verify -DskipTests -DskipITs + - name: Tar Maven Repo + shell: bash + run: tar -I 'pigz -9' -cf maven-repo.tgz -C ~ .m2/repository + - name: Persist Maven Repo + uses: actions/upload-artifact@v3 + with: + name: maven-repo + path: maven-repo.tgz + linux-build-jvm: + name: PR - Linux - JVM build - Latest Version + runs-on: ubuntu-latest + timeout-minutes: 20 + needs: validate-format + strategy: + matrix: + java: [ 11 ] + steps: + - uses: actions/checkout@v3 + - name: Install JDK {{ matrix.java }} + # Uses sha for added security since tags can be updated + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: ${{ matrix.java }} + check-latest: true + cache: 'maven' + - name: Download Maven Repo + uses: actions/download-artifact@v3 + with: + name: maven-repo + path: . + - name: Extract Maven Repo + shell: bash + run: tar -xzf maven-repo.tgz -C ~ + - name: Build with Maven + run: mvn -V -B -am clean verify +# TODO there is an error under investigation on Native mode +# linux-build-native: +# name: PR - Linux - Native build - Latest Version +# runs-on: ubuntu-latest +# timeout-minutes: 60 +# needs: validate-format +# strategy: +# matrix: +# java: [ 11 ] +# steps: +# - uses: actions/checkout@v3 +# - name: Install JDK {{ matrix.java }} +# # Uses sha for added security since tags can be updated +# uses: actions/setup-java@v3 +# with: +# distribution: 'temurin' +# java-version: ${{ matrix.java }} +# check-latest: true +# cache: 'maven' +# - name: Download Maven Repo +# uses: actions/download-artifact@v3 +# with: +# name: maven-repo +# path: . +# - name: Extract Maven Repo +# shell: bash +# run: tar -xzf maven-repo.tgz -C ~ +# - name: Build with Maven +# run: mvn -V -B -am clean verify -Dnative + From ab41c1271fdbb57566475a601fb4c55f17876c99 Mon Sep 17 00:00:00 2001 From: pablo gonzalez granados Date: Wed, 8 Mar 2023 16:36:19 +0100 Subject: [PATCH 3/5] Replace deprecated '@NativeImageTest' annotation by '@QuarkusIntegrationTest' --- .../io/quarkiverse/hivemqclient/NativeGreetingResourceIT.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration-tests/kitchensink/src/test/java/io/quarkiverse/hivemqclient/NativeGreetingResourceIT.java b/integration-tests/kitchensink/src/test/java/io/quarkiverse/hivemqclient/NativeGreetingResourceIT.java index b448f9e..ed9c7df 100644 --- a/integration-tests/kitchensink/src/test/java/io/quarkiverse/hivemqclient/NativeGreetingResourceIT.java +++ b/integration-tests/kitchensink/src/test/java/io/quarkiverse/hivemqclient/NativeGreetingResourceIT.java @@ -1,8 +1,8 @@ package io.quarkiverse.hivemqclient; -import io.quarkus.test.junit.NativeImageTest; +import io.quarkus.test.junit.QuarkusIntegrationTest; -@NativeImageTest +@QuarkusIntegrationTest public class NativeGreetingResourceIT extends GreetingResourceTest { // Execute the same tests but in native mode. From 1da0d1d94b05da733c05f9bd9a93f952473db6d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Aug 2023 18:34:35 +0000 Subject: [PATCH 4/5] Bump com.hivemq:hivemq-mqtt-client from 1.3.1 to 1.3.2 Bumps [com.hivemq:hivemq-mqtt-client](https://github.com/hivemq/hivemq-mqtt-client) from 1.3.1 to 1.3.2. - [Release notes](https://github.com/hivemq/hivemq-mqtt-client/releases) - [Changelog](https://github.com/hivemq/hivemq-mqtt-client/blob/master/RELEASE.md) - [Commits](https://github.com/hivemq/hivemq-mqtt-client/compare/v1.3.1...v1.3.2) --- updated-dependencies: - dependency-name: com.hivemq:hivemq-mqtt-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- runtime/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/pom.xml b/runtime/pom.xml index ad97b62..db404be 100644 --- a/runtime/pom.xml +++ b/runtime/pom.xml @@ -16,7 +16,7 @@ com.hivemq hivemq-mqtt-client - 1.3.1 + 1.3.2 io.smallrye.reactive From 0318763abd0b88e122cfb1c6a68298379db8daf8 Mon Sep 17 00:00:00 2001 From: Pablo Gonzalez Granados Date: Wed, 8 Mar 2023 21:12:29 +0100 Subject: [PATCH 5/5] Add smallrye coverage to integrations tests --- .all-contributorsrc | 12 ++- .../pom.xml | 12 +-- .../test/smallrye/PriceConverter.java | 30 +++++++ .../test/smallrye/PriceGenerator.java | 35 ++++++++ .../test/smallrye/PriceResource.java | 35 ++++++++ .../src/main/resources/application.properties | 13 +++ .../test/smallrye}/HivemqDefaultProfile.java | 2 +- .../test/smallrye}/HivemqResources.java | 9 ++- .../test/smallrye/PriceResourceIT.java | 7 ++ .../test/smallrye/PriceResourceTest.java | 62 ++++++++++++++ .../test/vanilla/HttpBridgeApplication.java | 12 --- .../test/vanilla/dto/MessageDto.java | 21 ----- .../test/vanilla/dto/PublishMsgRespDto.java | 15 ---- .../resources/BrokerPushToTopicResources.java | 46 ----------- .../BrokerSubscribeToTopicResources.java | 33 -------- .../test/vanilla/services/HiveProxy.java | 80 ------------------- .../src/main/resources/application.properties | 4 - .../BrokerPushToTopicResourcesTest.java | 32 -------- .../BrokerSubscribeToTopicResourceTest.java | 70 ---------------- .../test/vanilla/CommonsTestSuite.java | 26 ------ .../NativeBrokerPushToTopicResourcesIT.java | 7 -- integration-tests/pom.xml | 2 +- 22 files changed, 204 insertions(+), 361 deletions(-) rename integration-tests/{hivemq-client-vanilla => hivemq-client-smallrye}/pom.xml (88%) create mode 100644 integration-tests/hivemq-client-smallrye/src/main/java/io/quarkiverse/hivemqclient/test/smallrye/PriceConverter.java create mode 100644 integration-tests/hivemq-client-smallrye/src/main/java/io/quarkiverse/hivemqclient/test/smallrye/PriceGenerator.java create mode 100644 integration-tests/hivemq-client-smallrye/src/main/java/io/quarkiverse/hivemqclient/test/smallrye/PriceResource.java create mode 100644 integration-tests/hivemq-client-smallrye/src/main/resources/application.properties rename integration-tests/{hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla => hivemq-client-smallrye/src/test/java/io/quarkiverse/hivemqclient/test/smallrye}/HivemqDefaultProfile.java (86%) rename integration-tests/{hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla => hivemq-client-smallrye/src/test/java/io/quarkiverse/hivemqclient/test/smallrye}/HivemqResources.java (61%) create mode 100644 integration-tests/hivemq-client-smallrye/src/test/java/io/quarkiverse/hivemqclient/test/smallrye/PriceResourceIT.java create mode 100644 integration-tests/hivemq-client-smallrye/src/test/java/io/quarkiverse/hivemqclient/test/smallrye/PriceResourceTest.java delete mode 100644 integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/HttpBridgeApplication.java delete mode 100644 integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/dto/MessageDto.java delete mode 100644 integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/dto/PublishMsgRespDto.java delete mode 100644 integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/resources/BrokerPushToTopicResources.java delete mode 100644 integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/resources/BrokerSubscribeToTopicResources.java delete mode 100644 integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/services/HiveProxy.java delete mode 100644 integration-tests/hivemq-client-vanilla/src/main/resources/application.properties delete mode 100644 integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/BrokerPushToTopicResourcesTest.java delete mode 100644 integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/BrokerSubscribeToTopicResourceTest.java delete mode 100644 integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/CommonsTestSuite.java delete mode 100644 integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/NativeBrokerPushToTopicResourcesIT.java diff --git a/.all-contributorsrc b/.all-contributorsrc index 0c8efc1..6636ccd 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -14,7 +14,17 @@ "code", "maintenance" ] - } + }, + { + "login": "pjgg", + "name": "pjgg", + "avatar_url": "https://avatars.githubusercontent.com/u/3541131?v=4", + "profile": "https://github.com/pjgg", + "contributions": [ + "code", + "maintenance" + ] + } ], "contributorsPerLine": 7, "projectName": "quarkus-hivemq-client", diff --git a/integration-tests/hivemq-client-vanilla/pom.xml b/integration-tests/hivemq-client-smallrye/pom.xml similarity index 88% rename from integration-tests/hivemq-client-vanilla/pom.xml rename to integration-tests/hivemq-client-smallrye/pom.xml index 9f6255c..12d9f99 100644 --- a/integration-tests/hivemq-client-vanilla/pom.xml +++ b/integration-tests/hivemq-client-smallrye/pom.xml @@ -7,8 +7,8 @@ 1.0.1-SNAPSHOT - quarkus-hivemq-client-integration-tests-minimal - Quarkus - Hivemq Client - Integration Tests Vanilla + quarkus-hivemq-client-integration-tests-smallrye + Quarkus - Hivemq Client - Integration Tests smallrye 1.17.6 @@ -19,15 +19,11 @@ io.quarkus - quarkus-vertx + quarkus-resteasy-reactive io.quarkus - quarkus-resteasy-reactive-jackson - - - io.quarkus - quarkus-smallrye-openapi + quarkus-smallrye-reactive-messaging-mqtt io.quarkiverse.hivemqclient diff --git a/integration-tests/hivemq-client-smallrye/src/main/java/io/quarkiverse/hivemqclient/test/smallrye/PriceConverter.java b/integration-tests/hivemq-client-smallrye/src/main/java/io/quarkiverse/hivemqclient/test/smallrye/PriceConverter.java new file mode 100644 index 0000000..a519b40 --- /dev/null +++ b/integration-tests/hivemq-client-smallrye/src/main/java/io/quarkiverse/hivemqclient/test/smallrye/PriceConverter.java @@ -0,0 +1,30 @@ +package io.quarkiverse.hivemqclient.test.smallrye; + +import javax.enterprise.context.ApplicationScoped; + +import org.eclipse.microprofile.reactive.messaging.Incoming; +import org.eclipse.microprofile.reactive.messaging.Outgoing; +import org.jboss.logging.Logger; + +import io.smallrye.reactive.messaging.annotations.Broadcast; + +/** + * A bean consuming data from the "prices" MQTT topic and applying some conversion. + * The result is pushed to the "my-data-stream" stream which is an in-memory stream. + */ +@ApplicationScoped +public class PriceConverter { + + private static final Logger LOG = Logger.getLogger(PriceConverter.class); + private static final double CONVERSION_RATE = 0.88; + + @Incoming("prices") + @Outgoing("my-data-stream") + @Broadcast + public double process(byte[] priceRaw) { + int priceInUsd = Integer.parseInt(new String(priceRaw)); + LOG.infof("Receiving price: %d ", priceInUsd); + return priceInUsd * CONVERSION_RATE; + } + +} diff --git a/integration-tests/hivemq-client-smallrye/src/main/java/io/quarkiverse/hivemqclient/test/smallrye/PriceGenerator.java b/integration-tests/hivemq-client-smallrye/src/main/java/io/quarkiverse/hivemqclient/test/smallrye/PriceGenerator.java new file mode 100644 index 0000000..940e99a --- /dev/null +++ b/integration-tests/hivemq-client-smallrye/src/main/java/io/quarkiverse/hivemqclient/test/smallrye/PriceGenerator.java @@ -0,0 +1,35 @@ +package io.quarkiverse.hivemqclient.test.smallrye; + +import java.time.Duration; +import java.util.Random; + +import javax.enterprise.context.ApplicationScoped; + +import org.eclipse.microprofile.reactive.messaging.Outgoing; +import org.jboss.logging.Logger; + +import io.smallrye.mutiny.Multi; + +/** + * A bean producing random prices every second. + * The prices are written to a MQTT topic (prices). The MQTT configuration is specified in the application configuration. + */ +@ApplicationScoped +public class PriceGenerator { + + private static final Logger LOG = Logger.getLogger(PriceGenerator.class); + + private Random random = new Random(); + + @Outgoing("topic-price") + public Multi generate() { + return Multi.createFrom().ticks().every(Duration.ofSeconds(1)) + .onOverflow().drop() + .map(tick -> { + int price = random.nextInt(100); + LOG.infof("Sending price: %d", price); + return price; + }); + } + +} diff --git a/integration-tests/hivemq-client-smallrye/src/main/java/io/quarkiverse/hivemqclient/test/smallrye/PriceResource.java b/integration-tests/hivemq-client-smallrye/src/main/java/io/quarkiverse/hivemqclient/test/smallrye/PriceResource.java new file mode 100644 index 0000000..1e9da7b --- /dev/null +++ b/integration-tests/hivemq-client-smallrye/src/main/java/io/quarkiverse/hivemqclient/test/smallrye/PriceResource.java @@ -0,0 +1,35 @@ +package io.quarkiverse.hivemqclient.test.smallrye; + +import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.eclipse.microprofile.reactive.messaging.Channel; + +import io.smallrye.mutiny.Multi; + +/** + * A simple resource retrieving the "in-memory" "my-data-stream" and sending the items to a server sent event. + */ +@Path("/prices") +public class PriceResource { + + @Inject + @Channel("my-data-stream") + Multi prices; + + @GET + @Produces(MediaType.TEXT_PLAIN) + public String hello() { + return "hello"; + } + + @GET + @Path("/stream") + @Produces(MediaType.SERVER_SENT_EVENTS) + public Multi stream() { + return prices; + } +} diff --git a/integration-tests/hivemq-client-smallrye/src/main/resources/application.properties b/integration-tests/hivemq-client-smallrye/src/main/resources/application.properties new file mode 100644 index 0000000..8abf690 --- /dev/null +++ b/integration-tests/hivemq-client-smallrye/src/main/resources/application.properties @@ -0,0 +1,13 @@ +# Configure the MQTT sink (we write to it) +mp.messaging.outgoing.topic-price.type=smallrye-mqtt-hivemq +mp.messaging.outgoing.topic-price.topic=prices +mp.messaging.outgoing.topic-price.host=localhost +mp.messaging.outgoing.topic-price.port=1883 +mp.messaging.outgoing.topic-price.auto-generated-client-id=true + +# Configure the MQTT source (we read from it) +mp.messaging.incoming.prices.type=smallrye-mqtt-hivemq +mp.messaging.incoming.prices.topic=prices +mp.messaging.incoming.prices.host=localhost +mp.messaging.incoming.prices.port=1883 +mp.messaging.incoming.prices.auto-generated-client-id=true \ No newline at end of file diff --git a/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/HivemqDefaultProfile.java b/integration-tests/hivemq-client-smallrye/src/test/java/io/quarkiverse/hivemqclient/test/smallrye/HivemqDefaultProfile.java similarity index 86% rename from integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/HivemqDefaultProfile.java rename to integration-tests/hivemq-client-smallrye/src/test/java/io/quarkiverse/hivemqclient/test/smallrye/HivemqDefaultProfile.java index 093dcd0..956d6aa 100644 --- a/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/HivemqDefaultProfile.java +++ b/integration-tests/hivemq-client-smallrye/src/test/java/io/quarkiverse/hivemqclient/test/smallrye/HivemqDefaultProfile.java @@ -1,4 +1,4 @@ -package io.quarkiverse.hivemqclient.test.vanilla; +package io.quarkiverse.hivemqclient.test.smallrye; import java.util.Collections; import java.util.List; diff --git a/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/HivemqResources.java b/integration-tests/hivemq-client-smallrye/src/test/java/io/quarkiverse/hivemqclient/test/smallrye/HivemqResources.java similarity index 61% rename from integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/HivemqResources.java rename to integration-tests/hivemq-client-smallrye/src/test/java/io/quarkiverse/hivemqclient/test/smallrye/HivemqResources.java index 717907d..0598b0f 100644 --- a/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/HivemqResources.java +++ b/integration-tests/hivemq-client-smallrye/src/test/java/io/quarkiverse/hivemqclient/test/smallrye/HivemqResources.java @@ -1,4 +1,4 @@ -package io.quarkiverse.hivemqclient.test.vanilla; +package io.quarkiverse.hivemqclient.test.smallrye; import static org.testcontainers.utility.DockerImageName.parse; @@ -17,9 +17,10 @@ public class HivemqResources implements QuarkusTestResourceLifecycleManager { public Map start() { hivemqContainer.start(); Map config = new HashMap<>(); - config.put("hivemq.cluster.host", hivemqContainer.getHost()); - config.put("hivemq.cluster.port", "" + hivemqContainer.getMqttPort()); - + config.put("mp.messaging.outgoing.topic-price.host", hivemqContainer.getHost()); + config.put("mp.messaging.outgoing.topic-price.port", "" + hivemqContainer.getMqttPort()); + config.put("mp.messaging.incoming.prices.host", hivemqContainer.getHost()); + config.put("mp.messaging.incoming.prices.port", "" + hivemqContainer.getMqttPort()); return config; } diff --git a/integration-tests/hivemq-client-smallrye/src/test/java/io/quarkiverse/hivemqclient/test/smallrye/PriceResourceIT.java b/integration-tests/hivemq-client-smallrye/src/test/java/io/quarkiverse/hivemqclient/test/smallrye/PriceResourceIT.java new file mode 100644 index 0000000..7ad8d25 --- /dev/null +++ b/integration-tests/hivemq-client-smallrye/src/test/java/io/quarkiverse/hivemqclient/test/smallrye/PriceResourceIT.java @@ -0,0 +1,7 @@ +package io.quarkiverse.hivemqclient.test.smallrye; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +public class PriceResourceIT extends PriceResourceTest { +} diff --git a/integration-tests/hivemq-client-smallrye/src/test/java/io/quarkiverse/hivemqclient/test/smallrye/PriceResourceTest.java b/integration-tests/hivemq-client-smallrye/src/test/java/io/quarkiverse/hivemqclient/test/smallrye/PriceResourceTest.java new file mode 100644 index 0000000..f2b8fb2 --- /dev/null +++ b/integration-tests/hivemq-client-smallrye/src/test/java/io/quarkiverse/hivemqclient/test/smallrye/PriceResourceTest.java @@ -0,0 +1,62 @@ +package io.quarkiverse.hivemqclient.test.smallrye; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.net.URI; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.sse.SseEventSource; + +import org.jboss.logging.Logger; +import org.junit.jupiter.api.Test; + +import io.quarkus.test.common.http.TestHTTPResource; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; + +@TestProfile(HivemqDefaultProfile.class) +@QuarkusTest +public class PriceResourceTest { + + private static final Logger LOG = Logger.getLogger(PriceResourceTest.class); + + @TestHTTPResource("prices/stream") + URI pricesUrl; + + @Test + public void shouldGetHello() { + given() + .when().get("/prices") + .then() + .statusCode(200) + .body(is("hello")); + } + + @Test + public void shouldGetStreamOfPrices() { + Client client = ClientBuilder.newClient(); + WebTarget target = client.target(pricesUrl); + + AtomicInteger priceCount = new AtomicInteger(); + + try (SseEventSource source = SseEventSource.target(target).build()) { + source.register(event -> { + Double value = event.readData(Double.class); + LOG.infof("Received price: %f", value); + priceCount.incrementAndGet(); + }); + source.open(); + Thread.sleep(15 * 1000L); + } catch (InterruptedException ignored) { + } + + int count = priceCount.get(); + assertTrue(count > 1, "Expected more than 2 prices read from the source, got " + count); + } + +} diff --git a/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/HttpBridgeApplication.java b/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/HttpBridgeApplication.java deleted file mode 100644 index 1db3e92..0000000 --- a/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/HttpBridgeApplication.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.quarkiverse.hivemqclient.test.vanilla; - -import javax.ws.rs.core.Application; - -import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition; -import org.eclipse.microprofile.openapi.annotations.info.Contact; -import org.eclipse.microprofile.openapi.annotations.info.Info; -import org.eclipse.microprofile.openapi.annotations.info.License; - -@OpenAPIDefinition(info = @Info(title = "Http / HiveMQ bridge API example", version = "1.0.0", contact = @Contact(name = "Http / HiveMQ bridge API Support", url = "http://exampleurl.com/contact", email = "fake-support-examples@hivemq.com"), license = @License(name = "Apache 2.0", url = "https://www.apache.org/licenses/LICENSE-2.0.html"))) -public class HttpBridgeApplication extends Application { -} diff --git a/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/dto/MessageDto.java b/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/dto/MessageDto.java deleted file mode 100644 index 742f826..0000000 --- a/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/dto/MessageDto.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.quarkiverse.hivemqclient.test.vanilla.dto; - -public class MessageDto { - - private String value; - - public MessageDto() { - } - - public MessageDto(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } -} diff --git a/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/dto/PublishMsgRespDto.java b/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/dto/PublishMsgRespDto.java deleted file mode 100644 index 6c65fe4..0000000 --- a/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/dto/PublishMsgRespDto.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.quarkiverse.hivemqclient.test.vanilla.dto; - -public class PublishMsgRespDto { - - private final String topic; - - public PublishMsgRespDto(String topic) { - this.topic = topic; - } - - public String getTopic() { - return topic; - } - -} diff --git a/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/resources/BrokerPushToTopicResources.java b/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/resources/BrokerPushToTopicResources.java deleted file mode 100644 index e75dc8e..0000000 --- a/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/resources/BrokerPushToTopicResources.java +++ /dev/null @@ -1,46 +0,0 @@ -package io.quarkiverse.hivemqclient.test.vanilla.resources; - -import javax.ws.rs.Consumes; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -import org.jboss.resteasy.reactive.RestPath; - -import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5PublishResult; - -import io.quarkiverse.hivemqclient.test.vanilla.dto.MessageDto; -import io.quarkiverse.hivemqclient.test.vanilla.dto.PublishMsgRespDto; -import io.quarkiverse.hivemqclient.test.vanilla.services.HiveProxy; -import io.smallrye.mutiny.Uni; - -@Consumes(MediaType.APPLICATION_JSON) -@Produces(MediaType.APPLICATION_JSON) -@Path("/mqtt/{brokerName}/push") -public class BrokerPushToTopicResources { - - private HiveProxy hiveProxy; - - BrokerPushToTopicResources(HiveProxy hiveProxy) { - this.hiveProxy = hiveProxy; - } - - @POST - @Path("/{topicName}") - public Uni pushMessage(@RestPath("brokerName") String brokerName, @RestPath("topicName") String topicName, - MessageDto message) { - return hiveProxy - .pushSimpleMsg(brokerName, topicName, message.getValue()) - .onItem().transform(payload -> makePushMsgResponse(topicName, payload)); - } - - private static Response makePushMsgResponse(String topicName, Mqtt5PublishResult payload) { - if (payload.getError().isPresent()) { - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(payload.getError().get().getMessage()).build(); - } - - return Response.status(Response.Status.CREATED).entity(new PublishMsgRespDto(topicName)).build(); - } -} diff --git a/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/resources/BrokerSubscribeToTopicResources.java b/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/resources/BrokerSubscribeToTopicResources.java deleted file mode 100644 index 368928b..0000000 --- a/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/resources/BrokerSubscribeToTopicResources.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.quarkiverse.hivemqclient.test.vanilla.resources; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.core.MediaType; - -import org.jboss.resteasy.reactive.RestPath; -import org.jboss.resteasy.reactive.RestStreamElementType; - -import io.quarkiverse.hivemqclient.test.vanilla.services.HiveProxy; -import io.smallrye.mutiny.Multi; -import io.vertx.mutiny.core.eventbus.EventBus; - -@Path("/mqtt/{brokerName}/subscribe") -public class BrokerSubscribeToTopicResources { - - private EventBus bus; - private HiveProxy hiveProxy; - - BrokerSubscribeToTopicResources(EventBus bus, HiveProxy hiveProxy) { - this.bus = bus; - this.hiveProxy = hiveProxy; - } - - @GET - @Path("/{topicName}") - @RestStreamElementType(MediaType.TEXT_PLAIN) - public Multi subscribeToTopic(@RestPath("brokerName") String brokerName, @RestPath("topicName") String topicName) { - return hiveProxy.subscribeTo(brokerName, topicName).toMulti() - .flatMap(topic -> bus. consumer(topic).bodyStream().toMulti()); - } - -} diff --git a/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/services/HiveProxy.java b/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/services/HiveProxy.java deleted file mode 100644 index f5f6c85..0000000 --- a/integration-tests/hivemq-client-vanilla/src/main/java/io/quarkiverse/hivemqclient/test/vanilla/services/HiveProxy.java +++ /dev/null @@ -1,80 +0,0 @@ -package io.quarkiverse.hivemqclient.test.vanilla.services; - -import static com.hivemq.client.mqtt.MqttGlobalPublishFilter.ALL; -import static java.nio.charset.StandardCharsets.UTF_8; - -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; - -import javax.inject.Singleton; - -import org.eclipse.microprofile.config.inject.ConfigProperty; - -import com.hivemq.client.mqtt.MqttClient; -import com.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient; -import com.hivemq.client.mqtt.mqtt5.message.connect.connack.Mqtt5ConnAck; -import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5PublishResult; - -import io.smallrye.mutiny.Uni; -import io.vertx.mutiny.core.eventbus.EventBus; - -@Singleton -public class HiveProxy { - - private EventBus bus; - private String clusterHostName; - private int clusterPort; - private final Map connectionsPool = new ConcurrentHashMap<>(); - - HiveProxy( - EventBus bus, - @ConfigProperty(name = "hivemq.cluster.host", defaultValue = "localhost") String clusterHostName, - @ConfigProperty(name = "hivemq.cluster.port") int clusterPort) { - - this.bus = bus; - this.clusterHostName = clusterHostName; - this.clusterPort = clusterPort; - } - - public Uni pushSimpleMsg(final String brokerName, final String topic, final String msg) { - return getMqttClient(brokerName) - .flatMap(conn -> Uni.createFrom() - .completionStage(() -> conn.publishWith().topic(topic).payload(UTF_8.encode(msg)).send())); - } - - public Uni subscribeTo(final String brokerName, final String topic) { - String internalTopicName = getInternalSubscriptionTopicName(brokerName, topic); - return getMqttClient(brokerName) - .map(conn -> { - conn.subscribeWith().topicFilter(topic).send(); - conn.toAsync().publishes(ALL, - event -> bus.send(internalTopicName, UTF_8.decode(event.getPayload().get()).toString())); - return internalTopicName; - }); - } - - private Uni getMqttClient(final String brokerName) { - Mqtt5AsyncClient client = connectionsPool.get(brokerName); - if (Objects.isNull(client)) { - return newMQTTClient().invoke(asyncClient -> connectionsPool.put(brokerName, asyncClient)); - } - - return Uni.createFrom().item(client); - } - - private Uni newMQTTClient() { - Mqtt5AsyncClient asyncClient = MqttClient.builder() - .useMqttVersion5() - .serverHost(clusterHostName) - .serverPort(clusterPort) - .buildAsync(); - - Uni ack = Uni.createFrom().completionStage(asyncClient::connect); - return ack.map(completed -> asyncClient); - } - - private String getInternalSubscriptionTopicName(final String brokerName, final String topic) { - return brokerName + "_" + topic; - } -} diff --git a/integration-tests/hivemq-client-vanilla/src/main/resources/application.properties b/integration-tests/hivemq-client-vanilla/src/main/resources/application.properties deleted file mode 100644 index 282a529..0000000 --- a/integration-tests/hivemq-client-vanilla/src/main/resources/application.properties +++ /dev/null @@ -1,4 +0,0 @@ -# hiveMQ config -hivemq.cluster.host=localhost -hivemq.cluster.port=8883 - diff --git a/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/BrokerPushToTopicResourcesTest.java b/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/BrokerPushToTopicResourcesTest.java deleted file mode 100644 index bcb6c64..0000000 --- a/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/BrokerPushToTopicResourcesTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.quarkiverse.hivemqclient.test.vanilla; - -import javax.ws.rs.core.Response; - -import org.junit.jupiter.api.Test; - -import io.quarkus.test.junit.QuarkusTest; -import io.quarkus.test.junit.TestProfile; - -@TestProfile(HivemqDefaultProfile.class) -@QuarkusTest -public class BrokerPushToTopicResourcesTest extends CommonsTestSuite { - - @Test - public void verifyMessageIsPushed() { - final String message = "helloWorld!"; - final String topicName = "hello"; - - pushMessage(DEFAULT_BROKER_NAME, topicName, message, Response.Status.CREATED); - } - - @Test - public void verifyMassivePush() { - final int amountOfEvents = 1000; - final String message = "helloWorld!"; - final String topicName = "hello"; - - for (int i = 0; i < amountOfEvents; i++) { - pushMessage(DEFAULT_BROKER_NAME, topicName, message, Response.Status.CREATED); - } - } -} diff --git a/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/BrokerSubscribeToTopicResourceTest.java b/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/BrokerSubscribeToTopicResourceTest.java deleted file mode 100644 index bc91990..0000000 --- a/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/BrokerSubscribeToTopicResourceTest.java +++ /dev/null @@ -1,70 +0,0 @@ -package io.quarkiverse.hivemqclient.test.vanilla; - -import static java.util.concurrent.TimeUnit.SECONDS; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.testcontainers.shaded.org.awaitility.Awaitility.await; - -import java.net.URI; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.Response; -import javax.ws.rs.sse.SseEventSource; - -import org.hamcrest.Matchers; -import org.junit.jupiter.api.Test; - -import io.quarkus.test.common.http.TestHTTPResource; -import io.quarkus.test.junit.QuarkusTest; -import io.quarkus.test.junit.TestProfile; - -@TestProfile(HivemqDefaultProfile.class) -@QuarkusTest -class BrokerSubscribeToTopicResourceTest extends CommonsTestSuite { - private final String message = "helloWorld!"; - private final String topicName = "hello"; - - @TestHTTPResource("/mqtt/") - private URI brokerSubscribeToTopicResource; - - @Test - void verifyServerSentEventSubscription() throws InterruptedException { - - // create a client for `BrokerSubscribeToTopicResources` and collect the consumed resources in a list - WebTarget target = ClientBuilder.newClient() - .target(brokerSubscribeToTopicResource + DEFAULT_BROKER_NAME + "/subscribe/hello"); - List received = new CopyOnWriteArrayList<>(); - SseEventSource source = SseEventSource.target(target).build(); - source.register(inboundSseEvent -> received.add(inboundSseEvent.readData())); - - // in a separate thread, feed the `BrokerPushToTopicResource` - ExecutorService msgSender = startSendingMsg(); - source.open(); - // check if, after at most 5 seconds, we have at least 'expectedMsgAmount' items collected, and they are what we expect - await().atMost(30, SECONDS).until(() -> received.size() >= 2); - assertThat(received, Matchers.hasItems("helloWorld!", "helloWorld!", "helloWorld!")); - source.close(); - - // shutdown the executor that is feeding the `BrokerPushToTopicResource` - msgSender.shutdown(); - msgSender.awaitTermination(5, SECONDS); - } - - private ExecutorService startSendingMsg() { - ExecutorService executorService = Executors.newSingleThreadExecutor(); - executorService.execute(() -> { - while (true) { - try { - pushMessage(DEFAULT_BROKER_NAME, topicName, message, Response.Status.CREATED); - } catch (Exception e) { - // Ignore errors when test is completed: Connection refused - } - } - }); - return executorService; - } -} diff --git a/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/CommonsTestSuite.java b/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/CommonsTestSuite.java deleted file mode 100644 index c24513d..0000000 --- a/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/CommonsTestSuite.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.quarkiverse.hivemqclient.test.vanilla; - -import static io.restassured.RestAssured.given; -import static org.hamcrest.CoreMatchers.equalTo; - -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; - -import io.quarkiverse.hivemqclient.test.vanilla.dto.MessageDto; - -public abstract class CommonsTestSuite { - - protected final static String DEFAULT_BROKER_NAME = "test"; - - protected void pushMessage(final String brokerName, final String topic, final String msg, - final Response.Status ExpectedStatusCode) { - given() - .when() - .header("Content-Type", MediaType.APPLICATION_JSON) - .body(new MessageDto(msg)) - .post("/mqtt/" + brokerName + "/push/" + topic) - .then() - .statusCode(ExpectedStatusCode.getStatusCode()) - .body("topic", equalTo(topic)); - } -} diff --git a/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/NativeBrokerPushToTopicResourcesIT.java b/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/NativeBrokerPushToTopicResourcesIT.java deleted file mode 100644 index b68471e..0000000 --- a/integration-tests/hivemq-client-vanilla/src/test/java/io/quarkiverse/hivemqclient/test/vanilla/NativeBrokerPushToTopicResourcesIT.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.quarkiverse.hivemqclient.test.vanilla; - -import io.quarkus.test.junit.QuarkusIntegrationTest; - -@QuarkusIntegrationTest -public class NativeBrokerPushToTopicResourcesIT extends BrokerPushToTopicResourcesTest { -} diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index db962f7..990882d 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -12,7 +12,7 @@ Quarkus - Hivemq Client - Integration Tests - hivemq-client-vanilla + hivemq-client-smallrye kitchensink