diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle deleted file mode 100644 index 67840524..00000000 --- a/buildSrc/build.gradle +++ /dev/null @@ -1,3 +0,0 @@ -plugins { - id 'groovy-gradle-plugin' -} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 00000000..849c690f --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + id("groovy-gradle-plugin") +} + +repositories { + gradlePluginPortal() +} + +dependencies { + implementation("org.graalvm.buildtools.native:org.graalvm.buildtools.native.gradle.plugin:0.9.21") + implementation("io.micronaut.gradle:micronaut-gradle-plugin:4.0.0-M1") + implementation("io.micronaut.gradle:micronaut-test-resources-plugin:4.0.0-M1") +} diff --git a/buildSrc/src/main/groovy/io.micronaut.build.internal.graal-test.gradle b/buildSrc/src/main/groovy/io.micronaut.build.internal.graal-test.gradle new file mode 100644 index 00000000..18afcf08 --- /dev/null +++ b/buildSrc/src/main/groovy/io.micronaut.build.internal.graal-test.gradle @@ -0,0 +1,53 @@ +plugins { + id("org.graalvm.buildtools.native") + id("io.micronaut.library") + id("io.micronaut.test-resources") +} + +repositories { + mavenCentral() +} + +configurations.all { + resolutionStrategy { + force 'io.micronaut.platform:micronaut-platform:4.0.0-M1' + } +} + +dependencies { + testAnnotationProcessor(mn.micronaut.inject.java) + testImplementation(mn.micronaut.http) + testImplementation(mn.micronaut.json.core) + testImplementation(mn.micronaut.http.client) + testImplementation(mn.micronaut.http.server.netty) + testImplementation(mnTest.micronaut.test.junit5) + testImplementation(libs.awaitility) + testImplementation(mnSerde.micronaut.serde.jackson) + testRuntimeOnly(mn.logback.classic) +} + +micronaut { + version = libs.versions.micronaut.asProvider().get() + testResources { + enabled = true + additionalModules.add("hivemq") + } +} + +test { + useJUnitPlatform() +} + +def isGraalVMJdk = ["jvmci.Compiler", "java.vendor.version", "java.vendor"].any { + System.getProperty(it)?.toLowerCase(Locale.ENGLISH)?.contains("graal") +} + +tasks.named("check") { + if (isGraalVMJdk) { + it.dependsOn("nativeTest") + } +} + +graalvmNative { + toolchainDetection.set(false) +} diff --git a/settings.gradle b/settings.gradle index 738e93fc..2c4ad183 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,12 +1,12 @@ pluginManagement { repositories { - gradlePluginPortal() mavenCentral() + gradlePluginPortal() } } plugins { - id("io.micronaut.build.shared.settings") version "6.4.1" + id("io.micronaut.build.shared.settings") version "6.4.2" } enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") @@ -19,13 +19,19 @@ include 'mqttv5' include 'test-suite-utils' include 'mqtt-ssl' include 'mqtt-bom' + include 'test-suite-groovy' include 'test-suite' include 'test-suite-kotlin' +include 'test-suite-mqttv3-graal' +include 'test-suite-mqttv5-graal' + +enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") micronautBuild { addSnapshotRepository() useStandardizedProjectNames = true + importMicronautCatalog() importMicronautCatalog("micronaut-serde") importMicronautCatalog("micronaut-validation") diff --git a/src/main/docs/guide/consumer/consumerExecutor.adoc b/src/main/docs/guide/consumer/consumerExecutor.adoc index e668f344..97beca3f 100644 --- a/src/main/docs/guide/consumer/consumerExecutor.adoc +++ b/src/main/docs/guide/consumer/consumerExecutor.adoc @@ -3,7 +3,7 @@ MQTT allows an link:{jdkapi}/java/util/concurrent/ExecutorService.html[ExecutorS For example: .Configuring the `consumer` thread pool -[source,yaml] +[configuration] ---- micronaut: executors: diff --git a/test-suite-mqttv3-graal/build.gradle.kts b/test-suite-mqttv3-graal/build.gradle.kts new file mode 100644 index 00000000..f88a1897 --- /dev/null +++ b/test-suite-mqttv3-graal/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + id("io.micronaut.build.internal.graal-test") +} + +repositories { + mavenCentral() +} + +dependencies { + testImplementation(projects.micronautMqttv3) +} diff --git a/test-suite-mqttv3-graal/src/test/java/io/micronaut/mqtt3/graal/MessageConverterMqttClient.java b/test-suite-mqttv3-graal/src/test/java/io/micronaut/mqtt3/graal/MessageConverterMqttClient.java new file mode 100644 index 00000000..5eb5a55e --- /dev/null +++ b/test-suite-mqttv3-graal/src/test/java/io/micronaut/mqtt3/graal/MessageConverterMqttClient.java @@ -0,0 +1,12 @@ +package io.micronaut.mqtt3.graal; + +import io.micronaut.mqtt.annotation.Topic; +import io.micronaut.mqtt.v3.annotation.MqttPublisher; + +@MqttPublisher +public interface MessageConverterMqttClient { + + @Topic("message") + void sendMessage(MessageRequest messageRequest); + +} diff --git a/test-suite-mqttv3-graal/src/test/java/io/micronaut/mqtt3/graal/MessageListener.java b/test-suite-mqttv3-graal/src/test/java/io/micronaut/mqtt3/graal/MessageListener.java new file mode 100644 index 00000000..b8f60104 --- /dev/null +++ b/test-suite-mqttv3-graal/src/test/java/io/micronaut/mqtt3/graal/MessageListener.java @@ -0,0 +1,23 @@ +package io.micronaut.mqtt3.graal; + +import io.micronaut.mqtt.annotation.MqttSubscriber; +import io.micronaut.mqtt.annotation.Topic; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@MqttSubscriber +public class MessageListener { + + private final List messages = Collections.synchronizedList(new ArrayList<>()); + + @Topic("message") + public void receiveMessage(MessageRequest message) { + messages.add(new MessageResponse(message.getText())); + } + + public List getMessages() { + return messages; + } +} diff --git a/test-suite-mqttv3-graal/src/test/java/io/micronaut/mqtt3/graal/MessageRequest.java b/test-suite-mqttv3-graal/src/test/java/io/micronaut/mqtt3/graal/MessageRequest.java new file mode 100644 index 00000000..7d17f56d --- /dev/null +++ b/test-suite-mqttv3-graal/src/test/java/io/micronaut/mqtt3/graal/MessageRequest.java @@ -0,0 +1,17 @@ +package io.micronaut.mqtt3.graal; + +import io.micronaut.core.annotation.Introspected; + +@Introspected +public class MessageRequest { + + private final String text; + + public MessageRequest(String text) { + this.text = text; + } + + public String getText() { + return text; + } +} diff --git a/test-suite-mqttv3-graal/src/test/java/io/micronaut/mqtt3/graal/MessageResponse.java b/test-suite-mqttv3-graal/src/test/java/io/micronaut/mqtt3/graal/MessageResponse.java new file mode 100644 index 00000000..07bf7fcd --- /dev/null +++ b/test-suite-mqttv3-graal/src/test/java/io/micronaut/mqtt3/graal/MessageResponse.java @@ -0,0 +1,28 @@ +package io.micronaut.mqtt3.graal; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.micronaut.serde.annotation.Serdeable; + +import java.time.LocalDateTime; + +@Serdeable +public class MessageResponse { + + private final String text; + + private final LocalDateTime date; + + public MessageResponse(String text) { + this.text = text.toUpperCase(); + this.date = LocalDateTime.now(); + } + + public String getText() { + return text; + } + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") + public LocalDateTime getDate() { + return date; + } +} diff --git a/test-suite-mqttv3-graal/src/test/java/io/micronaut/mqtt3/graal/MqttController.java b/test-suite-mqttv3-graal/src/test/java/io/micronaut/mqtt3/graal/MqttController.java new file mode 100644 index 00000000..f3df4872 --- /dev/null +++ b/test-suite-mqttv3-graal/src/test/java/io/micronaut/mqtt3/graal/MqttController.java @@ -0,0 +1,30 @@ +package io.micronaut.mqtt3.graal; + +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; + +import java.util.List; + +@Controller("/mqtt") +public class MqttController { + + private final MessageConverterMqttClient messageConverterMqttClient; + private final MessageListener messageListener; + + public MqttController(MessageConverterMqttClient messageConverterMqttClient, + MessageListener messageListener) { + this.messageConverterMqttClient = messageConverterMqttClient; + this.messageListener = messageListener; + } + + @Get("/send/{text}") + public void send(String text) { + messageConverterMqttClient.sendMessage(new MessageRequest(text)); + } + + @Get("/messages") + public List messages() { + return messageListener.getMessages(); + } + +} diff --git a/test-suite-mqttv3-graal/src/test/java/io/micronaut/mqtt3/graal/MqttTest.java b/test-suite-mqttv3-graal/src/test/java/io/micronaut/mqtt3/graal/MqttTest.java new file mode 100644 index 00000000..ac80edec --- /dev/null +++ b/test-suite-mqttv3-graal/src/test/java/io/micronaut/mqtt3/graal/MqttTest.java @@ -0,0 +1,36 @@ +package io.micronaut.mqtt3.graal; + +import io.micronaut.context.annotation.Property; +import io.micronaut.core.type.Argument; +import io.micronaut.http.HttpRequest; +import io.micronaut.http.HttpResponse; +import io.micronaut.http.client.HttpClient; +import io.micronaut.http.client.annotation.Client; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@MicronautTest +@Property(name = "mqtt.client.client-id", value = "micronaut") +class MqttTest { + + @Inject + @Client("/") + HttpClient httpClient; + + @Test + void helloWorld() { + HttpResponse exchange = httpClient.toBlocking().exchange("/mqtt/send/Micronaut"); + assertEquals(200, exchange.getStatus().getCode()); + await().atMost(5, TimeUnit.SECONDS).until(() -> { + List exchange1 = httpClient.toBlocking().exchange(HttpRequest.GET("/mqtt/messages"), Argument.listOf(MessageResponse.class)).body(); + return exchange1 != null && exchange1.size() == 1 && exchange1.get(0).getText().equals("MICRONAUT"); + }); + } +} diff --git a/test-suite-mqttv3-graal/src/test/resources/logback.xml b/test-suite-mqttv3-graal/src/test/resources/logback.xml new file mode 100644 index 00000000..17f2807e --- /dev/null +++ b/test-suite-mqttv3-graal/src/test/resources/logback.xml @@ -0,0 +1,17 @@ + + + + true + + + %cyan(%d{HH:mm:ss.SSS}) %gray([%thread]) %highlight(%-5level) %magenta(%logger{36}) - %msg%n + + + + + + + + + diff --git a/test-suite-mqttv5-graal/build.gradle.kts b/test-suite-mqttv5-graal/build.gradle.kts new file mode 100644 index 00000000..c2055e90 --- /dev/null +++ b/test-suite-mqttv5-graal/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + id("io.micronaut.build.internal.graal-test") +} + +repositories { + mavenCentral() +} + +dependencies { + testImplementation(projects.micronautMqttv5) +} diff --git a/test-suite-mqttv5-graal/src/test/java/io/micronaut/mqtt5/graal/MessageConverterMqttClient.java b/test-suite-mqttv5-graal/src/test/java/io/micronaut/mqtt5/graal/MessageConverterMqttClient.java new file mode 100644 index 00000000..f81cfd98 --- /dev/null +++ b/test-suite-mqttv5-graal/src/test/java/io/micronaut/mqtt5/graal/MessageConverterMqttClient.java @@ -0,0 +1,12 @@ +package io.micronaut.mqtt5.graal; + +import io.micronaut.mqtt.annotation.Topic; +import io.micronaut.mqtt.v5.annotation.MqttPublisher; + +@MqttPublisher +public interface MessageConverterMqttClient { + + @Topic("message") + void sendMessage(MessageRequest messageRequest); + +} diff --git a/test-suite-mqttv5-graal/src/test/java/io/micronaut/mqtt5/graal/MessageListener.java b/test-suite-mqttv5-graal/src/test/java/io/micronaut/mqtt5/graal/MessageListener.java new file mode 100644 index 00000000..b9b98b14 --- /dev/null +++ b/test-suite-mqttv5-graal/src/test/java/io/micronaut/mqtt5/graal/MessageListener.java @@ -0,0 +1,23 @@ +package io.micronaut.mqtt5.graal; + +import io.micronaut.mqtt.annotation.MqttSubscriber; +import io.micronaut.mqtt.annotation.Topic; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@MqttSubscriber +public class MessageListener { + + private final List messages = Collections.synchronizedList(new ArrayList<>()); + + @Topic("message") + public void receiveMessage(MessageRequest message) { + messages.add(new MessageResponse(message.getText())); + } + + public List getMessages() { + return messages; + } +} diff --git a/test-suite-mqttv5-graal/src/test/java/io/micronaut/mqtt5/graal/MessageRequest.java b/test-suite-mqttv5-graal/src/test/java/io/micronaut/mqtt5/graal/MessageRequest.java new file mode 100644 index 00000000..444892e7 --- /dev/null +++ b/test-suite-mqttv5-graal/src/test/java/io/micronaut/mqtt5/graal/MessageRequest.java @@ -0,0 +1,17 @@ +package io.micronaut.mqtt5.graal; + +import io.micronaut.core.annotation.Introspected; + +@Introspected +public class MessageRequest { + + private final String text; + + public MessageRequest(String text) { + this.text = text; + } + + public String getText() { + return text; + } +} diff --git a/test-suite-mqttv5-graal/src/test/java/io/micronaut/mqtt5/graal/MessageResponse.java b/test-suite-mqttv5-graal/src/test/java/io/micronaut/mqtt5/graal/MessageResponse.java new file mode 100644 index 00000000..d62dcb92 --- /dev/null +++ b/test-suite-mqttv5-graal/src/test/java/io/micronaut/mqtt5/graal/MessageResponse.java @@ -0,0 +1,28 @@ +package io.micronaut.mqtt5.graal; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.micronaut.serde.annotation.Serdeable; + +import java.time.LocalDateTime; + +@Serdeable +public class MessageResponse { + + private final String text; + + private final LocalDateTime date; + + public MessageResponse(String text) { + this.text = text.toUpperCase(); + this.date = LocalDateTime.now(); + } + + public String getText() { + return text; + } + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") + public LocalDateTime getDate() { + return date; + } +} diff --git a/test-suite-mqttv5-graal/src/test/java/io/micronaut/mqtt5/graal/MqttController.java b/test-suite-mqttv5-graal/src/test/java/io/micronaut/mqtt5/graal/MqttController.java new file mode 100644 index 00000000..59036eb2 --- /dev/null +++ b/test-suite-mqttv5-graal/src/test/java/io/micronaut/mqtt5/graal/MqttController.java @@ -0,0 +1,30 @@ +package io.micronaut.mqtt5.graal; + +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; + +import java.util.List; + +@Controller("/mqtt") +public class MqttController { + + private final MessageConverterMqttClient messageConverterMqttClient; + private final MessageListener messageListener; + + public MqttController(MessageConverterMqttClient messageConverterMqttClient, + MessageListener messageListener) { + this.messageConverterMqttClient = messageConverterMqttClient; + this.messageListener = messageListener; + } + + @Get("/send/{text}") + public void send(String text) { + messageConverterMqttClient.sendMessage(new MessageRequest(text)); + } + + @Get("/messages") + public List messages() { + return messageListener.getMessages(); + } + +} diff --git a/test-suite-mqttv5-graal/src/test/java/io/micronaut/mqtt5/graal/MqttTest.java b/test-suite-mqttv5-graal/src/test/java/io/micronaut/mqtt5/graal/MqttTest.java new file mode 100644 index 00000000..96410b4a --- /dev/null +++ b/test-suite-mqttv5-graal/src/test/java/io/micronaut/mqtt5/graal/MqttTest.java @@ -0,0 +1,38 @@ +package io.micronaut.mqtt5.graal; + +import io.micronaut.context.annotation.Property; +import io.micronaut.core.annotation.Introspected; +import io.micronaut.core.type.Argument; +import io.micronaut.http.HttpRequest; +import io.micronaut.http.HttpResponse; +import io.micronaut.http.client.HttpClient; +import io.micronaut.http.client.annotation.Client; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@MicronautTest +@Property(name = "mqtt.client.client-id", value = "micronaut") +class MqttTest { + + @Inject + @Client("/") + HttpClient httpClient; + + @Test + void helloWorld() { + HttpResponse exchange = httpClient.toBlocking().exchange("/mqtt/send/Micronaut"); + assertEquals(200, exchange.getStatus().getCode()); + await().atMost(5, TimeUnit.SECONDS).until(() -> { + List exchange1 = httpClient.toBlocking().exchange(HttpRequest.GET("/mqtt/messages"), Argument.listOf(MessageResponse.class)).body(); + return exchange1 != null && exchange1.size() == 1 && exchange1.get(0).getText().equals("MICRONAUT"); + }); + } +} diff --git a/test-suite-mqttv5-graal/src/test/resources/logback.xml b/test-suite-mqttv5-graal/src/test/resources/logback.xml new file mode 100644 index 00000000..17f2807e --- /dev/null +++ b/test-suite-mqttv5-graal/src/test/resources/logback.xml @@ -0,0 +1,17 @@ + + + + true + + + %cyan(%d{HH:mm:ss.SSS}) %gray([%thread]) %highlight(%-5level) %magenta(%logger{36}) - %msg%n + + + + + + + + +