diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 67840524..2209f9f3 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -1,3 +1,15 @@ plugins { id 'groovy-gradle-plugin' } + +repositories { + gradlePluginPortal() + mavenCentral() +} + +dependencies { + implementation libs.gradle.micronaut + implementation libs.gradle.kotlin + implementation libs.gradle.kotlin.allopen + implementation libs.gradle.kotlin.noarg +} diff --git a/buildSrc/settings.gradle b/buildSrc/settings.gradle new file mode 100644 index 00000000..242e53d0 --- /dev/null +++ b/buildSrc/settings.gradle @@ -0,0 +1,10 @@ +rootProject.name = 'nats-parent' +dependencyResolutionManagement { + dependencyResolutionManagement { + versionCatalogs { + libs { + from(files("../gradle/libs.versions.toml")) + } + } + } +} diff --git a/buildSrc/src/main/groovy/io.micronaut.build.internal.nats-base.gradle b/buildSrc/src/main/groovy/io.micronaut.build.internal.nats-base.gradle index ec8bb307..57eb3acb 100644 --- a/buildSrc/src/main/groovy/io.micronaut.build.internal.nats-base.gradle +++ b/buildSrc/src/main/groovy/io.micronaut.build.internal.nats-base.gradle @@ -1,15 +1,19 @@ +plugins { + id 'java' +} + repositories { mavenCentral() - maven { url "https://s01.oss.sonatype.org/content/repositories/snapshots/" } -} + maven { url "https://s01.oss.sonatype.org/content/repositories/snapshots/" }} -configurations.all { - resolutionStrategy.dependencySubstitution { - substitute(module("org.codehaus.groovy:groovy")) - .using(module("org.apache.groovy:groovy:${libs.versions.groovy.get()}")) - } +dependencies { + testRuntimeOnly mn.logback.classic } -tasks.withType(GroovyCompile).configureEach { - options.forkOptions.jvmArgs << '-Dspock.iKnowWhatImDoing.disableGroovyVersionCheck=true' +test { + useJUnitPlatform() + + jvmArgs '-Duser.country=US' + jvmArgs '-Duser.language=en' + failFast = true } diff --git a/buildSrc/src/main/groovy/io.micronaut.build.internal.nats-examples.gradle b/buildSrc/src/main/groovy/io.micronaut.build.internal.nats-examples.gradle new file mode 100644 index 00000000..ef1851ca --- /dev/null +++ b/buildSrc/src/main/groovy/io.micronaut.build.internal.nats-examples.gradle @@ -0,0 +1,30 @@ +plugins { + id "io.micronaut.build.internal.nats-base" + id "io.micronaut.application" + id "io.micronaut.test-resources" +} + +dependencies { + testImplementation projects.micronautNats + + runtimeOnly mn.snakeyaml + testRuntimeOnly mn.snakeyaml + testImplementation mn.reactor + testImplementation libs.awaitility + testImplementation 'io.micronaut.testresources:micronaut-test-resources-client' +} + + +configurations.all { + resolutionStrategy.dependencySubstitution { + substitute module('io.micronaut.nats:micronaut-nats') using project(':micronaut-nats') + } +} + +micronaut { + version libs.versions.micronaut.platform.get() + testRuntime "junit5" + testResources { + clientTimeout = 300 + } +} diff --git a/buildSrc/src/main/groovy/io.micronaut.build.internal.nats-native-tests.gradle b/buildSrc/src/main/groovy/io.micronaut.build.internal.nats-native-tests.gradle new file mode 100644 index 00000000..51a91725 --- /dev/null +++ b/buildSrc/src/main/groovy/io.micronaut.build.internal.nats-native-tests.gradle @@ -0,0 +1,13 @@ +plugins { + id 'io.micronaut.build.internal.nats-examples' + id 'org.graalvm.buildtools.native' +} + +tasks.named("check") { task -> + def graal = ["jvmci.Compiler", "java.vendor.version", "java.vendor"].any { + System.getProperty(it)?.toLowerCase(Locale.ENGLISH)?.contains("graal") + } + if (graal) { + task.dependsOn("nativeTest") + } +} diff --git a/buildSrc/src/main/groovy/io.micronaut.build.internal.nats-tests.gradle b/buildSrc/src/main/groovy/io.micronaut.build.internal.nats-tests.gradle deleted file mode 100644 index 01604ca9..00000000 --- a/buildSrc/src/main/groovy/io.micronaut.build.internal.nats-tests.gradle +++ /dev/null @@ -1,3 +0,0 @@ -plugins { - id "io.micronaut.build.internal.nats-base" -} diff --git a/docs-examples/example-groovy/build.gradle b/docs-examples/example-groovy/build.gradle index c9e74ae9..66f6977d 100644 --- a/docs-examples/example-groovy/build.gradle +++ b/docs-examples/example-groovy/build.gradle @@ -1,45 +1,13 @@ plugins { - id "groovy" - id 'io.micronaut.build.internal.nats-tests' -} - -repositories { - mavenCentral() + id 'io.micronaut.build.internal.nats-examples' + id 'groovy' } dependencies { - testImplementation projects.micronautNats - testCompileOnly mn.micronaut.inject.groovy - testImplementation libs.testcontainers.spock - testImplementation mn.micronaut.inject - testImplementation mn.reactor testImplementation mnTest.micronaut.test.spock - testRuntimeOnly libs.junit.jupiter.engine - testRuntimeOnly mn.snakeyaml -} - -test { - useJUnitPlatform() - - jvmArgs '-Duser.country=US' - jvmArgs '-Duser.language=en' - failFast = true } tasks.withType(GroovyCompile) { groovyOptions.forkOptions.jvmArgs.add('-Dgroovy.parameters=true') } - -java { - sourceCompatibility = JavaVersion.toVersion("17") - targetCompatibility = JavaVersion.toVersion("17") -} - -test { - useJUnitPlatform() - testLogging { - showStandardStreams = true - exceptionFormat = 'full' - } -} diff --git a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/AbstractNatsTest.groovy b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/AbstractNatsTest.groovy deleted file mode 100644 index ad32b6f0..00000000 --- a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/AbstractNatsTest.groovy +++ /dev/null @@ -1,46 +0,0 @@ -package io.micronaut.nats - -import io.micronaut.context.ApplicationContext -import org.testcontainers.containers.GenericContainer -import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy -import spock.lang.Specification -import spock.util.concurrent.PollingConditions - -abstract class AbstractNatsTest extends Specification { - - static GenericContainer natsContainer = - new GenericContainer("nats:latest") - .withExposedPorts(4222) - .withCommand("--js") - .waitingFor(new LogMessageWaitStrategy().withRegEx("(?s).*Server is ready.*")) - - static { - natsContainer.start() - } - - protected ApplicationContext applicationContext - protected PollingConditions conditions = new PollingConditions(timeout: 5) - - protected void startContext() { - applicationContext = ApplicationContext.run(configuration, "test") - } - - protected Map getConfiguration() { - ["nats.default.addresses": "nats://localhost:" + natsContainer.getMappedPort(4222), - "spec.name" : getClass().simpleName, - "nats.default.jetstream.streams.events.storage-type": "Memory", - "nats.default.jetstream.streams.events.subjects": ["events.>"], - "nats.default.jetstream.keyvalue.examplebucket.storage-type": "Memory", - "nats.default.jetstream.keyvalue.examplebucket.max-history-per-key": 5, - "nats.default.jetstream.objectstore.examplebucket.storage-type": "Memory", - ] as Map - } - - protected void waitFor(Closure conditionEvaluator) { - conditions.eventually conditionEvaluator - } - - void cleanup() { - applicationContext?.close() - } -} diff --git a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/connection/ConnectionSpec.groovy b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/connection/ConnectionSpec.groovy index 116f83b1..15bd12b7 100644 --- a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/connection/ConnectionSpec.groovy +++ b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/connection/ConnectionSpec.groovy @@ -1,32 +1,51 @@ -package io.micronaut.nats.docs.consumer.connection - -import io.micronaut.nats.AbstractNatsTest - -class ConnectionSpec extends AbstractNatsTest { - - void "test product client and listener"() { - startContext() - - when: -// tag::producer[] - def productClient = applicationContext.getBean(ProductClient) - productClient.send("connection-test".bytes) -// end::producer[] - - ProductListener productListener = applicationContext.getBean(ProductListener) - - then: - waitFor { - productListener.messageLengths.size() == 1 - productListener.messageLengths[0] == "connection-test" - } - - cleanup: - // Finding that the context is closing the channel before ack is sent - sleep 200 - } - - protected Map getConfiguration() { - super.configuration + ["nats.product-cluster.addresses": super.configuration.remove("nats.default.addresses")] - } -} +package io.micronaut.nats.docs.consumer.connection + +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import io.micronaut.test.support.TestPropertyProvider +import io.micronaut.testresources.client.TestResourcesClientFactory +import jakarta.inject.Inject +import spock.lang.Specification + +import static java.util.concurrent.TimeUnit.SECONDS +import static org.awaitility.Awaitility.await + +@MicronautTest +@Property(name = "spec.name", value = "ConnectionSpec") +class ConnectionSpec extends Specification implements TestPropertyProvider { + @Inject ProductClient productClient + @Inject ProductListener productListener + + void "test product client and listener"() { + when: +// tag::producer[] + productClient.send("connection-test".bytes) +// end::producer[] + + then: + await().atMost(10, SECONDS).until { + productListener.messageLengths.size() == 1 + productListener.messageLengths[0] == "connection-test" + } + + cleanup: + // Finding that the context is closing the channel before ack is sent + sleep 200 + } + + @Override + Map getProperties() { + var client = TestResourcesClientFactory.fromSystemProperties().get() + var natsPort = client.resolve("nats.port", Map.of(), Map.of( + "containers.nats.startup-timeout", "600s", + "containers.nats.image-name", "nats:latest", + "containers.nats.exposed-ports[0].nats.port", 4222, + "containers.nats.exposed-ports", List.of(Map.of("nats.port", 4222)), + "containers.nats.command", "--js", + "containers.nats.wait-strategy.log.regex", ".*Server is ready.*" + )) + return natsPort + .map(port -> Map.of("nats.product-cluster.addresses[0]", "nats://localhost:$port")) + .orElse(Collections.emptyMap()) + } +} diff --git a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/custom/annotation/SIDSpec.groovy b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/custom/annotation/SIDSpec.groovy index e6d4eba2..75385bf9 100644 --- a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/custom/annotation/SIDSpec.groovy +++ b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/custom/annotation/SIDSpec.groovy @@ -1,28 +1,34 @@ -package io.micronaut.nats.docs.consumer.custom.annotation - -import io.micronaut.nats.AbstractNatsTest - -class SIDSpec extends AbstractNatsTest { - - void "test using a custom annotation binder"() { - startContext() - - when: -// tag::producer[] -def productClient = applicationContext.getBean(ProductClient) -productClient.send("body".getBytes()) -productClient.send("body2".getBytes()) -productClient.send("body3".getBytes()) -// end::producer[] - - ProductListener productListener = applicationContext.getBean(ProductListener) - - then: - waitFor { - productListener.messages.size() == 3 - } - - cleanup: - sleep 200 - } -} +package io.micronaut.nats.docs.consumer.custom.annotation + +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import jakarta.inject.Inject +import spock.lang.Specification + +import static java.util.concurrent.TimeUnit.SECONDS +import static org.awaitility.Awaitility.await + +@MicronautTest +@Property(name = "spec.name", value = "SIDSpec") +class SIDSpec extends Specification { + @Inject ProductClient productClient + @Inject ProductListener productListener + + + void "test using a custom annotation binder"() { + when: +// tag::producer[] +productClient.send("body".getBytes()) +productClient.send("body2".getBytes()) +productClient.send("body3".getBytes()) +// end::producer[] + + then: + await().atMost(10, SECONDS).until { + productListener.messages.size() == 3 + } + + cleanup: + sleep 200 + } +} diff --git a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/custom/type/ProductInfoSpec.groovy b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/custom/type/ProductInfoSpec.groovy index 4dc90efd..12224b3a 100644 --- a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/custom/type/ProductInfoSpec.groovy +++ b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/custom/type/ProductInfoSpec.groovy @@ -1,37 +1,43 @@ -package io.micronaut.nats.docs.consumer.custom.type - -import io.micronaut.nats.AbstractNatsTest - -class ProductInfoSpec extends AbstractNatsTest { - - void "test using a custom type binder"() { - startContext() - - when: -// tag::producer[] - ProductClient productClient = applicationContext.getBean(ProductClient) - productClient.send("body".bytes) - productClient.send("medium", 20L, "body2".bytes) - productClient.send(null, 30L, "body3".bytes) -// end::producer[] - - ProductListener productListener = applicationContext.getBean(ProductListener) - - then: - waitFor { - productListener.messages.size() == 3 - - productListener.messages.find({ pi -> - pi.size == "small" && pi.count == 10 && pi.sealed - }) != null - - productListener.messages.find({ pi -> - pi.size == "medium" && pi.count == 20 && pi.sealed - }) != null - - productListener.messages.find({ pi -> - pi.size == null && pi.count == 30 && pi.sealed - }) != null - } - } -} +package io.micronaut.nats.docs.consumer.custom.type + +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import jakarta.inject.Inject +import spock.lang.Specification + +import static java.util.concurrent.TimeUnit.SECONDS +import static org.awaitility.Awaitility.await + +@MicronautTest +@Property(name = "spec.name", value = "ProductInfoSpec") +class ProductInfoSpec extends Specification { + @Inject ProductClient productClient + @Inject ProductListener productListener + + + void "test using a custom type binder"() { + when: +// tag::producer[] + productClient.send("body".bytes) + productClient.send("medium", 20L, "body2".bytes) + productClient.send(null, 30L, "body3".bytes) +// end::producer[] + + then: + await().atMost(10, SECONDS).until { + productListener.messages.size() == 3 + + productListener.messages.find({ pi -> + pi.size == "small" && pi.count == 10 && pi.sealed + }) != null + + productListener.messages.find({ pi -> + pi.size == "medium" && pi.count == 20 && pi.sealed + }) != null + + productListener.messages.find({ pi -> + pi.size == null && pi.count == 30 && pi.sealed + }) != null + } + } +} diff --git a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/queue/QueueSpec.groovy b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/queue/QueueSpec.groovy index 14051e99..3f978c4f 100644 --- a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/queue/QueueSpec.groovy +++ b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/queue/QueueSpec.groovy @@ -1,28 +1,34 @@ -package io.micronaut.nats.docs.consumer.queue - -import io.micronaut.nats.AbstractNatsTest - -class QueueSpec extends AbstractNatsTest { - - void "test product client and listener"() { - startContext() - - when: -// tag::producer[] -def productClient = applicationContext.getBean(ProductClient) -productClient.send("quickstart".bytes) -// end::producer[] - - io.micronaut.nats.docs.consumer.queue.ProductListener productListener = applicationContext.getBean(io.micronaut.nats.docs.consumer.queue.ProductListener) - - then: - waitFor { - productListener.messageLengths.size() == 1 - productListener.messageLengths[0] == "quickstart" - } - - cleanup: - // Finding that the context is closing the channel before ack is sent - sleep 200 - } -} +package io.micronaut.nats.docs.consumer.queue + +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import jakarta.inject.Inject +import spock.lang.Specification + +import static java.util.concurrent.TimeUnit.SECONDS +import static org.awaitility.Awaitility.await + +@MicronautTest +@Property(name = "spec.name", value = "QueueSpec") +class QueueSpec extends Specification { + @Inject ProductClient productClient + @Inject ProductListener productListener + + void "test product client and listener"() { + + when: +// tag::producer[] +productClient.send("quickstart".bytes) +// end::producer[] + + then: + await().atMost(10, SECONDS).until { + productListener.messageLengths.size() == 1 + productListener.messageLengths[0] == "quickstart" + } + + cleanup: + // Finding that the context is closing the channel before ack is sent + sleep 200 + } +} diff --git a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/types/TypeBindingSpec.groovy b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/types/TypeBindingSpec.groovy index 392adf31..2c2ff9ae 100644 --- a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/types/TypeBindingSpec.groovy +++ b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/consumer/types/TypeBindingSpec.groovy @@ -1,28 +1,36 @@ -package io.micronaut.nats.docs.consumer.types - -import io.micronaut.nats.AbstractNatsTest - -class TypeBindingSpec extends AbstractNatsTest { - - void "test publishing and receiving nats types"() { - startContext() - - when: -// tag::producer[] - ProductClient productClient = applicationContext.getBean(ProductClient) - productClient.send("body".bytes, 20L) - productClient.send("body2".bytes, 30L) - productClient.send("body3".bytes, 40L) -// end::producer[] - - ProductListener productListener = applicationContext.getBean(ProductListener) - - then: - waitFor { - productListener.messages.size() == 3 - productListener.messages.contains("subject: [product], maxPayload: [1048576], pendingMessageCount: [0], x-productCount: [20]") - productListener.messages.contains("subject: [product], maxPayload: [1048576], pendingMessageCount: [0], x-productCount: [30]") - productListener.messages.contains("subject: [product], maxPayload: [1048576], pendingMessageCount: [0], x-productCount: [40]") - } - } -} +package io.micronaut.nats.docs.consumer.types + +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import jakarta.inject.Inject +import spock.lang.Specification + +import static java.util.concurrent.TimeUnit.SECONDS +import static org.awaitility.Awaitility.await + +@MicronautTest +@Property(name = "spec.name", value = "TypeBindingSpec") +class TypeBindingSpec extends Specification { + @Inject ProductClient productClient + @Inject ProductListener productListener + + + void "test publishing and receiving nats types"() { + + when: +// tag::producer[] + productClient.send("body".bytes, 20L) + productClient.send("body2".bytes, 30L) + productClient.send("body3".bytes, 40L) +// end::producer[] + + + then: + await().atMost(10, SECONDS).until { + productListener.messages.size() == 3 + productListener.messages.contains("subject: [product], maxPayload: [1048576], pendingMessageCount: [0], x-productCount: [20]") + productListener.messages.contains("subject: [product], maxPayload: [1048576], pendingMessageCount: [0], x-productCount: [30]") + productListener.messages.contains("subject: [product], maxPayload: [1048576], pendingMessageCount: [0], x-productCount: [40]") + } + } +} diff --git a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/headers/HeadersSpec.groovy b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/headers/HeadersSpec.groovy index a5e8c5ea..2b8945e5 100644 --- a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/headers/HeadersSpec.groovy +++ b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/headers/HeadersSpec.groovy @@ -1,37 +1,44 @@ -package io.micronaut.nats.docs.headers - -import io.micronaut.nats.AbstractNatsTest -import io.nats.client.impl.Headers - -class HeadersSpec extends AbstractNatsTest { - - void "test publishing and receiving headers"() { - when: - startContext() -// tag::producer[] - ProductClient productClient = applicationContext.getBean(ProductClient) - productClient.send("body".bytes) - productClient.send("medium", 20L, "body2".bytes) - productClient.send(null, 30L, "body3".bytes) - - Headers headers = new Headers() - headers.put("productSize", "large") - headers.put("x-product-count", "40") - productClient.send("body4".getBytes(), headers) - productClient.send("body5".getBytes(), Arrays.asList("xtra-small", "xtra-large")) -// end::producer[] - - ProductListener productListener = applicationContext.getBean(ProductListener) - - then: - waitFor { - productListener.messageProperties.size() == 6 - productListener.messageProperties.contains("true|10|small") - productListener.messageProperties.contains("true|20|medium") - productListener.messageProperties.contains("true|30|null") - productListener.messageProperties.contains("true|40|large") - productListener.messageProperties.contains("true|20|xtra-small") - productListener.messageProperties.contains("true|20|xtra-large") - } - } -} +package io.micronaut.nats.docs.headers + +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import io.nats.client.impl.Headers +import jakarta.inject.Inject +import spock.lang.Specification + +import static java.util.concurrent.TimeUnit.SECONDS +import static org.awaitility.Awaitility.await + +@MicronautTest +@Property(name = "spec.name", value = "HeadersSpec") +class HeadersSpec extends Specification { + @Inject ProductClient productClient + @Inject ProductListener productListener + + void "test publishing and receiving headers"() { + when: +// tag::producer[] + productClient.send("body".bytes) + productClient.send("medium", 20L, "body2".bytes) + productClient.send(null, 30L, "body3".bytes) + + Headers headers = new Headers() + headers.put("productSize", "large") + headers.put("x-product-count", "40") + productClient.send("body4".getBytes(), headers) + productClient.send("body5".getBytes(), Arrays.asList("xtra-small", "xtra-large")) +// end::producer[] + + + then: + await().atMost(10, SECONDS).until { + productListener.messageProperties.size() == 6 + productListener.messageProperties.contains("true|10|small") + productListener.messageProperties.contains("true|20|medium") + productListener.messageProperties.contains("true|30|null") + productListener.messageProperties.contains("true|40|large") + productListener.messageProperties.contains("true|20|xtra-small") + productListener.messageProperties.contains("true|20|xtra-large") + } + } +} diff --git a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/jetstream/JetstreamSpec.groovy b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/jetstream/JetstreamSpec.groovy index 78a29c05..81cb5332 100644 --- a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/jetstream/JetstreamSpec.groovy +++ b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/jetstream/JetstreamSpec.groovy @@ -1,20 +1,31 @@ package io.micronaut.nats.docs.jetstream -import io.micronaut.nats.AbstractNatsTest +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.spock.annotation.MicronautTest import io.nats.client.JetStreamManagement import io.nats.client.PublishOptions import io.nats.client.api.PublishAck +import jakarta.inject.Inject +import spock.lang.Specification import java.nio.charset.StandardCharsets -class JetstreamSpec extends AbstractNatsTest { +import static java.util.concurrent.TimeUnit.SECONDS +import static org.awaitility.Awaitility.await + +@MicronautTest +@Property(name = "spec.name", value = "JetstreamSpec") +class JetstreamSpec extends Specification { + @Inject ProductClient productClient + @Inject ProductListener productListener + @Inject JetStreamManagement jsm + @Inject PullConsumerHelper pullConsumerHelper + void "simple producer"() { - startContext() when: // tag::producer[] - def productClient = applicationContext.getBean(ProductClient) PublishAck pa = productClient.send("events.one", "ghi".getBytes(StandardCharsets.UTF_8), PublishOptions.builder() .stream("events") @@ -31,24 +42,16 @@ class JetstreamSpec extends AbstractNatsTest { .build()) // end::producer[] - ProductListener productListener = applicationContext.getBean(ProductListener) - JetStreamManagement jsm = applicationContext.getBean(JetStreamManagement) - then: - waitFor { + await().atMost(10, SECONDS).until { productListener.messageLengths.size() == 2 jsm.getStreamInfo("events").getStreamState().getMsgCount() == 2 } - - cleanup: - jsm.deleteStream("events") } void "pull consumer"() { - startContext() when: - def productClient = applicationContext.getBean(ProductClient) PublishAck pa = productClient.send("events.three", "ghi".getBytes(StandardCharsets.UTF_8), PublishOptions.builder() .stream("events") @@ -64,15 +67,10 @@ class JetstreamSpec extends AbstractNatsTest { .expectedLastSequence(pa.getSeqno()) .build()) - PullConsumerHelper pullConsumerHelper = applicationContext.getBean(PullConsumerHelper) - then: - waitFor { + await().atMost(10, SECONDS).until { pullConsumerHelper.pullMessages().size() == 2 } - cleanup: - JetStreamManagement jsm = applicationContext.getBean(JetStreamManagement) - jsm.deleteStream("events") } } diff --git a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/jetstream/kv/KeyValueSpec.groovy b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/jetstream/kv/KeyValueSpec.groovy index f956b5e3..1108cd03 100644 --- a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/jetstream/kv/KeyValueSpec.groovy +++ b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/jetstream/kv/KeyValueSpec.groovy @@ -1,14 +1,17 @@ package io.micronaut.nats.docs.jetstream.kv -import io.micronaut.nats.AbstractNatsTest +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import jakarta.inject.Inject +import spock.lang.Specification -class KeyValueSpec extends AbstractNatsTest { +@MicronautTest +@Property(name = "spec.name", value = "KeyValueSpec") +class KeyValueSpec extends Specification { + @Inject KeyValueStoreHolder keyValueStoreHolder void "simple producer"() { - startContext() - when: - def keyValueStoreHolder = applicationContext.getBean(KeyValueStoreHolder) keyValueStoreHolder.put("test", "myvalue") then: diff --git a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/jetstream/os/ObjectStoreSpec.groovy b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/jetstream/os/ObjectStoreSpec.groovy index 94036b5b..44ff8ae2 100644 --- a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/jetstream/os/ObjectStoreSpec.groovy +++ b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/jetstream/os/ObjectStoreSpec.groovy @@ -1,14 +1,18 @@ package io.micronaut.nats.docs.jetstream.os -import io.micronaut.nats.AbstractNatsTest +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import jakarta.inject.Inject +import spock.lang.Specification -class ObjectStoreSpec extends AbstractNatsTest { +@MicronautTest +@Property(name = "spec.name", value = "ObjectStoreSpec") +class ObjectStoreSpec extends Specification { + @Inject ObjectStoreHolder objectStoreHolder void "simple producer"() { - startContext() when: - def objectStoreHolder = applicationContext.getBean(ObjectStoreHolder) objectStoreHolder.put("test", new ByteArrayInputStream("myvalue".getBytes())) then: diff --git a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/parameters/BindingSpec.groovy b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/parameters/BindingSpec.groovy index 331adb5c..51721e59 100644 --- a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/parameters/BindingSpec.groovy +++ b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/parameters/BindingSpec.groovy @@ -1,26 +1,32 @@ -package io.micronaut.nats.docs.parameters - -import io.micronaut.nats.AbstractNatsTest - -class BindingSpec extends AbstractNatsTest { - - void "test dynamic binding"() { - startContext() - - when: -// tag::producer[] - def productClient = applicationContext.getBean(ProductClient) - productClient.send("message body".bytes) - productClient.send("product", "message body2".bytes) -// end::producer[] - - ProductListener productListener = applicationContext.getBean(ProductListener) - - then: - waitFor { - productListener.messageLengths.size() == 2 - productListener.messageLengths.contains(12) - productListener.messageLengths.contains(13) - } - } -} +package io.micronaut.nats.docs.parameters + +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import jakarta.inject.Inject +import spock.lang.Specification + +import static java.util.concurrent.TimeUnit.SECONDS +import static org.awaitility.Awaitility.await + +@MicronautTest +@Property(name = "spec.name", value = "BindingSpec") +class BindingSpec extends Specification { + @Inject ProductClient productClient + @Inject ProductListener productListener + + void "test dynamic binding"() { + + when: +// tag::producer[] + productClient.send("message body".bytes) + productClient.send("product", "message body2".bytes) +// end::producer[] + + then: + await().atMost(10, SECONDS).until { + productListener.messageLengths.size() == 2 + productListener.messageLengths.contains(12) + productListener.messageLengths.contains(13) + } + } +} diff --git a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/quickstart/QuickstartSpec.groovy b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/quickstart/QuickstartSpec.groovy index 8cf1c297..d19be820 100644 --- a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/quickstart/QuickstartSpec.groovy +++ b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/quickstart/QuickstartSpec.groovy @@ -1,28 +1,34 @@ -package io.micronaut.nats.docs.quickstart - -import io.micronaut.nats.AbstractNatsTest - -class QuickstartSpec extends AbstractNatsTest { - - void "test product client and listener"() { - startContext() - - when: -// tag::producer[] -def productClient = applicationContext.getBean(ProductClient) -productClient.send("quickstart".bytes) -// end::producer[] - - ProductListener productListener = applicationContext.getBean(ProductListener) - - then: - waitFor { - productListener.messageLengths.size() == 1 - productListener.messageLengths[0] == "quickstart" - } - - cleanup: - // Finding that the context is closing the channel before ack is sent - sleep 200 - } -} +package io.micronaut.nats.docs.quickstart + +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import jakarta.inject.Inject +import spock.lang.Specification + +import static java.util.concurrent.TimeUnit.SECONDS +import static org.awaitility.Awaitility.await + +@MicronautTest +@Property(name = "spec.name", value = "QuickstartSpec") +class QuickstartSpec extends Specification { + @Inject ProductClient productClient + @Inject ProductListener productListener + + void "test product client and listener"() { + + when: +// tag::producer[] +productClient.send("quickstart".bytes) +// end::producer[] + + then: + await().atMost(10, SECONDS).until { + productListener.messageLengths.size() == 1 + productListener.messageLengths[0] == "quickstart" + } + + cleanup: + // Finding that the context is closing the channel before ack is sent + sleep 200 + } +} diff --git a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/rpc/RpcUppercaseSpec.groovy b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/rpc/RpcUppercaseSpec.groovy index c0d7da9a..cd06765f 100644 --- a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/rpc/RpcUppercaseSpec.groovy +++ b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/rpc/RpcUppercaseSpec.groovy @@ -1,20 +1,24 @@ -package io.micronaut.nats.docs.rpc - -import io.micronaut.nats.AbstractNatsTest -import reactor.core.publisher.Mono - -class RpcUppercaseSpec extends AbstractNatsTest { - - void "test product client and listener"() { - startContext() - - when: -// tag::producer[] - def productClient = applicationContext.getBean(ProductClient) - - then: - productClient.send("hello") == "HELLO" - Mono.from(productClient.sendReactive("world")).block() == "WORLD" -// end::producer[] - } -} +package io.micronaut.nats.docs.rpc + +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import jakarta.inject.Inject +import reactor.core.publisher.Mono +import spock.lang.Specification + +@MicronautTest +@Property(name = "spec.name", value = "RpcUppercaseSpec") +class RpcUppercaseSpec extends Specification { + @Inject ProductClient productClient + + void "test product client and listener"() { + when: + // tag::producer[] + productClient.send("hello") == "HELLO" + + then: + + Mono.from(productClient.sendReactive("world")).block() == "WORLD" + // end::producer[] + } +} diff --git a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/serdes/ProductInfoSerDesSpec.groovy b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/serdes/ProductInfoSerDesSpec.groovy index 7906aab5..3eb2ea7c 100644 --- a/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/serdes/ProductInfoSerDesSpec.groovy +++ b/docs-examples/example-groovy/src/test/groovy/io/micronaut/nats/docs/serdes/ProductInfoSerDesSpec.groovy @@ -1,28 +1,34 @@ -package io.micronaut.nats.docs.serdes - -import io.micronaut.nats.AbstractNatsTest - -class ProductInfoSerDesSpec extends AbstractNatsTest { - - void "test using a custom serdes"() { - startContext() - - when: -// tag::producer[] - ProductClient productClient = applicationContext.getBean(ProductClient) - productClient.send(new ProductInfo("small", 10L, true)) - productClient.send(new ProductInfo("medium", 20L, true)) - productClient.send(new ProductInfo(null, 30L, false)) -// end::producer[] - - ProductListener listener = applicationContext.getBean(ProductListener) - - then: - waitFor { - listener.messages.size() == 3 - listener.messages.find({ p -> p.size == "small" && p.count == 10L && p.sealed }) != null - listener.messages.find({ p -> p.size == "medium" && p.count == 20L && p.sealed }) != null - listener.messages.find({ p -> p.size == null && p.count == 30L && !p.sealed }) != null - } - } -} +package io.micronaut.nats.docs.serdes + +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import jakarta.inject.Inject +import spock.lang.Specification + +import static java.util.concurrent.TimeUnit.SECONDS +import static org.awaitility.Awaitility.await + +@MicronautTest +@Property(name = "spec.name", value = "ProductInfoSerDesSpec") +class ProductInfoSerDesSpec extends Specification { + @Inject ProductClient productClient + @Inject ProductListener listener + + + void "test using a custom serdes"() { + when: +// tag::producer[] + productClient.send(new ProductInfo("small", 10L, true)) + productClient.send(new ProductInfo("medium", 20L, true)) + productClient.send(new ProductInfo(null, 30L, false)) +// end::producer[] + + then: + await().atMost(10, SECONDS).until { + listener.messages.size() == 3 + listener.messages.find({ p -> p.size == "small" && p.count == 10L && p.sealed }) != null + listener.messages.find({ p -> p.size == "medium" && p.count == 20L && p.sealed }) != null + listener.messages.find({ p -> p.size == null && p.count == 30L && !p.sealed }) != null + } + } +} diff --git a/docs-examples/example-groovy/src/test/resources/application-test.yml b/docs-examples/example-groovy/src/test/resources/application-test.yml deleted file mode 100644 index 7ea434ba..00000000 --- a/docs-examples/example-groovy/src/test/resources/application-test.yml +++ /dev/null @@ -1,12 +0,0 @@ -micronaut: - application: - name: test-application - -nats: - default: - jetstream: - streams: - events: - storage-type: Memory - subjects: - - events.> diff --git a/docs-examples/example-groovy/src/test/resources/application.yml b/docs-examples/example-groovy/src/test/resources/application.yml new file mode 100644 index 00000000..3cc48f2c --- /dev/null +++ b/docs-examples/example-groovy/src/test/resources/application.yml @@ -0,0 +1,33 @@ +micronaut: + application: + name: test-application + +nats: + default: + addresses: + - nats://localhost:${nats.port} + jetstream: + streams: + events: + storage-type: Memory + subjects: + - events.> + keyvalue: + examplebucket: + storage-type: Memory + max-history-per-key: 5 + objectstore: + examplebucket: + storage-type: Memory + +test-resources: + containers: + nats: + startup-timeout: 600s + image-name: nats:latest + exposed-ports: + - nats.port: 4222 + command: "--js" + wait-strategy: + log: + regex: ".*Server is ready.*" diff --git a/docs-examples/example-java/build.gradle b/docs-examples/example-java/build.gradle index 30034cdb..58c88c0e 100644 --- a/docs-examples/example-java/build.gradle +++ b/docs-examples/example-java/build.gradle @@ -1,32 +1,3 @@ plugins { - id "java-library" - id 'io.micronaut.build.internal.nats-tests' -} - -dependencies { - testImplementation projects.micronautNats - - testAnnotationProcessor mn.micronaut.inject.java - - testImplementation mn.reactor - testImplementation libs.awaitility - testImplementation libs.testcontainers - testImplementation libs.junit.jupiter.api - testRuntimeOnly libs.junit.jupiter.engine - testRuntimeOnly mn.snakeyaml -} - -compileJava.options.compilerArgs += '-parameters' -compileTestJava.options.compilerArgs += '-parameters' - -java { - sourceCompatibility = JavaVersion.toVersion("17") - targetCompatibility = JavaVersion.toVersion("17") -} -test { - useJUnitPlatform() - - jvmArgs '-Duser.country=US' - jvmArgs '-Duser.language=en' - failFast = true + id 'io.micronaut.build.internal.nats-native-tests' } diff --git a/docs-examples/example-java/src/test/java/io/micronaut/nats/AbstractNatsTest.java b/docs-examples/example-java/src/test/java/io/micronaut/nats/AbstractNatsTest.java deleted file mode 100644 index 8adc21df..00000000 --- a/docs-examples/example-java/src/test/java/io/micronaut/nats/AbstractNatsTest.java +++ /dev/null @@ -1,56 +0,0 @@ -package io.micronaut.nats; - -import io.micronaut.context.ApplicationContext; -import org.junit.jupiter.api.AfterEach; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Callable; - -import static java.util.concurrent.TimeUnit.SECONDS; -import static org.awaitility.Awaitility.await; - -public abstract class AbstractNatsTest { - - protected static GenericContainer natsContainer = new GenericContainer<>("nats:latest") - .withExposedPorts(4222) - .withCommand("--js") - .waitingFor(new LogMessageWaitStrategy().withRegEx("(?s).*Server is ready.*")); - - static { - natsContainer.start(); - } - - protected ApplicationContext applicationContext; - - protected void startContext() { - applicationContext = ApplicationContext.run(getConfiguration(), "test"); - } - - protected Map getConfiguration() { - Map config = new HashMap<>(); - config.put("nats.default.addresses", - "nats://localhost:" + natsContainer.getMappedPort(4222)); - config.put("spec.name", getClass().getSimpleName()); - config.put("nats.default.jetstream.streams.events.storage-type", "Memory"); - config.put("nats.default.jetstream.streams.events.subjects", List.of("events.>")); - config.put("nats.default.jetstream.keyvalue.examplebucket.storage-type", "Memory"); - config.put("nats.default.jetstream.keyvalue.examplebucket.max-history-per-key", 5); - config.put("nats.default.jetstream.objectstore.examplebucket.storage-type", "Memory"); - return config; - } - - protected void waitFor(Callable conditionEvaluator) { - await().atMost(5, SECONDS).until(conditionEvaluator); - } - - @AfterEach - void cleanup() { - if (applicationContext != null) { - applicationContext.close(); - } - } -} diff --git a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/connection/ConnectionSpec.java b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/connection/ConnectionSpec.java index 0d7b0620..3e43410f 100644 --- a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/connection/ConnectionSpec.java +++ b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/connection/ConnectionSpec.java @@ -1,34 +1,50 @@ package io.micronaut.nats.docs.consumer.connection; -import io.micronaut.nats.AbstractNatsTest; +import io.micronaut.context.annotation.Property; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import io.micronaut.test.support.TestPropertyProvider; +import io.micronaut.testresources.client.TestResourcesClientFactory; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import java.util.Collections; +import java.util.List; import java.util.Map; -class ConnectionSpec extends AbstractNatsTest { +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; - @Test - void testProductClientAndListener() { - startContext(); +@MicronautTest +@Property(name = "spec.name", value = "ConnectionSpec") +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class ConnectionSpec implements TestPropertyProvider { -// tag::producer[] -ProductClient productClient = applicationContext.getBean(ProductClient.class); -productClient.send("connection-test".getBytes()); -// end::producer[] + @Test + void testProductClientAndListener(ProductClient productClient, ProductListener productListener) { - ProductListener productListener = applicationContext.getBean(ProductListener.class); + // tag::producer[] + productClient.send("connection-test".getBytes()); + // end::producer[] - waitFor(() -> + await().atMost(10, SECONDS).until(() -> productListener.messageLengths.size() == 1 && productListener.messageLengths.get(0).equals("connection-test") ); } @Override - protected Map getConfiguration() { - Map configuration = super.getConfiguration(); - configuration.put("nats.product-cluster.addresses", - configuration.remove("nats.default.addresses")); - return configuration; + public Map getProperties() { + var client = TestResourcesClientFactory.fromSystemProperties().get(); + var natsPort = client.resolve("nats.port", Map.of(), Map.of( + "containers.nats.startup-timeout", "600s", + "containers.nats.image-name", "nats:latest", + "containers.nats.exposed-ports[0].nats.port", 4222, + "containers.nats.exposed-ports", List.of(Map.of("nats.port", 4222)), + "containers.nats.command", "--js", + "containers.nats.wait-strategy.log.regex", ".*Server is ready.*" + )); + return natsPort + .map(port -> Map.of("nats.product-cluster.addresses[0]", "nats://localhost:" + port)) + .orElse(Collections.emptyMap()); } } diff --git a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/custom/annotation/SIDSpec.java b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/custom/annotation/SIDSpec.java index d09c417b..01fac2c3 100644 --- a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/custom/annotation/SIDSpec.java +++ b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/custom/annotation/SIDSpec.java @@ -1,23 +1,24 @@ package io.micronaut.nats.docs.consumer.custom.annotation; -import io.micronaut.nats.AbstractNatsTest; +import io.micronaut.context.annotation.Property; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; import org.junit.jupiter.api.Test; -class SIDSpec extends AbstractNatsTest { +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; - @Test - void testUsingACustomAnnotationBinder() { - startContext(); +@MicronautTest +@Property(name = "spec.name", value = "SIDSpec") +class SIDSpec { + @Test + void testUsingACustomAnnotationBinder(ProductClient productClient, ProductListener productListener) { // tag::producer[] - ProductClient productClient = applicationContext.getBean(ProductClient.class); productClient.send("body".getBytes()); productClient.send("body2".getBytes()); productClient.send("body3".getBytes()); // end::producer[] - ProductListener productListener = applicationContext.getBean(ProductListener.class); - - waitFor(() -> productListener.messages.size() == 3); + await().atMost(60, SECONDS).until(() -> productListener.messages.size() == 3); } } diff --git a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/custom/type/ProductInfoSpec.java b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/custom/type/ProductInfoSpec.java index be2ba868..418d1d92 100644 --- a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/custom/type/ProductInfoSpec.java +++ b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/custom/type/ProductInfoSpec.java @@ -1,24 +1,27 @@ package io.micronaut.nats.docs.consumer.custom.type; -import io.micronaut.nats.AbstractNatsTest; +import io.micronaut.context.annotation.Property; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; import org.junit.jupiter.api.Test; -class ProductInfoSpec extends AbstractNatsTest { +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; + +@MicronautTest +@Property(name = "spec.name", value = "ProductInfoSpec") +class ProductInfoSpec { @Test - void testUsingACustomTypeBinder() { - startContext(); + void testUsingACustomTypeBinder(ProductClient productClient, ProductListener productListener) { // tag::producer[] - ProductClient productClient = applicationContext.getBean(ProductClient.class); productClient.send("body".getBytes()); productClient.send("medium", 20L, "body2".getBytes()); productClient.send(null, 30L, "body3".getBytes()); // end::producer[] - ProductListener productListener = applicationContext.getBean(ProductListener.class); - waitFor(() -> + await().atMost(60, SECONDS).until(() -> productListener.messages.size() == 3 && productListener.messages.stream().anyMatch(pi -> pi.getCount() == 10L) && productListener.messages.stream().anyMatch(pi -> pi.getCount() == 20L) && diff --git a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/queue/QueueSpec.java b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/queue/QueueSpec.java index 66dad646..5b1f47e3 100644 --- a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/queue/QueueSpec.java +++ b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/queue/QueueSpec.java @@ -1,23 +1,24 @@ package io.micronaut.nats.docs.consumer.queue; -import io.micronaut.nats.AbstractNatsTest; +import io.micronaut.context.annotation.Property; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; import org.junit.jupiter.api.Test; -class QueueSpec extends AbstractNatsTest { +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; - @Test - void testProductClientAndListener() { - startContext(); - -// tag::producer[] -ProductClient productClient = applicationContext.getBean(ProductClient.class); -productClient.send("queue-test".getBytes()); -// end::producer[] +@MicronautTest +@Property(name = "spec.name", value = "QueueSpec") +class QueueSpec { - ProductListener productListener = applicationContext.getBean(ProductListener.class); + @Test + void testProductClientAndListener(ProductClient productClient, ProductListener productListener) { + // tag::producer[] + productClient.send("queue-test".getBytes()); + // end::producer[] - waitFor(() -> - productListener.messageLengths.size() == 1 && + await().atMost(60, SECONDS).until(() -> + productListener.messageLengths.size() == 1 && productListener.messageLengths.get(0).equals("queue-test") ); } diff --git a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/types/TypeBindingSpec.java b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/types/TypeBindingSpec.java index 5e71ec01..6a814548 100644 --- a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/types/TypeBindingSpec.java +++ b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/consumer/types/TypeBindingSpec.java @@ -1,24 +1,26 @@ package io.micronaut.nats.docs.consumer.types; -import io.micronaut.nats.AbstractNatsTest; +import io.micronaut.context.annotation.Property; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; import org.junit.jupiter.api.Test; -class TypeBindingSpec extends AbstractNatsTest { +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; + +@MicronautTest +@Property(name = "spec.name", value = "TypeBindingSpec") +class TypeBindingSpec { @Test - void testBindingByType() { - startContext(); + void testBindingByType(ProductClient productClient, ProductListener productListener) { // tag::producer[] - ProductClient productClient = applicationContext.getBean(ProductClient.class); productClient.send("body".getBytes(), 20L); productClient.send("body2".getBytes(), 30L); productClient.send("body3".getBytes(), 40L); // end::producer[] - ProductListener productListener = applicationContext.getBean(ProductListener.class); - - waitFor(() -> + await().atMost(60, SECONDS).until(() -> productListener.messages.size() == 3 && productListener.messages.contains("subject: [product], maxPayload: [1048576], pendingMessageCount: [0], x-productCount: [20]") && productListener.messages.contains("subject: [product], maxPayload: [1048576], pendingMessageCount: [0], x-productCount: [30]") && diff --git a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/headers/HeadersSpec.java b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/headers/HeadersSpec.java index a236e5a8..2beb0777 100644 --- a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/headers/HeadersSpec.java +++ b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/headers/HeadersSpec.java @@ -1,19 +1,22 @@ package io.micronaut.nats.docs.headers; -import io.micronaut.nats.AbstractNatsTest; +import io.micronaut.context.annotation.Property; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; import io.nats.client.impl.Headers; import org.junit.jupiter.api.Test; import java.util.Arrays; -class HeadersSpec extends AbstractNatsTest { +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; - @Test - void testPublishingAndReceivingHeaders() { - startContext(); +@MicronautTest +@Property(name = "spec.name", value = "HeadersSpec") +class HeadersSpec { + @Test + void testPublishingAndReceivingHeaders(ProductClient productClient, ProductListener productListener) { // tag::producer[] - ProductClient productClient = applicationContext.getBean(ProductClient.class); productClient.send("body".getBytes()); productClient.send("medium", 20L, "body2".getBytes()); productClient.send(null, 30L, "body3".getBytes()); @@ -25,9 +28,7 @@ void testPublishingAndReceivingHeaders() { productClient.send("body5".getBytes(), Arrays.asList("xtra-small", "xtra-large")); // end::producer[] - ProductListener productListener = applicationContext.getBean(ProductListener.class); - - waitFor(() -> + await().atMost(60, SECONDS).until(() -> productListener.messageProperties.size() == 6 && productListener.messageProperties.contains("true|10|small") && productListener.messageProperties.contains("true|20|medium") && diff --git a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/jetstream/JetstreamTest.java b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/jetstream/JetstreamTest.java index d7130314..d3cc9fe1 100644 --- a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/jetstream/JetstreamTest.java +++ b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/jetstream/JetstreamTest.java @@ -1,77 +1,69 @@ package io.micronaut.nats.docs.jetstream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; - -import io.micronaut.nats.AbstractNatsTest; -import io.nats.client.JetStreamApiException; +import io.micronaut.context.annotation.Property; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; import io.nats.client.JetStreamManagement; import io.nats.client.PublishOptions; import io.nats.client.api.PublishAck; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledInNativeImage; + +import java.nio.charset.StandardCharsets; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; -class JetstreamTest extends AbstractNatsTest { +@MicronautTest +@Property(name = "spec.name", value = "JetstreamTest") +@DisabledInNativeImage +class JetstreamTest { @Test - void simplePublisher() throws JetStreamApiException, IOException { - startContext(); + void simplePublisher(ProductClient productClient, ProductListener productListener, JetStreamManagement jsm) { // tag::producer[] - ProductClient productClient = applicationContext.getBean(ProductClient.class); PublishAck pa = productClient.send("events.one", "ghi".getBytes(StandardCharsets.UTF_8), PublishOptions.builder() - .stream("events") - .messageId("id00001") - .expectedStream("events") - .build()); + .stream("events") + .messageId("id00001") + .expectedStream("events") + .build()); productClient.send("events.two", "jkl".getBytes(StandardCharsets.UTF_8), PublishOptions.builder() - .stream("events") - .messageId("id00002") - .expectedStream("events") - .expectedLastMsgId("id00001") - .expectedLastSequence(pa.getSeqno()) - .build()); + .stream("events") + .messageId("id00002") + .expectedStream("events") + .expectedLastMsgId("id00001") + .expectedLastSequence(pa.getSeqno()) + .build()); // end::producer[] - ProductListener productListener = applicationContext.getBean(ProductListener.class); - JetStreamManagement jsm = applicationContext.getBean(JetStreamManagement.class); - waitFor(() -> + await().atMost(60, SECONDS).until(() -> productListener.messageLengths.size() == 2 && jsm.getStreamInfo("events").getStreamState().getMsgCount() == 2 ); - - jsm.deleteStream("events"); } @Test - void pullConsumer() throws JetStreamApiException, IOException { - startContext(); - - ProductClient productClient = applicationContext.getBean(ProductClient.class); + void pullConsumer(ProductClient productClient, PullConsumerHelper pullConsumerHelper) { PublishAck pa = productClient.send("events.three", "ghi".getBytes(StandardCharsets.UTF_8), PublishOptions.builder() - .stream("events") - .messageId("id00001") - .expectedStream("events") - .build()); + .stream("events") + .messageId("id00001") + .expectedStream("events") + .build()); productClient.send("events.four", "jkl".getBytes(StandardCharsets.UTF_8), PublishOptions.builder() - .stream("events") - .messageId("id00002") - .expectedStream("events") - .expectedLastMsgId("id00001") - .expectedLastSequence(pa.getSeqno()) - .build()); + .stream("events") + .messageId("id00002") + .expectedStream("events") + .expectedLastMsgId("id00001") + .expectedLastSequence(pa.getSeqno()) + .build()); - PullConsumerHelper pullConsumerHelper = applicationContext.getBean(PullConsumerHelper.class); - - waitFor(() -> + await().atMost(60, SECONDS).until(() -> pullConsumerHelper.pullMessages().size() == 2 ); - - JetStreamManagement jsm = applicationContext.getBean(JetStreamManagement.class); - jsm.deleteStream("events"); } } diff --git a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/jetstream/kv/KeyValueTest.java b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/jetstream/kv/KeyValueTest.java index e9e74fff..5ed5a730 100644 --- a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/jetstream/kv/KeyValueTest.java +++ b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/jetstream/kv/KeyValueTest.java @@ -1,19 +1,19 @@ package io.micronaut.nats.docs.jetstream.kv; -import io.micronaut.nats.AbstractNatsTest; +import io.micronaut.context.annotation.Property; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; import io.nats.client.JetStreamApiException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.io.IOException; -class KeyValueTest extends AbstractNatsTest { +@MicronautTest +@Property(name = "spec.name", value = "KeyValueTest") +class KeyValueTest { @Test - void simpleTest() throws JetStreamApiException, IOException { - startContext(); - KeyValueStoreHolder keyValueStoreHolder = applicationContext.getBean(KeyValueStoreHolder.class); - + void simpleTest(KeyValueStoreHolder keyValueStoreHolder) throws JetStreamApiException, IOException { keyValueStoreHolder.put("test", "myvalue"); Assertions.assertEquals("myvalue", keyValueStoreHolder.store.get("test").getValueAsString()); diff --git a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/jetstream/os/ObjectStoreTest.java b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/jetstream/os/ObjectStoreTest.java index 36767049..52b32c8d 100644 --- a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/jetstream/os/ObjectStoreTest.java +++ b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/jetstream/os/ObjectStoreTest.java @@ -1,6 +1,7 @@ package io.micronaut.nats.docs.jetstream.os; -import io.micronaut.nats.AbstractNatsTest; +import io.micronaut.context.annotation.Property; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; import io.nats.client.JetStreamApiException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -9,13 +10,12 @@ import java.io.IOException; import java.security.NoSuchAlgorithmException; -class ObjectStoreTest extends AbstractNatsTest { +@MicronautTest +@Property(name = "spec.name", value = "ObjectStoreTest") +class ObjectStoreTest { @Test - void simpleTest() throws JetStreamApiException, IOException, NoSuchAlgorithmException { - startContext(); - ObjectStoreHolder objectStoreHolder = applicationContext.getBean(ObjectStoreHolder.class); - + void simpleTest(ObjectStoreHolder objectStoreHolder) throws JetStreamApiException, IOException, NoSuchAlgorithmException { objectStoreHolder.put("test", new ByteArrayInputStream("myvalue".getBytes())); Assertions.assertNotNull(objectStoreHolder.store.getInfo("test")); diff --git a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/parameters/BindingSpec.java b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/parameters/BindingSpec.java index 8579fdcf..356a039f 100644 --- a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/parameters/BindingSpec.java +++ b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/parameters/BindingSpec.java @@ -1,23 +1,25 @@ package io.micronaut.nats.docs.parameters; -import io.micronaut.nats.AbstractNatsTest; +import io.micronaut.context.annotation.Property; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; import org.junit.jupiter.api.Test; -class BindingSpec extends AbstractNatsTest { +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; + +@MicronautTest +@Property(name = "spec.name", value = "BindingSpec") +class BindingSpec { @Test - void testDynamicBinding() { - startContext(); + void testDynamicBinding(ProductClient productClient, ProductListener productListener) { // tag::producer[] - ProductClient productClient = applicationContext.getBean(ProductClient.class); productClient.send("message body".getBytes()); productClient.send("product", "message body2".getBytes()); // end::producer[] - ProductListener productListener = applicationContext.getBean(ProductListener.class); - - waitFor(() -> + await().atMost(60, SECONDS).until(() -> productListener.messageLengths.size() == 2 && productListener.messageLengths.contains(12) && productListener.messageLengths.contains(13) diff --git a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/quickstart/QuickstartSpec.java b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/quickstart/QuickstartSpec.java index fe4fad9a..648fabf4 100644 --- a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/quickstart/QuickstartSpec.java +++ b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/quickstart/QuickstartSpec.java @@ -1,22 +1,24 @@ package io.micronaut.nats.docs.quickstart; -import io.micronaut.nats.AbstractNatsTest; +import io.micronaut.context.annotation.Property; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; import org.junit.jupiter.api.Test; -class QuickstartSpec extends AbstractNatsTest { +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; + +@MicronautTest +@Property(name = "spec.name", value = "QuickstartSpec") +class QuickstartSpec { @Test - void testProductClientAndListener() { - startContext(); + void testProductClientAndListener(ProductClient productClient, ProductListener productListener) { // tag::producer[] -ProductClient productClient = applicationContext.getBean(ProductClient.class); productClient.send("quickstart".getBytes()); // end::producer[] - ProductListener productListener = applicationContext.getBean(ProductListener.class); - - waitFor(() -> + await().atMost(60, SECONDS).until(() -> productListener.messageLengths.size() == 1 && productListener.messageLengths.get(0).equals("quickstart") ); diff --git a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/rpc/RpcUppercaseSpec.java b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/rpc/RpcUppercaseSpec.java index 3277e5a5..76f3381d 100644 --- a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/rpc/RpcUppercaseSpec.java +++ b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/rpc/RpcUppercaseSpec.java @@ -1,19 +1,20 @@ package io.micronaut.nats.docs.rpc; -import io.micronaut.nats.AbstractNatsTest; +import io.micronaut.context.annotation.Property; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; import org.junit.jupiter.api.Test; import reactor.core.publisher.Mono; import static org.junit.jupiter.api.Assertions.assertEquals; -class RpcUppercaseSpec extends AbstractNatsTest { +@MicronautTest +@Property(name = "spec.name", value = "RpcUppercaseSpec") +class RpcUppercaseSpec { @Test - void testProductClientAndListener() { - startContext(); + void testProductClientAndListener(ProductClient productClient) { // tag::producer[] -ProductClient productClient = applicationContext.getBean(ProductClient.class); assertEquals("RPC", productClient.send("rpc")); assertEquals("HELLO", Mono.from(productClient.sendReactive("hello")).block()); // end::producer[] diff --git a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/serdes/ProductInfoSerDesSpec.java b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/serdes/ProductInfoSerDesSpec.java index 00954d75..db9883d1 100644 --- a/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/serdes/ProductInfoSerDesSpec.java +++ b/docs-examples/example-java/src/test/java/io/micronaut/nats/docs/serdes/ProductInfoSerDesSpec.java @@ -1,24 +1,26 @@ package io.micronaut.nats.docs.serdes; -import io.micronaut.nats.AbstractNatsTest; +import io.micronaut.context.annotation.Property; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; import org.junit.jupiter.api.Test; -class ProductInfoSerDesSpec extends AbstractNatsTest { +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; + +@MicronautTest +@Property(name = "spec.name", value = "ProductInfoSerDesSpec") +class ProductInfoSerDesSpec { @Test - void testUsingACustomSerDes() { - startContext(); + void testUsingACustomSerDes(ProductClient productClient, ProductListener productListener) { // tag::producer[] - ProductClient productClient = applicationContext.getBean(ProductClient.class); productClient.send(new ProductInfo("small", 10L, true)); productClient.send(new ProductInfo("medium", 20L, true)); productClient.send(new ProductInfo(null, 30L, false)); // end::producer[] - ProductListener productListener = applicationContext.getBean(ProductListener.class); - - waitFor(() -> + await().atMost(60, SECONDS).until(() -> productListener.messages.size() == 3 && productListener.messages.stream().anyMatch(pi -> pi.getCount() == 10L) && productListener.messages.stream().anyMatch(pi -> pi.getCount() == 20L) && diff --git a/docs-examples/example-java/src/test/resources/application-test.yml b/docs-examples/example-java/src/test/resources/application-test.yml deleted file mode 100644 index 7ea434ba..00000000 --- a/docs-examples/example-java/src/test/resources/application-test.yml +++ /dev/null @@ -1,12 +0,0 @@ -micronaut: - application: - name: test-application - -nats: - default: - jetstream: - streams: - events: - storage-type: Memory - subjects: - - events.> diff --git a/docs-examples/example-java/src/test/resources/application.yml b/docs-examples/example-java/src/test/resources/application.yml new file mode 100644 index 00000000..3cc48f2c --- /dev/null +++ b/docs-examples/example-java/src/test/resources/application.yml @@ -0,0 +1,33 @@ +micronaut: + application: + name: test-application + +nats: + default: + addresses: + - nats://localhost:${nats.port} + jetstream: + streams: + events: + storage-type: Memory + subjects: + - events.> + keyvalue: + examplebucket: + storage-type: Memory + max-history-per-key: 5 + objectstore: + examplebucket: + storage-type: Memory + +test-resources: + containers: + nats: + startup-timeout: 600s + image-name: nats:latest + exposed-ports: + - nats.port: 4222 + command: "--js" + wait-strategy: + log: + regex: ".*Server is ready.*" diff --git a/docs-examples/example-kotlin/build.gradle b/docs-examples/example-kotlin/build.gradle index 6e1f3fe8..57fcb031 100644 --- a/docs-examples/example-kotlin/build.gradle +++ b/docs-examples/example-kotlin/build.gradle @@ -1,31 +1,10 @@ plugins { - alias libs.plugins.kotlin.jvm - alias libs.plugins.kotlin.kapt - id 'io.micronaut.build.internal.nats-tests' + id 'io.micronaut.build.internal.nats-examples' + id("org.jetbrains.kotlin.jvm") + id("org.jetbrains.kotlin.kapt") + id("org.jetbrains.kotlin.plugin.allopen") } -dependencies { - kaptTest(mn.micronaut.inject.java) - - testImplementation projects.micronautNats - testImplementation mnTest.micronaut.test.kotest5 - testImplementation libs.testcontainers - testImplementation mn.reactor - testRuntimeOnly libs.junit.jupiter.engine - testRuntimeOnly mn.snakeyaml -} - -test { - useJUnitPlatform() - - jvmArgs '-Duser.country=US' - jvmArgs '-Duser.language=en' - failFast = true -} - -compileTestKotlin { - kotlinOptions { - jvmTarget = '17' - javaParameters = true - } +micronaut { + testRuntime "kotest5" } diff --git a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/AbstractNatsTest.kt b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/AbstractNatsTest.kt deleted file mode 100644 index 2ee5e246..00000000 --- a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/AbstractNatsTest.kt +++ /dev/null @@ -1,37 +0,0 @@ -package io.micronaut.nats - -import io.kotest.core.spec.style.BehaviorSpec -import io.micronaut.context.ApplicationContext -import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy - -abstract class AbstractNatsTest(body: BehaviorSpec.() -> Unit) : BehaviorSpec(body) { - - companion object { - val natsContainer = KGenericContainer("nats:latest") - .withExposedPorts(4222) - .withCommand("--js") - .waitingFor(LogMessageWaitStrategy().withRegEx("(?s).*Server is ready.*")) - - init { - natsContainer.start() - } - - fun startContext(specName: String): ApplicationContext = - ApplicationContext.run(getDefaultConfig(specName), "test") - - fun startContext(configuration: Map): ApplicationContext = - ApplicationContext.run(configuration, "test") - - fun getDefaultConfig(specName: String): MutableMap = - mutableMapOf( - "nats.default.addresses" to "nats://localhost:" + natsContainer.getMappedPort(4222), - "spec.name" to specName, - "nats.default.jetstream.streams.events.storage-type" to "Memory", - "nats.default.jetstream.streams.events.subjects" to "events.>", - "nats.default.jetstream.keyvalue.examplebucket.storage-type" to "Memory", - "nats.default.jetstream.keyvalue.examplebucket.max-history-per-key" to 5, - "nats.default.jetstream.objectstore.examplebucket.storage-type" to "Memory" - ) - } - -} diff --git a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/KGenericContainer.kt b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/KGenericContainer.kt deleted file mode 100644 index 192d5fc7..00000000 --- a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/KGenericContainer.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.micronaut.nats - -import org.testcontainers.containers.GenericContainer - -class KGenericContainer(imageName: String) : GenericContainer(imageName) diff --git a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/ProjectConfig.kt b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/ProjectConfig.kt new file mode 100644 index 00000000..68abfdb2 --- /dev/null +++ b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/ProjectConfig.kt @@ -0,0 +1,9 @@ +package io.micronaut.nats.docs + +import io.kotest.core.config.AbstractProjectConfig +import io.micronaut.test.extensions.kotest5.MicronautKotest5Extension + +@Suppress("unused") +object ProjectConfig : AbstractProjectConfig() { + override fun extensions() = listOf(MicronautKotest5Extension) +} diff --git a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/connection/ConnectionSpec.kt b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/connection/ConnectionSpec.kt index 946dd8f8..91e17459 100644 --- a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/connection/ConnectionSpec.kt +++ b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/connection/ConnectionSpec.kt @@ -1,39 +1,55 @@ package io.micronaut.nats.docs.consumer.connection import io.kotest.assertions.timing.eventually +import io.kotest.core.spec.style.AnnotationSpec import io.kotest.matchers.shouldBe -import io.micronaut.nats.AbstractNatsTest -import kotlin.time.Duration +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.kotest5.annotation.MicronautTest +import io.micronaut.test.support.TestPropertyProvider +import io.micronaut.testresources.client.TestResourcesClientFactory +import jakarta.inject.Inject import kotlin.time.Duration.Companion.seconds -import kotlin.time.ExperimentalTime -@OptIn(ExperimentalTime::class) -class ConnectionSpec : AbstractNatsTest({ +@MicronautTest +@Property(name = "spec.name", value = "ConnectionSpec") +class ConnectionSpec : TestPropertyProvider, AnnotationSpec() { + @Inject + lateinit var productClient: ProductClient - val specName = javaClass.simpleName - - given("A basic producer and consumer") { - val config = AbstractNatsTest.getDefaultConfig(specName) - config["nats.product-cluster.addresses"] = config.remove("nats.default.addresses")!! - - val ctx = startContext(config) - - `when`("the message is published") { - val productListener = ctx.getBean(ProductListener::class.java) + @Inject + lateinit var productListener: ProductListener + @Test + suspend fun testBasicProducerAndConsumer() { // tag::producer[] - val productClient = ctx.getBean(ProductClient::class.java) - productClient.send("connection-test".toByteArray()) + productClient.send("connection-test".toByteArray()) // end::producer[] - - then("the message is consumed") { - eventually(10.seconds) { - productListener.messageLengths.size shouldBe 1 - productListener.messageLengths[0] shouldBe "connection-test" - } - } + eventually(10.seconds) { + productListener.messageLengths.size shouldBe 1 + productListener.messageLengths[0] shouldBe "connection-test" } + } - ctx.stop() + override fun getProperties(): MutableMap { + val client = TestResourcesClientFactory.fromSystemProperties().get() + val natsPort = client.resolve( + "nats.port", + mapOf(), + mapOf( + "containers.nats.startup-timeout" to "600s", + "containers.nats.image-name" to "nats:latest", + "containers.nats.exposed-ports[0].nats.port" to 4222, + "containers.nats.exposed-ports" to listOf(mapOf("nats.port" to 4222)), + "containers.nats.command" to "--js", + "containers.nats.wait-strategy.log.regex" to ".*Server is ready.*" + ) + ) + return natsPort + .map { port: String -> + mutableMapOf( + "nats.product-cluster.addresses[0]" to "nats://localhost:$port" + ) + } + .orElse(mutableMapOf()) } -}) +} diff --git a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/custom/annotation/SIDSpec.kt b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/custom/annotation/SIDSpec.kt index c44754ef..a0528afe 100644 --- a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/custom/annotation/SIDSpec.kt +++ b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/custom/annotation/SIDSpec.kt @@ -1,25 +1,20 @@ package io.micronaut.nats.docs.consumer.custom.annotation import io.kotest.assertions.timing.eventually +import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.shouldBe -import io.micronaut.nats.AbstractNatsTest -import kotlin.time.Duration +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.kotest5.annotation.MicronautTest import kotlin.time.Duration.Companion.seconds -import kotlin.time.ExperimentalTime -@OptIn(ExperimentalTime::class) -class SIDSpec : AbstractNatsTest({ - - val specName = javaClass.simpleName +@MicronautTest +@Property(name = "spec.name", value = "SIDSpec") +class SIDSpec(productListener: ProductListener, productClient: ProductClient) : BehaviorSpec({ given("A custom type binder") { - val ctx = startContext(specName) `when`("The messages are published") { - val productListener = ctx.getBean(ProductListener::class.java) - // tag::producer[] - val productClient = ctx.getBean(ProductClient::class.java) productClient.send("body".toByteArray()) productClient.send("body2".toByteArray()) productClient.send("body3".toByteArray()) @@ -31,7 +26,5 @@ class SIDSpec : AbstractNatsTest({ } } } - - ctx.stop() } }) diff --git a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/custom/type/ProductInfoSpec.kt b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/custom/type/ProductInfoSpec.kt index 4d52ebd5..11e343f7 100644 --- a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/custom/type/ProductInfoSpec.kt +++ b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/custom/type/ProductInfoSpec.kt @@ -1,26 +1,21 @@ package io.micronaut.nats.docs.consumer.custom.type import io.kotest.assertions.timing.eventually +import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.collections.shouldExist import io.kotest.matchers.shouldBe -import io.micronaut.nats.AbstractNatsTest -import kotlin.time.Duration +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.kotest5.annotation.MicronautTest import kotlin.time.Duration.Companion.seconds -import kotlin.time.ExperimentalTime -@OptIn(ExperimentalTime::class) -class ProductInfoSpec : AbstractNatsTest({ - - val specName = javaClass.simpleName +@MicronautTest +@Property(name = "spec.name", value = "ProductInfoSpec") +class ProductInfoSpec(productClient: ProductClient, productListener: ProductListener) : BehaviorSpec({ given("A custom type binder") { - val ctx = startContext(specName) - `when`("The messages are published") { - val productListener = ctx.getBean(ProductListener::class.java) // tag::producer[] - val productClient = ctx.getBean(ProductClient::class.java) productClient.send("body".toByteArray()) productClient.send("medium", 20L, "body2".toByteArray()) productClient.send(null, 30L, "body3".toByteArray()) @@ -35,7 +30,5 @@ class ProductInfoSpec : AbstractNatsTest({ } } } - - ctx.stop() } }) diff --git a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/queue/QueueSpec.kt b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/queue/QueueSpec.kt index b8fa5adf..b0532568 100644 --- a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/queue/QueueSpec.kt +++ b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/queue/QueueSpec.kt @@ -1,25 +1,20 @@ package io.micronaut.nats.docs.consumer.queue import io.kotest.assertions.timing.eventually +import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.shouldBe -import io.micronaut.nats.AbstractNatsTest -import kotlin.time.Duration +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.kotest5.annotation.MicronautTest import kotlin.time.Duration.Companion.seconds -import kotlin.time.ExperimentalTime -@OptIn(ExperimentalTime::class) -class QueueSpec : AbstractNatsTest({ - - val specName = javaClass.simpleName +@MicronautTest +@Property(name = "spec.name", value = "QueueSpec") +class QueueSpec(productClient: ProductClient, productListener: ProductListener) : BehaviorSpec({ given("A basic producer and consumer") { - val ctx = startContext(specName) `when`("the message is published") { - val productListener = ctx.getBean(ProductListener::class.java) - // tag::producer[] - val productClient = ctx.getBean(ProductClient::class.java) productClient.send("queue-test".toByteArray()) // end::producer[] @@ -30,8 +25,5 @@ class QueueSpec : AbstractNatsTest({ } } } - - Thread.sleep(1000) - ctx.stop() } }) diff --git a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/types/TypeBindingSpec.kt b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/types/TypeBindingSpec.kt index 10d3d5d7..7f6edb8d 100644 --- a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/types/TypeBindingSpec.kt +++ b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/consumer/types/TypeBindingSpec.kt @@ -1,26 +1,20 @@ package io.micronaut.nats.docs.consumer.types import io.kotest.assertions.timing.eventually +import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.collections.shouldContain import io.kotest.matchers.shouldBe -import io.micronaut.nats.AbstractNatsTest -import kotlin.time.Duration +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.kotest5.annotation.MicronautTest import kotlin.time.Duration.Companion.seconds -import kotlin.time.ExperimentalTime -@OptIn(ExperimentalTime::class) -class TypeBindingSpec : AbstractNatsTest({ - - val specName = javaClass.simpleName +@MicronautTest +@Property(name = "spec.name", value = "TypeBindingSpec") +class TypeBindingSpec(productClient: ProductClient, productListener: ProductListener) : BehaviorSpec({ given("A basic producer and consumer") { - val ctx = startContext(specName) - `when`("the message is published") { - val productListener = ctx.getBean(ProductListener::class.java) - // tag::producer[] - val productClient = ctx.getBean(ProductClient::class.java) productClient.send("body".toByteArray(), 20L); productClient.send("body2".toByteArray(), 30L); productClient.send("body3".toByteArray(), 40L) @@ -35,8 +29,5 @@ class TypeBindingSpec : AbstractNatsTest({ } } } - - Thread.sleep(1000) - ctx.stop() } }) diff --git a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/headers/HeadersSpec.kt b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/headers/HeadersSpec.kt index 080c2ff0..64b04cc3 100644 --- a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/headers/HeadersSpec.kt +++ b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/headers/HeadersSpec.kt @@ -1,27 +1,22 @@ package io.micronaut.nats.docs.headers import io.kotest.assertions.timing.eventually +import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.collections.shouldContain import io.kotest.matchers.shouldBe -import io.micronaut.nats.AbstractNatsTest +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.kotest5.annotation.MicronautTest import io.nats.client.impl.Headers -import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds -import kotlin.time.ExperimentalTime -@OptIn(ExperimentalTime::class) -class HeadersSpec : AbstractNatsTest({ - - val specName = javaClass.simpleName +@MicronautTest +@Property(name = "spec.name", value = "HeadersSpec") +class HeadersSpec(productClient: ProductClient, productListener: ProductListener) : BehaviorSpec({ given("A basic producer and consumer") { - val ctx = startContext(specName) - `when`("The messages are published") { - val productListener = ctx.getBean(ProductListener::class.java) // tag::producer[] - val productClient = ctx.getBean(ProductClient::class.java) productClient.send("body".toByteArray()); productClient.send("medium", 20L, "body2".toByteArray()); productClient.send(null, 30L, "body3".toByteArray()); @@ -46,6 +41,5 @@ class HeadersSpec : AbstractNatsTest({ } } - ctx.stop() } }) diff --git a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/jetstream/JetstreamSpec.kt b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/jetstream/JetstreamSpec.kt index 5dadc86c..03c09c54 100644 --- a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/jetstream/JetstreamSpec.kt +++ b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/jetstream/JetstreamSpec.kt @@ -1,29 +1,27 @@ package io.micronaut.nats.docs.jetstream import io.kotest.assertions.timing.eventually +import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.shouldBe -import io.micronaut.nats.AbstractNatsTest +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.kotest5.annotation.MicronautTest import io.nats.client.JetStreamManagement import io.nats.client.PublishOptions -import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds -import kotlin.time.ExperimentalTime -@OptIn(ExperimentalTime::class) -class JetstreamSpec : AbstractNatsTest({ - - val specName = javaClass.simpleName +@MicronautTest +@Property(name = "spec.name", value = "JetstreamSpec") +class JetstreamSpec( + productClient: ProductClient, + productListener: ProductListener, + jsm: JetStreamManagement, + pullConsumerHelper: PullConsumerHelper +) : BehaviorSpec({ given("A basic producer and consumer") { - val ctx = startContext(specName) - val jsm = ctx.getBean(JetStreamManagement::class.java) - - `when`("The messages are published") { - val productListener = ctx.getBean(ProductListener::class.java) // tag::producer[] - val productClient = ctx.getBean(ProductClient::class.java) val pa = productClient.send( "events.one", "ghi".toByteArray(), PublishOptions.builder() @@ -51,19 +49,11 @@ class JetstreamSpec : AbstractNatsTest({ } } } - - jsm.deleteStream("events") - ctx.stop() } given("Pull consumer") { - val ctx = startContext(specName) - `when`("The messages are published") { - val pullConsumerHelper = ctx.getBean(PullConsumerHelper::class.java) - // tag::producer[] - val productClient = ctx.getBean(ProductClient::class.java) val pa = productClient.send( "events.three", "ghi".toByteArray(), PublishOptions.builder() @@ -85,17 +75,11 @@ class JetstreamSpec : AbstractNatsTest({ // end::producer[] - then("The messages are received") { eventually(10.seconds) { pullConsumerHelper.pullMessages().size shouldBe 2 } } } - - val jsm = ctx.getBean(JetStreamManagement::class.java) - jsm.deleteStream("events") - - ctx.stop() } }) diff --git a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/jetstream/kv/KeyValueSpec.kt b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/jetstream/kv/KeyValueSpec.kt index 16a2b41c..4967905d 100644 --- a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/jetstream/kv/KeyValueSpec.kt +++ b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/jetstream/kv/KeyValueSpec.kt @@ -1,16 +1,15 @@ package io.micronaut.nats.docs.jetstream.kv +import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.shouldBe -import io.micronaut.nats.AbstractNatsTest +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.kotest5.annotation.MicronautTest -class KeyValueSpec : AbstractNatsTest({ - - val specName = javaClass.simpleName +@MicronautTest +@Property(name = "spec.name", value = "KeyValueSpec") +class KeyValueSpec(holder: KeyValueStoreHolder) : BehaviorSpec({ given("A key value store holder") { - val ctx = startContext(specName) - val holder = ctx.getBean(KeyValueStoreHolder::class.java) - `when`("A key is put into the store") { holder.put("test", "myvalue") diff --git a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/jetstream/os/ObjectStoreSpec.kt b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/jetstream/os/ObjectStoreSpec.kt index a16fc429..8c16734e 100644 --- a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/jetstream/os/ObjectStoreSpec.kt +++ b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/jetstream/os/ObjectStoreSpec.kt @@ -1,17 +1,15 @@ package io.micronaut.nats.docs.jetstream.os -import io.kotest.matchers.shouldBe +import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.shouldNotBe -import io.micronaut.nats.AbstractNatsTest +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.kotest5.annotation.MicronautTest -class ObjectStoreSpec : AbstractNatsTest({ - - val specName = javaClass.simpleName +@MicronautTest +@Property(name = "spec.name", value = "ObjectStoreSpec") +class ObjectStoreSpec(holder: ObjectStoreHolder) : BehaviorSpec({ given("A key value store holder") { - val ctx = startContext(specName) - val holder = ctx.getBean(ObjectStoreHolder::class.java) - `when`("A key is put into the store") { holder.put("test", "myvalue".byteInputStream()) diff --git a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/parameters/BindingSpec.kt b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/parameters/BindingSpec.kt index 1722c355..002fd79e 100644 --- a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/parameters/BindingSpec.kt +++ b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/parameters/BindingSpec.kt @@ -1,26 +1,21 @@ package io.micronaut.nats.docs.parameters import io.kotest.assertions.timing.eventually +import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.collections.shouldContain import io.kotest.matchers.shouldBe -import io.micronaut.nats.AbstractNatsTest -import kotlin.time.Duration +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.kotest5.annotation.MicronautTest import kotlin.time.Duration.Companion.seconds -import kotlin.time.ExperimentalTime -@OptIn(ExperimentalTime::class) -class BindingSpec: AbstractNatsTest({ - - val specName = javaClass.simpleName +@MicronautTest +@Property(name = "spec.name", value = "BindingSpec") +class BindingSpec(productClient: ProductClient, productListener: ProductListener) : BehaviorSpec({ given("A basic producer and consumer") { - val ctx = startContext(specName) `when`("The messages are published") { - val productListener = ctx.getBean(ProductListener::class.java) - // tag::producer[] - val productClient = ctx.getBean(ProductClient::class.java) productClient.send("message body".toByteArray()) productClient.send("product", "message body2".toByteArray()) // end::producer[] @@ -33,7 +28,5 @@ class BindingSpec: AbstractNatsTest({ } } } - - ctx.stop() } }) diff --git a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/quickstart/QuickstartSpec.kt b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/quickstart/QuickstartSpec.kt index e1cc8f6b..60a0906a 100644 --- a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/quickstart/QuickstartSpec.kt +++ b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/quickstart/QuickstartSpec.kt @@ -1,26 +1,21 @@ package io.micronaut.nats.docs.quickstart import io.kotest.assertions.timing.eventually +import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.shouldBe -import io.micronaut.nats.AbstractNatsTest -import kotlin.time.Duration +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.kotest5.annotation.MicronautTest import kotlin.time.Duration.Companion.seconds -import kotlin.time.ExperimentalTime -@OptIn(ExperimentalTime::class) -class QuickstartSpec:AbstractNatsTest({ +@MicronautTest +@Property(name = "spec.name", value = "QuickstartSpec") +class QuickstartSpec(productClient: ProductClient, productListener: ProductListener) : BehaviorSpec({ - val specName = javaClass.simpleName given("A basic producer and consumer") { - val ctx = startContext(specName) - `when`("the message is published") { - val productListener = ctx.getBean(ProductListener::class.java) - // tag::producer[] -val productClient = ctx.getBean(ProductClient::class.java) -productClient.send("quickstart".toByteArray()) + productClient.send("quickstart".toByteArray()) // end::producer[] then("the message is consumed") { @@ -30,8 +25,5 @@ productClient.send("quickstart".toByteArray()) } } } - - Thread.sleep(1000) - ctx.stop() } }) diff --git a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/rpc/RpcUppercaseSpec.kt b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/rpc/RpcUppercaseSpec.kt index 753961f9..7c2ed137 100644 --- a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/rpc/RpcUppercaseSpec.kt +++ b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/rpc/RpcUppercaseSpec.kt @@ -1,28 +1,21 @@ package io.micronaut.nats.docs.rpc +import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.shouldBe -import io.micronaut.nats.AbstractNatsTest +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.kotest5.annotation.MicronautTest import reactor.core.publisher.Mono -import kotlin.time.ExperimentalTime -@OptIn(ExperimentalTime::class) -class RpcUppercaseSpec: AbstractNatsTest({ - - val specName = javaClass.simpleName +@MicronautTest +@Property(name = "spec.name", value = "RpcUppercaseSpec") +class RpcUppercaseSpec(productClient: ProductClient) : BehaviorSpec({ given("A basic producer and consumer") { - val ctx = startContext(specName) - `when`("the message is published") { - - val productClient = ctx.getBean(ProductClient::class.java) - then("the message is consumed") { productClient.send("hello") shouldBe "HELLO" Mono.from(productClient.sendReactive("world")).block() shouldBe "WORLD" } } - - ctx.stop() } }) diff --git a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/serdes/ProductInfoSerDesSpec.kt b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/serdes/ProductInfoSerDesSpec.kt index 345da460..68fa7fd8 100644 --- a/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/serdes/ProductInfoSerDesSpec.kt +++ b/docs-examples/example-kotlin/src/test/kotlin/io/micronaut/nats/docs/serdes/ProductInfoSerDesSpec.kt @@ -1,28 +1,21 @@ package io.micronaut.nats.docs.serdes import io.kotest.assertions.timing.eventually +import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.collections.shouldExist import io.kotest.matchers.shouldBe -import io.micronaut.nats.AbstractNatsTest -import io.micronaut.nats.docs.serdes.ProductClient -import io.micronaut.nats.docs.serdes.ProductListener -import kotlin.time.Duration +import io.micronaut.context.annotation.Property +import io.micronaut.test.extensions.kotest5.annotation.MicronautTest import kotlin.time.Duration.Companion.seconds -import kotlin.time.ExperimentalTime -@OptIn(ExperimentalTime::class) -class ProductInfoSerDesSpec: AbstractNatsTest({ - - val specName = javaClass.simpleName +@MicronautTest +@Property(name = "spec.name", value = "ProductInfoSerDesSpec") +class ProductInfoSerDesSpec(productClient: ProductClient, listener: ProductListener) : BehaviorSpec({ given("A basic producer and consumer") { - val ctx = startContext(specName) `when`("the message is published") { - val listener = ctx.getBean(ProductListener::class.java) - // tag::producer[] - val productClient = ctx.getBean(ProductClient::class.java) productClient.send(ProductInfo("small", 10L, true)) productClient.send(ProductInfo("medium", 20L, true)) productClient.send(ProductInfo(null, 30L, false)) @@ -37,7 +30,5 @@ class ProductInfoSerDesSpec: AbstractNatsTest({ } } } - - ctx.stop() } }) diff --git a/docs-examples/example-kotlin/src/test/resources/application-test.yml b/docs-examples/example-kotlin/src/test/resources/application-test.yml deleted file mode 100644 index 7ea434ba..00000000 --- a/docs-examples/example-kotlin/src/test/resources/application-test.yml +++ /dev/null @@ -1,12 +0,0 @@ -micronaut: - application: - name: test-application - -nats: - default: - jetstream: - streams: - events: - storage-type: Memory - subjects: - - events.> diff --git a/docs-examples/example-kotlin/src/test/resources/application.yml b/docs-examples/example-kotlin/src/test/resources/application.yml new file mode 100644 index 00000000..3cc48f2c --- /dev/null +++ b/docs-examples/example-kotlin/src/test/resources/application.yml @@ -0,0 +1,33 @@ +micronaut: + application: + name: test-application + +nats: + default: + addresses: + - nats://localhost:${nats.port} + jetstream: + streams: + events: + storage-type: Memory + subjects: + - events.> + keyvalue: + examplebucket: + storage-type: Memory + max-history-per-key: 5 + objectstore: + examplebucket: + storage-type: Memory + +test-resources: + containers: + nats: + startup-timeout: 600s + image-name: nats:latest + exposed-ports: + - nats.port: 4222 + command: "--js" + wait-strategy: + log: + regex: ".*Server is ready.*" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8d8e971b..f696c7f0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,19 +1,21 @@ [versions] -micronaut = '4.0.0-M1' +micronaut = '4.0.0-M2' +micronaut-platform = '4.0.0-M1' micronaut-docs = '2.0.0' -micronaut-test = '4.0.0-M1' +micronaut-test = '4.0.0-M2' +micronaut-gradle-plugin = "4.0.0-M1" groovy = "4.0.10" spock = "2.3-groovy-4.0" awaitility = '4.2.0' junit = '5.9.2' kotlin = '1.8.20' -testcontainers = '1.17.6' +testcontainers = '1.18.0' nats = '2.16.10' micronaut-micrometer = "5.0.0-M1" micronaut-reactor = "3.0.0-M1" -micronaut-serde = "2.0.0-M1" +micronaut-serde = "2.0.0-M3" micronaut-rxjava3 = "3.0.0-M1" [libraries] @@ -30,6 +32,11 @@ micronaut-reactor = { module = 'io.micronaut.reactor:micronaut-reactor-bom', ver micronaut-serde = { module = "io.micronaut.serde:micronaut-serde-bom", version.ref = "micronaut-serde" } micronaut-rxjava3 = { module = 'io.micronaut.rxjava3:micronaut-rxjava3', version.ref = "micronaut-rxjava3"} +gradle-micronaut = { module = "io.micronaut.gradle:micronaut-gradle-plugin", version.ref = "micronaut-gradle-plugin" } +gradle-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } +gradle-kotlin-allopen = { module = "org.jetbrains.kotlin:kotlin-allopen", version.ref = "kotlin" } +gradle-kotlin-noarg = { module = "org.jetbrains.kotlin:kotlin-noarg", version.ref = "kotlin" } + [plugins] kotlin-jvm = { id = 'org.jetbrains.kotlin.jvm', version.ref = 'kotlin' } kotlin-kapt = { id = 'org.jetbrains.kotlin.kapt', version.ref = 'kotlin' } diff --git a/nats/src/main/java/io/micronaut/nats/bind/NatsBinderRegistry.java b/nats/src/main/java/io/micronaut/nats/bind/NatsBinderRegistry.java index 21b80b20..0cbf8d7a 100644 --- a/nats/src/main/java/io/micronaut/nats/bind/NatsBinderRegistry.java +++ b/nats/src/main/java/io/micronaut/nats/bind/NatsBinderRegistry.java @@ -15,11 +15,6 @@ */ package io.micronaut.nats.bind; -import java.lang.annotation.Annotation; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Optional; - import io.micronaut.core.bind.ArgumentBinder; import io.micronaut.core.bind.ArgumentBinderRegistry; import io.micronaut.core.bind.annotation.Bindable; @@ -28,6 +23,11 @@ import io.nats.client.Message; import jakarta.inject.Singleton; +import java.lang.annotation.Annotation; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Optional; + /** * Used to determine which {@link NatsArgumentBinder} to use for any given argument. * @@ -71,7 +71,7 @@ public NatsBinderRegistry(NatsDefaultBinder defaultBinder, NatsArgumentBinder... } @Override - public Optional> findArgumentBinder(Argument argument, Message source) { + public Optional> findArgumentBinder(Argument argument) { Optional> opt = argument.getAnnotationMetadata().getAnnotationTypeByStereotype( Bindable.class); if (opt.isPresent()) { diff --git a/nats/src/main/resources/META-INF/native-image/io/micronaut/nats/native-image.properties b/nats/src/main/resources/META-INF/native-image/io/micronaut/nats/native-image.properties index f8d38667..b48a2e4b 100644 --- a/nats/src/main/resources/META-INF/native-image/io/micronaut/nats/native-image.properties +++ b/nats/src/main/resources/META-INF/native-image/io/micronaut/nats/native-image.properties @@ -1,2 +1,2 @@ -Args = --initialize-at-build-time=io.nats.client.impl.NatsConnection \ +Args = --initialize-at-build-time=io.nats.client.impl.NatsConnection,io.nats.client.impl.ProtocolMessage,io.nats.client.support.NatsConstants,io.nats.client.support.ByteArrayBuilder,io.nats.client.support.BuilderBase \ --initialize-at-run-time=io.micronaut.nats.health.$NatsHealthIndicatorDefinition diff --git a/settings.gradle b/settings.gradle index 3a289977..fa07a7bd 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,7 +6,7 @@ pluginManagement { } plugins { - id("io.micronaut.build.shared.settings") version "6.4.1" + id("io.micronaut.build.shared.settings") version "6.4.2" } rootProject.name = 'nats-parent'