diff --git a/.github/workflows/combine-prs.yml b/.github/workflows/combine-prs.yml index a12fc172f65..2a634b34f22 100644 --- a/.github/workflows/combine-prs.yml +++ b/.github/workflows/combine-prs.yml @@ -13,6 +13,6 @@ jobs: steps: - name: combine-prs id: combine-prs - uses: github/combine-prs@v2.1.0 + uses: github/combine-prs@v3.0.1 with: github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/update-docs-version.yml b/.github/workflows/update-docs-version.yml index a511a8913de..8d69726bef3 100644 --- a/.github/workflows/update-docs-version.yml +++ b/.github/workflows/update-docs-version.yml @@ -23,7 +23,7 @@ jobs: sed -i "s/latest_version: .*/latest_version: ${GITHUB_REF##*/}/g" mkdocs.yml git diff - name: Create Pull Request - uses: peter-evans/create-pull-request@2b011faafdcbc9ceb11414d64d0573f37c774b04 # v3.10.1 + uses: peter-evans/create-pull-request@38e0b6e68b4c852a5500a94740f0e535e0d7ba54 # v3.10.1 with: title: Update docs version to ${GITHUB_REF##*/} body: | diff --git a/.github/workflows/update-testcontainers-version.yml b/.github/workflows/update-testcontainers-version.yml index 8c34789b25c..2a8f366e548 100644 --- a/.github/workflows/update-testcontainers-version.yml +++ b/.github/workflows/update-testcontainers-version.yml @@ -23,7 +23,7 @@ jobs: sed -i "s/^testcontainers\.version=.*/testcontainers\.version=${GITHUB_REF##*/}/g" gradle.properties git diff - name: Create Pull Request - uses: peter-evans/create-pull-request@2b011faafdcbc9ceb11414d64d0573f37c774b04 # v3.10.1 + uses: peter-evans/create-pull-request@38e0b6e68b4c852a5500a94740f0e535e0d7ba54 # v3.10.1 with: title: Update testcontainers version to ${GITHUB_REF##*/} body: | diff --git a/build.gradle b/build.gradle index 4737b5c043f..4b6501a3520 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ buildscript { plugins { id 'io.franzbecker.gradle-lombok' version '5.0.0' - id 'com.github.johnrengelman.shadow' version '8.1.0' + id 'com.github.johnrengelman.shadow' version '8.1.1' id 'me.champeau.gradle.japicmp' version '0.4.1' apply false id 'com.diffplug.spotless' version '6.13.0' apply false } @@ -52,7 +52,7 @@ subprojects { } lombok { - version = '1.18.24' + version = '1.18.26' } diff --git a/core/build.gradle b/core/build.gradle index a8417e69d37..f5f5e14fb09 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -69,14 +69,14 @@ configurations.all { dependencies { api 'junit:junit:4.13.2' api 'org.slf4j:slf4j-api:1.7.36' - compileOnly 'org.jetbrains:annotations:24.0.0' - testCompileOnly 'org.jetbrains:annotations:24.0.0' - api 'org.apache.commons:commons-compress:1.22' + compileOnly 'org.jetbrains:annotations:24.0.1' + testCompileOnly 'org.jetbrains:annotations:24.0.1' + api 'org.apache.commons:commons-compress:1.23.0' api ('org.rnorth.duct-tape:duct-tape:1.0.8') { exclude(group: 'org.jetbrains', module: 'annotations') } - provided('com.google.cloud.tools:jib-core:0.22.0') { + provided('com.google.cloud.tools:jib-core:0.23.0') { exclude group: 'com.google.guava', module: 'guava' exclude group: 'com.fasterxml.jackson.datatype', module: 'jackson-datatype-jsr310' exclude group: 'com.fasterxml.jackson.core', module: 'jackson-core' @@ -101,10 +101,10 @@ dependencies { shaded 'org.zeroturnaround:zt-exec:1.12' - testImplementation 'com.google.cloud.tools:jib-core:0.22.0' + testImplementation 'com.google.cloud.tools:jib-core:0.23.0' testImplementation 'org.apache.httpcomponents:httpclient:4.5.9' - testImplementation 'redis.clients:jedis:4.3.1' - testImplementation 'com.rabbitmq:amqp-client:5.16.0' + testImplementation 'redis.clients:jedis:4.3.2' + testImplementation 'com.rabbitmq:amqp-client:5.17.0' testImplementation 'org.mongodb:mongo-java-driver:3.12.12' testImplementation ('org.mockito:mockito-core:4.11.0') { @@ -125,7 +125,6 @@ dependencies { tasks.generatePomFileForMavenJavaPublication.finalizedBy( tasks.register('checkPOMdependencies', org.testcontainers.build.ComparePOMWithLatestReleasedTask) { ignore = [ - "com.google.cloud.tools:jib-core" ] } ) diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 683e9d9fdf5..090215fcec3 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -143,7 +143,7 @@ public DockerComposeContainer(String identifier, List composeFiles) { this.dockerComposeFiles = new DockerComposeFiles(composeFiles); // Use a unique identifier so that containers created for this compose environment can be identified - this.identifier = identifier; + this.identifier = identifier.toLowerCase(); this.project = randomProjectId(); this.dockerClient = DockerClientFactory.lazyClient(); @@ -689,7 +689,7 @@ public ContainerisedDockerCompose(List composeFiles, String identifier) { final String composeFileEnvVariableValue = Joiner.on(UNIX_PATH_SEPERATOR).join(absoluteDockerComposeFiles); // we always need the UNIX path separator logger().debug("Set env COMPOSE_FILE={}", composeFileEnvVariableValue); addEnv(ENV_COMPOSE_FILE, composeFileEnvVariableValue); - addFileSystemBind(pwd, containerPwd, BindMode.READ_WRITE); + withCopyFileToContainer(MountableFile.forHostPath(pwd), containerPwd); // Ensure that compose can access docker. Since the container is assumed to be running on the same machine // as the docker daemon, just mapping the docker control socket is OK. diff --git a/core/src/main/java/org/testcontainers/utility/ImageNameSubstitutor.java b/core/src/main/java/org/testcontainers/utility/ImageNameSubstitutor.java index dae3f178230..3f491e4c9b3 100644 --- a/core/src/main/java/org/testcontainers/utility/ImageNameSubstitutor.java +++ b/core/src/main/java/org/testcontainers/utility/ImageNameSubstitutor.java @@ -33,7 +33,12 @@ public static synchronized ImageNameSubstitutor instance() { ImageNameSubstitutor configuredInstance; try { configuredInstance = - (ImageNameSubstitutor) Class.forName(configuredClassName).getConstructor().newInstance(); + (ImageNameSubstitutor) Thread + .currentThread() + .getContextClassLoader() + .loadClass(configuredClassName) + .getConstructor() + .newInstance(); } catch (Exception e) { throw new IllegalArgumentException( "Configured Image Substitutor could not be loaded: " + configuredClassName, diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeV2FormatWithIdentifierTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeV2FormatWithIdentifierTest.java new file mode 100644 index 00000000000..90c041b53b6 --- /dev/null +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeV2FormatWithIdentifierTest.java @@ -0,0 +1,21 @@ +package org.testcontainers.junit; + +import org.junit.Rule; +import org.testcontainers.containers.DockerComposeContainer; + +import java.io.File; + +public class DockerComposeV2FormatWithIdentifierTest extends BaseDockerComposeTest { + + @Rule + public DockerComposeContainer environment = new DockerComposeContainer( + "TEST", + new File("src/test/resources/v2-compose-test.yml") + ) + .withExposedService("redis_1", REDIS_PORT); + + @Override + protected DockerComposeContainer getEnvironment() { + return this.environment; + } +} diff --git a/docs/_redirects b/docs/_redirects index 5918fb853f2..d3c61aba618 100644 --- a/docs/_redirects +++ b/docs/_redirects @@ -12,7 +12,7 @@ /usage/database_containers.html /modules/databases/ /usage/neo4j_container.html /modules/databases/neo4j/ /compatibility.html /supported_docker_environment/ -/on_failure.html /supported_docker_environment/ +/on_failure.html /error_missing_container_runtime_environment # No great 1:1 mapping exists for the following, so redirect to somewhere where at least a sensible sidebar will be shown diff --git a/docs/error_missing_container_runtime_environment.md b/docs/error_missing_container_runtime_environment.md new file mode 100644 index 00000000000..373d04fff38 --- /dev/null +++ b/docs/error_missing_container_runtime_environment.md @@ -0,0 +1,16 @@ +# Fixing Issues with Discovering A Supported Container Runtime Environment + + +If you ended up on this page, +it seems that either Testcontainers was not able to find a supported container runtime in your environment, +or you found this page while searching for information to deal with errors regarding the environment discovery mechanism of Testcontainers. + +Testcontainers requires a supported container runtime environment to be present in order to manage and run containers. +Here is a list of supported container runtime environments: + +* [Docker Desktop](https://www.docker.com/products/docker-desktop/) +* [Docker Engine on Linux](https://docs.docker.com/engine/install/) +* [Testcontainers Cloud](https://www.testcontainers.cloud?utm_medium=direct&utm_source=testcontainers.com&utm_content=docs&utm_term=on-failure) + +For more extensive information on supported container runtime environments, as well as known limitations of alternative container runtime environments, +please refer to [this page](https://www.testcontainers.org/supported_docker_environment/) in our documentation. diff --git a/docs/modules/hivemq.md b/docs/modules/hivemq.md index 66f9670648c..2ebdd7a9ad8 100644 --- a/docs/modules/hivemq.md +++ b/docs/modules/hivemq.md @@ -34,7 +34,7 @@ Using the Enterprise Edition: [Enterprise Edition HiveMQ image](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java) inside_block:hiveEEVersion -Using a specifc version is possible by using the tag: +Using a specific version is possible by using the tag: [Specific HiveMQ Version](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java) inside_block:specificVersion @@ -151,7 +151,7 @@ If the extension folder contains a DISABLED file, the extension will be disabled --- -We first load the extension from the filesytem: +We first load the extension from the filesystem: [Extension from filesystem](../../modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoDisableExtensionsIT.java) inside_block:startFromFilesystem diff --git a/docs/modules/kafka.md b/docs/modules/kafka.md index 691c4f10bf8..13f8cf3b0a8 100644 --- a/docs/modules/kafka.md +++ b/docs/modules/kafka.md @@ -34,8 +34,7 @@ If for some reason you want to use an externally running Zookeeper, then just pa ### Using Kraft mode -The self-managed (Kraft) mode is available as a preview feature since version 3.0 (confluentinc/cp-kafka:7.0.x) and -declared as a production ready in 3.3.1 (confluentinc/cp-kafka:7.3.x). +KRaft mode was declared production ready in 3.3.1 (confluentinc/cp-kafka:7.3.x)" [Kraft mode](../../modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java) inside_block:withKraftMode diff --git a/docs/test_framework_integration/external.md b/docs/test_framework_integration/external.md new file mode 100644 index 00000000000..2082af93bf0 --- /dev/null +++ b/docs/test_framework_integration/external.md @@ -0,0 +1,9 @@ +# External Integrations + +The following Open Source frameworks add direct integration to Testcontainers + +| Framework | Source Code | Documentation | +| --- | --- | --- | +| jqwik | [jqwik-testcontainers](https://github.com/jqwik-team/jqwik-testcontainers) | [README](https://github.com/jqwik-team/jqwik-testcontainers) | +| Kotest | [Kotest Extensions Testcontainers](https://github.com/kotest/kotest-extensions-testcontainers) | [kotest.io](https://kotest.io/docs/extensions/test_containers.html) | + diff --git a/examples/gradle/wrapper/gradle-wrapper.jar b/examples/gradle/wrapper/gradle-wrapper.jar index ccebba7710d..c1962a79e29 100644 Binary files a/examples/gradle/wrapper/gradle-wrapper.jar and b/examples/gradle/wrapper/gradle-wrapper.jar differ diff --git a/examples/gradle/wrapper/gradle-wrapper.properties b/examples/gradle/wrapper/gradle-wrapper.properties index 19acfb4ef2f..2c3425d49ec 100644 --- a/examples/gradle/wrapper/gradle-wrapper.properties +++ b/examples/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=ff7bf6a86f09b9b2c40bb8f48b25fc19cf2b2664fd1d220cd7ab833ec758d0d7 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip +distributionSha256Sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/examples/gradlew b/examples/gradlew index 79a61d421cc..aeb74cbb43e 100755 --- a/examples/gradlew +++ b/examples/gradlew @@ -85,9 +85,6 @@ done APP_BASE_NAME=${0##*/} APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -197,6 +194,10 @@ if "$cygwin" || "$msys" ; then done fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in diff --git a/examples/hazelcast/build.gradle b/examples/hazelcast/build.gradle index a13e16a23c6..63f43c11143 100644 --- a/examples/hazelcast/build.gradle +++ b/examples/hazelcast/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { testImplementation 'org.testcontainers:testcontainers' - testImplementation 'com.hazelcast:hazelcast:5.2.2' + testImplementation 'com.hazelcast:hazelcast:5.2.3' testImplementation 'ch.qos.logback:logback-classic:1.3.5' testImplementation 'org.assertj:assertj-core:3.24.2' } diff --git a/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerClusterTest.java b/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerClusterTest.java index 60790514825..089d80fa080 100644 --- a/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerClusterTest.java +++ b/examples/kafka-cluster/src/test/java/com/example/kafkacluster/KafkaContainerClusterTest.java @@ -51,6 +51,18 @@ public void testKafkaContainerKraftCluster() throws Exception { } } + @Test + public void testKafkaContainerKraftClusterAfterConfluentPlatform740() throws Exception { + try (KafkaContainerKraftCluster cluster = new KafkaContainerKraftCluster("7.4.0", 3, 2)) { + cluster.start(); + String bootstrapServers = cluster.getBootstrapServers(); + + assertThat(cluster.getBrokers()).hasSize(3); + + testKafkaFunctionality(bootstrapServers, 3, 2); + } + } + protected void testKafkaFunctionality(String bootstrapServers, int partitions, int rf) throws Exception { try ( AdminClient adminClient = AdminClient.create( diff --git a/examples/linked-container/build.gradle b/examples/linked-container/build.gradle index b27851a23cb..1aa9dae1b23 100644 --- a/examples/linked-container/build.gradle +++ b/examples/linked-container/build.gradle @@ -9,7 +9,7 @@ dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.36' implementation 'com.squareup.okhttp3:okhttp:4.10.0' implementation 'org.json:json:20230227' - testImplementation 'org.postgresql:postgresql:42.5.4' + testImplementation 'org.postgresql:postgresql:42.6.0' testImplementation 'ch.qos.logback:logback-classic:1.3.5' testImplementation 'org.testcontainers:postgresql' testImplementation 'org.assertj:assertj-core:3.24.2' diff --git a/examples/nats/build.gradle b/examples/nats/build.gradle index 263aebf59ca..feeccdb32a6 100644 --- a/examples/nats/build.gradle +++ b/examples/nats/build.gradle @@ -9,7 +9,7 @@ repositories { dependencies { testImplementation 'org.assertj:assertj-core:3.24.2' testImplementation 'org.testcontainers:testcontainers' - testImplementation 'io.nats:jnats:2.16.8' + testImplementation 'io.nats:jnats:2.16.10' testImplementation 'ch.qos.logback:logback-classic:1.3.5' testImplementation 'org.apache.httpcomponents:httpclient:4.5.14' } diff --git a/examples/redis-backed-cache-testng/build.gradle b/examples/redis-backed-cache-testng/build.gradle index 3a1e162c82a..0f284e3ffa7 100644 --- a/examples/redis-backed-cache-testng/build.gradle +++ b/examples/redis-backed-cache-testng/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.36' - implementation 'redis.clients:jedis:4.3.1' + implementation 'redis.clients:jedis:4.3.2' implementation 'com.google.code.gson:gson:2.10.1' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/redis-backed-cache/build.gradle b/examples/redis-backed-cache/build.gradle index c8286015285..d5807de0899 100644 --- a/examples/redis-backed-cache/build.gradle +++ b/examples/redis-backed-cache/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { compileOnly 'org.slf4j:slf4j-api:1.7.36' - implementation 'redis.clients:jedis:4.3.1' + implementation 'redis.clients:jedis:4.3.2' implementation 'com.google.code.gson:gson:2.10.1' implementation 'com.google.guava:guava:23.0' testImplementation 'org.testcontainers:testcontainers' diff --git a/examples/selenium-container/build.gradle b/examples/selenium-container/build.gradle index 5e8bb02a184..820564255b2 100644 --- a/examples/selenium-container/build.gradle +++ b/examples/selenium-container/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.7.9' + id 'org.springframework.boot' version '2.7.10' } apply plugin: 'io.spring.dependency-management' diff --git a/examples/settings.gradle b/examples/settings.gradle index bb3ce2952db..e43084b6e6a 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -6,8 +6,8 @@ buildscript { } dependencies { classpath "gradle.plugin.ch.myniva.gradle:s3-build-cache:0.10.0" - classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.12.3" - classpath "com.gradle:common-custom-user-data-gradle-plugin:1.8.2" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.12.6" + classpath "com.gradle:common-custom-user-data-gradle-plugin:1.10" } } diff --git a/examples/singleton-container/build.gradle b/examples/singleton-container/build.gradle index ad7d51c883a..a8319bddfa9 100644 --- a/examples/singleton-container/build.gradle +++ b/examples/singleton-container/build.gradle @@ -8,7 +8,7 @@ repositories { dependencies { - implementation 'redis.clients:jedis:4.3.1' + implementation 'redis.clients:jedis:4.3.2' implementation 'com.google.code.gson:gson:2.10.1' implementation 'com.google.guava:guava:23.0' compileOnly 'org.slf4j:slf4j-api:1.7.36' diff --git a/examples/spring-boot-kotlin-redis/build.gradle b/examples/spring-boot-kotlin-redis/build.gradle index eca2ee2fd3f..e99b37485b9 100644 --- a/examples/spring-boot-kotlin-redis/build.gradle +++ b/examples/spring-boot-kotlin-redis/build.gradle @@ -1,7 +1,7 @@ plugins { - id("org.springframework.boot") version "2.7.9" + id("org.springframework.boot") version "2.7.10" id("org.jetbrains.kotlin.jvm") version "1.8.10" - id("org.jetbrains.kotlin.plugin.spring") version "1.8.10" + id("org.jetbrains.kotlin.plugin.spring") version "1.8.20" } apply plugin: 'io.spring.dependency-management' diff --git a/examples/spring-boot/build.gradle b/examples/spring-boot/build.gradle index fb70124e81a..00edc4c78d3 100644 --- a/examples/spring-boot/build.gradle +++ b/examples/spring-boot/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.7.9' + id 'org.springframework.boot' version '2.7.10' } apply plugin: 'io.spring.dependency-management' diff --git a/gradle.properties b/gradle.properties index cc9c268c0d6..af72b6cbacf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel=false org.gradle.caching=true org.gradle.configureondemand=true -testcontainers.version=1.17.6 +testcontainers.version=1.18.0 diff --git a/gradle/publishing.gradle b/gradle/publishing.gradle index ffeb3cb38d4..3b2b3f22211 100644 --- a/gradle/publishing.gradle +++ b/gradle/publishing.gradle @@ -57,8 +57,12 @@ publishing { def dependenciesNode = rootNode.appendNode('dependencies') - def addDependencies = { Configuration configuration, scope -> - for (dependency in configuration.resolvedConfiguration.firstLevelModuleDependencies) { + def apiDeps= project.configurations.api.resolvedConfiguration.firstLevelModuleDependencies + def providedDeps = project.configurations.provided.resolvedConfiguration.firstLevelModuleDependencies + def newApiDeps = apiDeps - providedDeps + + def addDependencies = { Set resolvedDependencies, scope -> + for (dependency in resolvedDependencies) { if (dependency.configuration.startsWith("platform-")) { continue } @@ -66,6 +70,7 @@ publishing { if (!dependency.moduleGroup || !dependency.moduleName || !dependency.moduleVersion) { throw new IllegalStateException("Wrong dependency: $dependency") } + appendNode('groupId', dependency.moduleGroup) appendNode('artifactId', dependency.moduleName) appendNode('version', dependency.moduleVersion) @@ -83,8 +88,8 @@ publishing { } } } - addDependencies(project.configurations.api, 'compile') - addDependencies(project.configurations.provided, 'provided') + addDependencies(newApiDeps, 'compile') + addDependencies(providedDeps, 'provided') } } } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index ccebba7710d..c1962a79e29 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a2efda8857b..93eea3481ce 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=47a5bfed9ef814f90f8debcbbb315e8e7c654109acd224595ea39fca95c5d4da -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-all.zip +distributionSha256Sum=5625a0ae20fe000d9225d000b36909c7a0e0e8dda61c19b12da769add847c975 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-all.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 79a61d421cc..aeb74cbb43e 100755 --- a/gradlew +++ b/gradlew @@ -85,9 +85,6 @@ done APP_BASE_NAME=${0##*/} APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -197,6 +194,10 @@ if "$cygwin" || "$msys" ; then done fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in diff --git a/mkdocs.yml b/mkdocs.yml index 72c457b9d5f..84d9bc0aa18 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -94,9 +94,11 @@ nav: - test_framework_integration/junit_5.md - test_framework_integration/spock.md - test_framework_integration/manual_lifecycle_control.md + - test_framework_integration/external.md - Examples: examples.md - System Requirements: - supported_docker_environment/index.md + - error_missing_container_runtime_environment.md - Continuous Integration: - supported_docker_environment/continuous_integration/aws_codebuild.md - supported_docker_environment/continuous_integration/dind_patterns.md @@ -117,4 +119,4 @@ nav: - bounty.md edit_uri: edit/main/docs/ extra: - latest_version: 1.17.6 + latest_version: 1.18.0 diff --git a/modules/azure/build.gradle b/modules/azure/build.gradle index 33a30b0ecb5..83319057269 100644 --- a/modules/azure/build.gradle +++ b/modules/azure/build.gradle @@ -6,5 +6,5 @@ dependencies { shaded 'com.squareup.okhttp3:okhttp:4.10.0' testImplementation 'org.assertj:assertj-core:3.24.2' - testImplementation 'com.azure:azure-cosmos:4.41.0' + testImplementation 'com.azure:azure-cosmos:4.42.0' } diff --git a/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java index dcebe165f73..51d94128509 100644 --- a/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java +++ b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java @@ -21,7 +21,7 @@ /** * Cassandra container * - * Supports 2.x and 3.x Cassandra versions + * Testcontainers implementation for Apache Cassandra. */ public class CassandraContainer> extends GenericContainer { diff --git a/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraServer4Test.java b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraServer4Test.java new file mode 100644 index 00000000000..1a8447e7036 --- /dev/null +++ b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraServer4Test.java @@ -0,0 +1,35 @@ +package org.testcontainers.containers; + +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import org.junit.Rule; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CassandraServer4Test { + + @Rule + public CassandraContainer cassandra = new CassandraContainer<>("cassandra:4.1.1"); + + @Test + public void testCassandraGetContactPoint() { + try ( + CqlSession session = CqlSession + .builder() + .addContactPoint(this.cassandra.getContactPoint()) + .withLocalDatacenter(this.cassandra.getLocalDatacenter()) + .build() + ) { + session.execute( + "CREATE KEYSPACE IF NOT EXISTS test WITH replication = \n" + + "{'class':'SimpleStrategy','replication_factor':'1'};" + ); + + KeyspaceMetadata keyspace = session.getMetadata().getKeyspaces().get(CqlIdentifier.fromCql("test")); + + assertThat(keyspace).as("test keyspace created").isNotNull(); + } + } +} diff --git a/modules/cockroachdb/build.gradle b/modules/cockroachdb/build.gradle index c03157ba2f9..0e26a6f2a96 100644 --- a/modules/cockroachdb/build.gradle +++ b/modules/cockroachdb/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'org.postgresql:postgresql:42.5.4' + testImplementation 'org.postgresql:postgresql:42.6.0' testImplementation 'org.assertj:assertj-core:3.24.2' } diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle index 31be992141d..3e8dca2c1ad 100644 --- a/modules/couchbase/build.gradle +++ b/modules/couchbase/build.gradle @@ -5,7 +5,7 @@ dependencies { // TODO use JDK's HTTP client and/or Apache HttpClient5 shaded 'com.squareup.okhttp3:okhttp:4.10.0' - testImplementation 'com.couchbase.client:java-client:3.4.3' + testImplementation 'com.couchbase.client:java-client:3.4.4' testImplementation 'org.awaitility:awaitility:4.2.0' testImplementation 'org.assertj:assertj-core:3.24.2' } diff --git a/modules/cratedb/build.gradle b/modules/cratedb/build.gradle index d53031542f5..12013aa2c76 100644 --- a/modules/cratedb/build.gradle +++ b/modules/cratedb/build.gradle @@ -7,7 +7,7 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'org.postgresql:postgresql:42.5.4' + testImplementation 'org.postgresql:postgresql:42.6.0' - compileOnly 'org.jetbrains:annotations:24.0.0' + compileOnly 'org.jetbrains:annotations:24.0.1' } diff --git a/modules/dynalite/build.gradle b/modules/dynalite/build.gradle index 80d811edc9e..c29e1a5cae8 100644 --- a/modules/dynalite/build.gradle +++ b/modules/dynalite/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Dynalite" dependencies { api project(':testcontainers') - compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.418' - testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.418' + compileOnly 'com.amazonaws:aws-java-sdk-dynamodb:1.12.441' + testImplementation 'com.amazonaws:aws-java-sdk-dynamodb:1.12.441' testImplementation 'org.assertj:assertj-core:3.24.2' } diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 5d2132fe0d7..ea966a763be 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -2,7 +2,7 @@ description = "TestContainers :: elasticsearch" dependencies { api project(':testcontainers') - testImplementation "org.elasticsearch.client:elasticsearch-rest-client:8.6.2" + testImplementation "org.elasticsearch.client:elasticsearch-rest-client:8.7.0" testImplementation "org.elasticsearch.client:transport:7.17.9" testImplementation 'org.assertj:assertj-core:3.24.2' } diff --git a/modules/gcloud/build.gradle b/modules/gcloud/build.gradle index a8bb9c9f7f0..df60ae81dba 100644 --- a/modules/gcloud/build.gradle +++ b/modules/gcloud/build.gradle @@ -3,10 +3,10 @@ description = "Testcontainers :: GCloud" dependencies { api project(':testcontainers') - testImplementation 'com.google.cloud:google-cloud-datastore:2.13.5' - testImplementation 'com.google.cloud:google-cloud-firestore:3.8.1' - testImplementation 'com.google.cloud:google-cloud-pubsub:1.123.4' - testImplementation 'com.google.cloud:google-cloud-spanner:6.36.1' - testImplementation 'com.google.cloud:google-cloud-bigtable:2.19.2' + testImplementation 'com.google.cloud:google-cloud-datastore:2.14.2' + testImplementation 'com.google.cloud:google-cloud-firestore:3.9.3' + testImplementation 'com.google.cloud:google-cloud-pubsub:1.123.8' + testImplementation 'com.google.cloud:google-cloud-spanner:6.38.2' + testImplementation 'com.google.cloud:google-cloud-bigtable:2.20.3' testImplementation 'org.assertj:assertj-core:3.24.2' } diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index 48d7b5ab25c..1e37b848362 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -2,7 +2,7 @@ description = "TestContainers :: HiveMQ" dependencies { api(project(":testcontainers")) - api("org.jetbrains:annotations:24.0.0") + api("org.jetbrains:annotations:24.0.1") shaded("org.apache.commons:commons-lang3:3.12.0") shaded("commons-io:commons-io:2.11.0") @@ -13,10 +13,10 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2") testImplementation(project(":junit-jupiter")) - testImplementation("com.hivemq:hivemq-extension-sdk:4.12.0") + testImplementation("com.hivemq:hivemq-extension-sdk:4.14.0") testImplementation("com.hivemq:hivemq-mqtt-client:1.3.0") testImplementation("org.apache.httpcomponents:httpclient:4.5.14") - testImplementation("ch.qos.logback:logback-classic:1.4.5") + testImplementation("ch.qos.logback:logback-classic:1.4.6") testImplementation 'org.assertj:assertj-core:3.24.2' testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.2") } diff --git a/modules/influxdb/build.gradle b/modules/influxdb/build.gradle index bd37ae0ce50..457f29e660d 100644 --- a/modules/influxdb/build.gradle +++ b/modules/influxdb/build.gradle @@ -7,5 +7,5 @@ dependencies { testImplementation 'org.assertj:assertj-core:3.24.2' testImplementation 'org.influxdb:influxdb-java:2.23' - testImplementation "com.influxdb:influxdb-client-java:6.7.0" + testImplementation "com.influxdb:influxdb-client-java:6.8.0" } diff --git a/modules/jdbc/build.gradle b/modules/jdbc/build.gradle index 2380dec6185..a3fb4c4dd89 100644 --- a/modules/jdbc/build.gradle +++ b/modules/jdbc/build.gradle @@ -3,10 +3,10 @@ description = "Testcontainers :: JDBC" dependencies { api project(':database-commons') - compileOnly 'org.jetbrains:annotations:24.0.0' + compileOnly 'org.jetbrains:annotations:24.0.1' testImplementation 'commons-dbutils:commons-dbutils:1.7' testImplementation 'org.vibur:vibur-dbcp:25.0' - testImplementation 'org.apache.tomcat:tomcat-jdbc:10.1.6' + testImplementation 'org.apache.tomcat:tomcat-jdbc:10.1.7' testImplementation 'com.zaxxer:HikariCP-java6:2.3.13' testImplementation 'org.assertj:assertj-core:3.24.2' testImplementation ('org.mockito:mockito-core:4.11.0') { diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 8b3988a9982..d5adb84109d 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -8,7 +8,7 @@ dependencies { testImplementation project(':mysql') testImplementation project(':postgresql') testImplementation 'com.zaxxer:HikariCP:4.0.3' - testImplementation 'redis.clients:jedis:4.3.1' + testImplementation 'redis.clients:jedis:4.3.2' testImplementation 'org.apache.httpcomponents:httpclient:4.5.14' testImplementation ('org.mockito:mockito-core:4.11.0') { exclude(module: 'hamcrest-core') @@ -16,7 +16,7 @@ dependencies { testImplementation 'org.assertj:assertj-core:3.24.2' testImplementation 'org.junit.jupiter:junit-jupiter' - testRuntimeOnly 'org.postgresql:postgresql:42.5.4' + testRuntimeOnly 'org.postgresql:postgresql:42.6.0' testRuntimeOnly 'mysql:mysql-connector-java:8.0.32' } diff --git a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Container.java b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Container.java index a075786d0d5..a22c23e57a6 100644 --- a/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Container.java +++ b/modules/junit-jupiter/src/main/java/org/testcontainers/junit/jupiter/Container.java @@ -11,7 +11,7 @@ * * @see Testcontainers */ -@Target(ElementType.FIELD) +@Target({ ElementType.FIELD, ElementType.ANNOTATION_TYPE }) @Retention(RetentionPolicy.RUNTIME) public @interface Container { } diff --git a/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/MetaAnnotationTest.java b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/MetaAnnotationTest.java new file mode 100644 index 00000000000..627d778a93f --- /dev/null +++ b/modules/junit-jupiter/src/test/java/org/testcontainers/junit/jupiter/MetaAnnotationTest.java @@ -0,0 +1,28 @@ +package org.testcontainers.junit.jupiter; + +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.PostgreSQLContainer; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import static org.assertj.core.api.Assertions.assertThat; + +@Testcontainers +class MetaAnnotationTest { + + @TcContainer + private static final PostgreSQLContainer POSTGRESQL = new PostgreSQLContainer<>( + JUnitJupiterTestImages.POSTGRES_IMAGE + ); + + @Test + void test() { + assertThat(POSTGRESQL.isRunning()).isTrue(); + } +} + +@Container +@Retention(RetentionPolicy.RUNTIME) +@interface TcContainer { +} diff --git a/modules/k3s/build.gradle b/modules/k3s/build.gradle index b4dfd6903dd..e4fad44abfa 100644 --- a/modules/k3s/build.gradle +++ b/modules/k3s/build.gradle @@ -8,7 +8,7 @@ dependencies { // Any >2.8 version here is not compatible with jackson-databind 2.8.x. shaded 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.8.8' - testImplementation 'io.fabric8:kubernetes-client:6.4.1' - testImplementation 'io.kubernetes:client-java:17.0.1' + testImplementation 'io.fabric8:kubernetes-client:6.5.1' + testImplementation 'io.kubernetes:client-java:18.0.0' testImplementation 'org.assertj:assertj-core:3.24.2' } diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index 8bf0ae60617..9728203a87c 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -7,9 +7,3 @@ dependencies { testImplementation 'org.assertj:assertj-core:3.24.2' testImplementation 'com.google.guava:guava:23.0' } - -tasks.japicmp { - methodExcludes = [ - "org.testcontainers.containers.KafkaContainer#containerIsStarted(com.github.dockerjava.api.command.InspectContainerResponse)" - ] -} diff --git a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java index 32bfc366896..d00b15a1030 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -6,11 +6,10 @@ import org.testcontainers.utility.ComparableVersion; import org.testcontainers.utility.DockerImageName; -import java.io.IOException; +import java.util.Objects; /** * This container wraps Confluent Kafka and Zookeeper (optionally) - * */ public class KafkaContainer extends GenericContainer { @@ -29,11 +28,13 @@ public class KafkaContainer extends GenericContainer { // https://docs.confluent.io/platform/7.0.0/release-notes/index.html#ak-raft-kraft private static final String MIN_KRAFT_TAG = "7.0.0"; + public static final String DEFAULT_CLUSTER_ID = "4L6g3nShT-eMCtK--X86sw"; + protected String externalZookeeperConnect = null; private boolean kraftEnabled = false; - private String clusterId; + private String clusterId = DEFAULT_CLUSTER_ID; /** * @deprecated use {@link KafkaContainer(DockerImageName)} instead @@ -98,7 +99,7 @@ public KafkaContainer withKraft() { throw new IllegalStateException("Cannot configure Kraft mode when Zookeeper configured"); } verifyMinKraftVersion(); - kraftEnabled = true; + this.kraftEnabled = true; return self(); } @@ -115,7 +116,13 @@ private void verifyMinKraftVersion() { } } + private boolean isLessThanCP740() { + String actualVersion = DockerImageName.parse(getDockerImageName()).getVersionPart(); + return new ComparableVersion(actualVersion).isLessThan("7.4.0"); + } + public KafkaContainer withClusterId(String clusterId) { + Objects.requireNonNull(clusterId, "clusterId cannot be null"); this.clusterId = clusterId; return self(); } @@ -126,7 +133,7 @@ public String getBootstrapServers() { @Override protected void configure() { - if (kraftEnabled) { + if (this.kraftEnabled) { waitingFor(Wait.forLogMessage(".*Transitioning from RECOVERY to RUNNING.*", 1)); configureKraft(); } else { @@ -136,10 +143,9 @@ protected void configure() { } protected void configureKraft() { - withEnv( - "KAFKA_NODE_ID", - getEnvMap().computeIfAbsent("KAFKA_NODE_ID", key -> getEnvMap().get("KAFKA_BROKER_ID")) - ); + //CP 7.4.0 + getEnvMap().computeIfAbsent("CLUSTER_ID", key -> clusterId); + getEnvMap().computeIfAbsent("KAFKA_NODE_ID", key -> getEnvMap().get("KAFKA_BROKER_ID")); withEnv( "KAFKA_LISTENER_SECURITY_PROTOCOL_MAP", String.format("%s,CONTROLLER:PLAINTEXT", getEnvMap().get("KAFKA_LISTENER_SECURITY_PROTOCOL_MAP")) @@ -147,20 +153,17 @@ protected void configureKraft() { withEnv("KAFKA_LISTENERS", String.format("%s,CONTROLLER://0.0.0.0:9094", getEnvMap().get("KAFKA_LISTENERS"))); withEnv("KAFKA_PROCESS_ROLES", "broker,controller"); - withEnv( - "KAFKA_CONTROLLER_QUORUM_VOTERS", - getEnvMap() - .computeIfAbsent( - "KAFKA_CONTROLLER_QUORUM_VOTERS", - key -> { - return String.format( - "%s@%s:9094", - getEnvMap().get("KAFKA_NODE_ID"), - getNetwork() != null ? getNetworkAliases().get(0) : "localhost" - ); - } - ) - ); + getEnvMap() + .computeIfAbsent( + "KAFKA_CONTROLLER_QUORUM_VOTERS", + key -> { + return String.format( + "%s@%s:9094", + getEnvMap().get("KAFKA_NODE_ID"), + getNetwork() != null ? getNetworkAliases().get(0) : "localhost" + ); + } + ); withEnv("KAFKA_CONTROLLER_LISTENER_NAMES", "CONTROLLER"); } @@ -186,10 +189,18 @@ protected void containerIsStarting(InspectContainerResponse containerInfo) { brokerAdvertisedListener(containerInfo) ); - command += (kraftEnabled) ? commandKraft() : commandZookeeper(); + if (this.kraftEnabled && isLessThanCP740()) { + // Optimization: skip the checks + command += "echo '' > /etc/confluent/docker/ensure \n"; + command += commandKraft(); + } + + if (!this.kraftEnabled) { + // Optimization: skip the checks + command += "echo '' > /etc/confluent/docker/ensure \n"; + command += commandZookeeper(); + } - // Optimization: skip the checks - command += "echo '' > /etc/confluent/docker/ensure \n"; // Run the original command command += "/etc/confluent/docker/run \n"; copyFileToContainer(Transferable.of(command, 0777), STARTER_SCRIPT); @@ -197,16 +208,9 @@ protected void containerIsStarting(InspectContainerResponse containerInfo) { protected String commandKraft() { String command = "sed -i '/KAFKA_ZOOKEEPER_CONNECT/d' /etc/confluent/docker/configure\n"; - try { - if (clusterId == null) { - clusterId = execInContainer("kafka-storage", "random-uuid").getStdout().trim(); - } - } catch (IOException | InterruptedException e) { - logger().error("Failed to execute `kafka-storage random-uuid`. Exception message: {}", e.getMessage()); - } command += "echo 'kafka-storage format --ignore-formatted -t \"" + - clusterId + + this.clusterId + "\" -c /etc/kafka/kafka.properties' >> /etc/confluent/docker/configure\n"; return command; } diff --git a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java index bad3c8d89ef..860c990cb32 100644 --- a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java +++ b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java @@ -133,10 +133,20 @@ public void testWithHostExposedPortAndExternalNetwork() throws Exception { } @Test - public void testUsageKraft() throws Exception { + public void testUsageKraftBeforeConfluentPlatformVersion74() throws Exception { try ( - // withKraftMode { KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:7.0.1")).withKraft() + ) { + kafka.start(); + testKafkaFunctionality(kafka.getBootstrapServers()); + } + } + + @Test + public void testUsageKraftAfterConfluentPlatformVersion74() throws Exception { + try ( + // withKraftMode { + KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:7.4.0")).withKraft() // } ) { kafka.start(); diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index 516cc7bb736..7965ece91ba 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -3,16 +3,9 @@ description = "Testcontainers :: Localstack" dependencies { api project(':testcontainers') - testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.418' - testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.418' - testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.418' - testImplementation 'software.amazon.awssdk:s3:2.20.15' + testImplementation 'com.amazonaws:aws-java-sdk-s3:1.12.446' + testImplementation 'com.amazonaws:aws-java-sdk-sqs:1.12.441' + testImplementation 'com.amazonaws:aws-java-sdk-logs:1.12.446' + testImplementation 'software.amazon.awssdk:s3:2.20.38' testImplementation 'org.assertj:assertj-core:3.24.2' } - -tasks.japicmp { - methodExcludes = [ - "org.testcontainers.containers.localstack.LocalStackContainer#getEndpointConfiguration(org.testcontainers.containers.localstack.LocalStackContainer\$Service)", - "org.testcontainers.containers.localstack.LocalStackContainer#getDefaultCredentialsProvider()" - ] -} diff --git a/modules/mariadb/build.gradle b/modules/mariadb/build.gradle index c9c14ea72d3..697544c9e4f 100644 --- a/modules/mariadb/build.gradle +++ b/modules/mariadb/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'org.mariadb:r2dbc-mariadb:1.0.3' testImplementation project(':jdbc-test') - testImplementation 'org.mariadb.jdbc:mariadb-java-client:3.1.2' + testImplementation 'org.mariadb.jdbc:mariadb-java-client:3.1.3' testImplementation testFixtures(project(':r2dbc')) testImplementation 'org.mariadb:r2dbc-mariadb:1.0.3' diff --git a/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java b/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java index 8b39d5d3763..374cf2d928d 100644 --- a/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java +++ b/modules/mockserver/src/main/java/org/testcontainers/containers/MockServerContainer.java @@ -36,7 +36,7 @@ public MockServerContainer(DockerImageName dockerImageName) { super(dockerImageName); dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME, DockerImageName.parse("mockserver/mockserver")); - waitingFor(Wait.forHttp("/mockserver/status").withMethod("PUT").forStatusCode(200)); + waitingFor(Wait.forLogMessage(".*started on port: " + PORT + ".*", 1)); withCommand("-serverPort " + PORT); addExposedPorts(PORT); @@ -46,6 +46,10 @@ public String getEndpoint() { return String.format("http://%s:%d", getHost(), getMappedPort(PORT)); } + public String getSecureEndpoint() { + return String.format("https://%s:%d", getHost(), getMappedPort(PORT)); + } + public Integer getServerPort() { return getMappedPort(PORT); } diff --git a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java index c7225cfe1c2..3f4a8fef293 100644 --- a/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java +++ b/modules/mockserver/src/test/java/org/testcontainers/containers/MockServerContainerTest.java @@ -33,6 +33,53 @@ public void shouldCallActualMockserverVersion() throws Exception { } } + @Test + public void shouldCallMockserverUsingTlsProtocol() throws Exception { + try (MockServerContainer mockServer = new MockServerContainer(MOCKSERVER_IMAGE)) { + mockServer.start(); + + String expectedBody = "Hello World!"; + + try ( + MockServerClient client = new MockServerClient(mockServer.getHost(), mockServer.getServerPort()) + .withSecure(true) + ) { + assertThat(client.hasStarted()).as("Mockserver running").isTrue(); + + client.when(request().withPath("/hello")).respond(response().withBody(expectedBody)); + + assertThat(SimpleHttpClient.secureResponseFromMockserver(mockServer, "/hello")) + .as("MockServer returns correct result") + .isEqualTo(expectedBody); + } + } + } + + @Test + public void shouldCallMockserverUsingMutualTlsProtocol() throws Exception { + try ( + MockServerContainer mockServer = new MockServerContainer(MOCKSERVER_IMAGE) + .withEnv("MOCKSERVER_TLS_MUTUAL_AUTHENTICATION_REQUIRED", "true") + ) { + mockServer.start(); + + String expectedBody = "Hello World!"; + + try ( + MockServerClient client = new MockServerClient(mockServer.getHost(), mockServer.getServerPort()) + .withSecure(true) + ) { + assertThat(client.hasStarted()).as("Mockserver running").isTrue(); + + client.when(request().withPath("/hello")).respond(response().withBody(expectedBody)); + + assertThat(SimpleHttpClient.secureResponseFromMockserver(mockServer, "/hello")) + .as("MockServer returns correct result") + .isEqualTo(expectedBody); + } + } + } + @Test public void newVersionStartsWithDefaultWaitStrategy() { try (MockServerContainer mockServer = new MockServerContainer(MOCKSERVER_IMAGE)) { diff --git a/modules/mockserver/src/test/java/org/testcontainers/containers/SimpleHttpClient.java b/modules/mockserver/src/test/java/org/testcontainers/containers/SimpleHttpClient.java index da60ca9396a..6c7e75c4622 100644 --- a/modules/mockserver/src/test/java/org/testcontainers/containers/SimpleHttpClient.java +++ b/modules/mockserver/src/test/java/org/testcontainers/containers/SimpleHttpClient.java @@ -1,6 +1,9 @@ package org.testcontainers.containers; import lombok.Cleanup; +import org.mockserver.configuration.Configuration; +import org.mockserver.logging.MockServerLogger; +import org.mockserver.socket.tls.KeyStoreFactory; import java.io.BufferedReader; import java.io.IOException; @@ -8,6 +11,8 @@ import java.net.URL; import java.net.URLConnection; +import javax.net.ssl.HttpsURLConnection; + public class SimpleHttpClient { public static String responseFromMockserver(MockServerContainer mockServer, String path) throws IOException { @@ -16,4 +21,21 @@ public static String responseFromMockserver(MockServerContainer mockServer, Stri BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); return reader.readLine(); } + + public static String secureResponseFromMockserver(MockServerContainer mockServer, String path) throws IOException { + HttpsURLConnection httpUrlConnection = (HttpsURLConnection) new URL(mockServer.getSecureEndpoint() + path) + .openConnection(); + try { + httpUrlConnection.setSSLSocketFactory( + new KeyStoreFactory(Configuration.configuration(), new MockServerLogger()) + .sslContext() + .getSocketFactory() + ); + @Cleanup + BufferedReader reader = new BufferedReader(new InputStreamReader(httpUrlConnection.getInputStream())); + return reader.readLine(); + } finally { + httpUrlConnection.disconnect(); + } + } } diff --git a/modules/mongodb/build.gradle b/modules/mongodb/build.gradle index db56db32977..ddc346dd90b 100644 --- a/modules/mongodb/build.gradle +++ b/modules/mongodb/build.gradle @@ -6,9 +6,3 @@ dependencies { testImplementation("org.mongodb:mongodb-driver-sync:4.9.0") testImplementation 'org.assertj:assertj-core:3.24.2' } - -tasks.japicmp { - methodExcludes = [ - "org.testcontainers.containers.MongoDBContainer#containerIsStarted(com.github.dockerjava.api.command.InspectContainerResponse)" - ] -} diff --git a/modules/mysql/build.gradle b/modules/mysql/build.gradle index 395af69604a..bc2af87bcec 100644 --- a/modules/mysql/build.gradle +++ b/modules/mysql/build.gradle @@ -15,5 +15,5 @@ dependencies { testImplementation testFixtures(project(':r2dbc')) testImplementation 'dev.miku:r2dbc-mysql:0.8.2.RELEASE' - compileOnly 'org.jetbrains:annotations:24.0.0' + compileOnly 'org.jetbrains:annotations:24.0.1' } diff --git a/modules/nginx/build.gradle b/modules/nginx/build.gradle index 8a3e319b125..fa26b67237d 100644 --- a/modules/nginx/build.gradle +++ b/modules/nginx/build.gradle @@ -2,6 +2,6 @@ description = "Testcontainers :: Nginx" dependencies { api project(':testcontainers') - compileOnly 'org.jetbrains:annotations:24.0.0' + compileOnly 'org.jetbrains:annotations:24.0.1' testImplementation 'org.assertj:assertj-core:3.24.2' } diff --git a/modules/oracle-xe/build.gradle b/modules/oracle-xe/build.gradle index 7eccc7972e6..c1f44bb9427 100644 --- a/modules/oracle-xe/build.gradle +++ b/modules/oracle-xe/build.gradle @@ -10,9 +10,9 @@ dependencies { compileOnly 'com.oracle.database.r2dbc:oracle-r2dbc:1.0.0' testImplementation project(':jdbc-test') - testImplementation 'com.oracle.database.jdbc:ojdbc11:21.5.0.0' + testImplementation 'com.oracle.database.jdbc:ojdbc11:21.9.0.0' - compileOnly 'org.jetbrains:annotations:24.0.0' + compileOnly 'org.jetbrains:annotations:24.0.1' testImplementation testFixtures(project(':r2dbc')) testImplementation 'com.oracle.database.r2dbc:oracle-r2dbc:1.0.0' diff --git a/modules/orientdb/build.gradle b/modules/orientdb/build.gradle index 04a1a09b805..a2162787e3c 100644 --- a/modules/orientdb/build.gradle +++ b/modules/orientdb/build.gradle @@ -3,9 +3,9 @@ description = "TestContainers :: Orientdb" dependencies { api project(":testcontainers") - api "com.orientechnologies:orientdb-client:3.2.16" + api "com.orientechnologies:orientdb-client:3.2.17" testImplementation 'org.assertj:assertj-core:3.24.2' testImplementation 'org.apache.tinkerpop:gremlin-driver:3.6.2' - testImplementation "com.orientechnologies:orientdb-gremlin:3.2.16" + testImplementation "com.orientechnologies:orientdb-gremlin:3.2.17" } diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index b0ae02fd9b6..b21f21d4e68 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -10,10 +10,10 @@ dependencies { compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.13.RELEASE' testImplementation project(':jdbc-test') - testImplementation 'org.postgresql:postgresql:42.5.4' + testImplementation 'org.postgresql:postgresql:42.6.0' testImplementation testFixtures(project(':r2dbc')) testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.13.RELEASE' - compileOnly 'org.jetbrains:annotations:24.0.0' + compileOnly 'org.jetbrains:annotations:24.0.1' } diff --git a/modules/presto/build.gradle b/modules/presto/build.gradle index 7d5bde5a64d..63441839eb0 100644 --- a/modules/presto/build.gradle +++ b/modules/presto/build.gradle @@ -5,5 +5,5 @@ dependencies { testImplementation project(':jdbc-test') testImplementation 'io.prestosql:presto-jdbc:350' - compileOnly 'org.jetbrains:annotations:24.0.0' + compileOnly 'org.jetbrains:annotations:24.0.1' } diff --git a/modules/pulsar/build.gradle b/modules/pulsar/build.gradle index c4419a523d3..9cd1ef66474 100644 --- a/modules/pulsar/build.gradle +++ b/modules/pulsar/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Pulsar" dependencies { api project(':testcontainers') - testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '2.11.0' + testImplementation group: 'org.apache.pulsar', name: 'pulsar-client', version: '3.0.0' testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.24.2' - testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '2.11.0' + testImplementation group: 'org.apache.pulsar', name: 'pulsar-client-admin', version: '3.0.0' } diff --git a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java index 950149e3226..a47aa04447a 100644 --- a/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java +++ b/modules/pulsar/src/main/java/org/testcontainers/containers/PulsarContainer.java @@ -30,7 +30,7 @@ public class PulsarContainer extends GenericContainer { private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("apachepulsar/pulsar"); @Deprecated - private static final String DEFAULT_TAG = "2.10.0"; + private static final String DEFAULT_TAG = "3.0.0"; private final WaitAllStrategy waitAllStrategy = new WaitAllStrategy(); diff --git a/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java b/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java index b054c30d0ac..29321afca82 100644 --- a/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java +++ b/modules/pulsar/src/test/java/org/testcontainers/containers/PulsarContainerTest.java @@ -1,5 +1,6 @@ package org.testcontainers.containers; +import org.apache.pulsar.client.admin.ListTopicsOptions; import org.apache.pulsar.client.admin.PulsarAdmin; import org.apache.pulsar.client.admin.PulsarAdminException; import org.apache.pulsar.client.api.Consumer; @@ -13,6 +14,7 @@ import org.testcontainers.utility.DockerImageName; import java.time.Duration; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -23,14 +25,14 @@ public class PulsarContainerTest { public static final String TEST_TOPIC = "test_topic"; - private static final DockerImageName PULSAR_IMAGE = DockerImageName.parse("apachepulsar/pulsar:2.10.0"); + private static final DockerImageName PULSAR_IMAGE = DockerImageName.parse("apachepulsar/pulsar:3.0.0"); @Test public void testUsage() throws Exception { try ( // do not use PULSAR_IMAGE to make the doc looks easier // constructorWithVersion { - PulsarContainer pulsar = new PulsarContainer(DockerImageName.parse("apachepulsar/pulsar:2.10.0")); + PulsarContainer pulsar = new PulsarContainer(DockerImageName.parse("apachepulsar/pulsar:3.0.0")); // } ) { pulsar.start(); @@ -103,31 +105,26 @@ public void testTransactions() throws Exception { pulsar.start(); try (PulsarAdmin pulsarAdmin = PulsarAdmin.builder().serviceHttpUrl(pulsar.getHttpServiceUrl()).build()) { - assertThat( - pulsarAdmin - .topics() - .getList("pulsar/system") - .contains("persistent://pulsar/system/transaction_coordinator_assign-partition-0") - ) - .isTrue(); + assertTransactionsTopicCreated(pulsarAdmin); } testTransactionFunctionality(pulsar.getPulsarBrokerUrl()); } } + private void assertTransactionsTopicCreated(PulsarAdmin pulsarAdmin) throws PulsarAdminException { + final List topics = pulsarAdmin + .topics() + .getPartitionedTopicList("pulsar/system", ListTopicsOptions.builder().includeSystemTopic(true).build()); + assertThat(topics).contains("persistent://pulsar/system/transaction_coordinator_assign"); + } + @Test public void testTransactionsAndFunctionsWorker() throws Exception { try (PulsarContainer pulsar = new PulsarContainer(PULSAR_IMAGE).withTransactions().withFunctionsWorker()) { pulsar.start(); try (PulsarAdmin pulsarAdmin = PulsarAdmin.builder().serviceHttpUrl(pulsar.getHttpServiceUrl()).build();) { - assertThat( - pulsarAdmin - .topics() - .getList("pulsar/system") - .contains("persistent://pulsar/system/transaction_coordinator_assign-partition-0") - ) - .isTrue(); + assertTransactionsTopicCreated(pulsarAdmin); assertThat(pulsarAdmin.functions().getFunctions("public", "default")).hasSize(0); } testTransactionFunctionality(pulsar.getPulsarBrokerUrl()); diff --git a/modules/questdb/build.gradle b/modules/questdb/build.gradle index 3ff8525a340..88826ccb237 100644 --- a/modules/questdb/build.gradle +++ b/modules/questdb/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':testcontainers') api project(':jdbc') - testImplementation 'org.postgresql:postgresql:42.5.4' + testImplementation 'org.postgresql:postgresql:42.6.0' testImplementation project(':jdbc-test') testImplementation 'org.assertj:assertj-core:3.24.2' testImplementation 'org.questdb:questdb:7.0.1-jdk8' diff --git a/modules/r2dbc/build.gradle b/modules/r2dbc/build.gradle index cd542677e43..5d8db9abec1 100644 --- a/modules/r2dbc/build.gradle +++ b/modules/r2dbc/build.gradle @@ -15,6 +15,6 @@ dependencies { testImplementation 'io.r2dbc:r2dbc-postgresql:0.8.13.RELEASE' testImplementation project(':postgresql') - testFixturesImplementation 'io.projectreactor:reactor-core:3.5.3' + testFixturesImplementation 'io.projectreactor:reactor-core:3.5.4' testFixturesImplementation 'org.assertj:assertj-core:3.24.2' } diff --git a/modules/rabbitmq/build.gradle b/modules/rabbitmq/build.gradle index 0623e3e6982..bcbeb2bb39c 100644 --- a/modules/rabbitmq/build.gradle +++ b/modules/rabbitmq/build.gradle @@ -2,7 +2,7 @@ description = "TestContainers :: RabbitMQ" dependencies { api project(":testcontainers") - testImplementation 'com.rabbitmq:amqp-client:5.16.0' + testImplementation 'com.rabbitmq:amqp-client:5.17.0' testImplementation 'org.assertj:assertj-core:3.24.2' - compileOnly 'org.jetbrains:annotations:24.0.0' + compileOnly 'org.jetbrains:annotations:24.0.1' } diff --git a/modules/redpanda/src/main/java/org/testcontainers/redpanda/RedpandaContainer.java b/modules/redpanda/src/main/java/org/testcontainers/redpanda/RedpandaContainer.java index 61a36784766..ac232aed4d3 100644 --- a/modules/redpanda/src/main/java/org/testcontainers/redpanda/RedpandaContainer.java +++ b/modules/redpanda/src/main/java/org/testcontainers/redpanda/RedpandaContainer.java @@ -55,7 +55,7 @@ protected void containerIsStarting(InspectContainerResponse containerInfo) { String command = "#!/bin/bash\n"; - command += "/usr/bin/rpk redpanda start --mode dev-container "; + command += "/usr/bin/rpk redpanda start --mode dev-container --overprovisioned --smp 1 "; command += "--kafka-addr PLAINTEXT://0.0.0.0:29092,OUTSIDE://0.0.0.0:9092 "; command += "--advertise-kafka-addr PLAINTEXT://127.0.0.1:29092,OUTSIDE://" + getHost() + ":" + getMappedPort(9092); diff --git a/modules/selenium/build.gradle b/modules/selenium/build.gradle index f98b6fc0cee..330ff3d937c 100644 --- a/modules/selenium/build.gradle +++ b/modules/selenium/build.gradle @@ -6,12 +6,12 @@ dependencies { provided 'org.seleniumhq.selenium:selenium-remote-driver:4.6.0' provided 'org.seleniumhq.selenium:selenium-chrome-driver:4.6.0' testImplementation 'org.seleniumhq.selenium:selenium-firefox-driver:4.6.0' - testImplementation 'org.seleniumhq.selenium:selenium-edge-driver:4.8.1' + testImplementation 'org.seleniumhq.selenium:selenium-edge-driver:4.8.3' testImplementation 'org.seleniumhq.selenium:selenium-support:4.6.0' testImplementation 'org.mortbay.jetty:jetty:6.1.26' testImplementation project(':nginx') testImplementation 'org.assertj:assertj-core:3.24.2' - compileOnly 'org.jetbrains:annotations:24.0.0' + compileOnly 'org.jetbrains:annotations:24.0.1' } diff --git a/modules/solace/build.gradle b/modules/solace/build.gradle index dc92cdd58ce..3cfcaac8442 100644 --- a/modules/solace/build.gradle +++ b/modules/solace/build.gradle @@ -6,7 +6,7 @@ dependencies { shaded 'org.awaitility:awaitility:4.2.0' testImplementation 'org.assertj:assertj-core:3.24.2' - testImplementation 'com.solacesystems:sol-jcsmp:10.18.0' + testImplementation 'com.solacesystems:sol-jcsmp:10.19.0' testImplementation 'org.apache.qpid:qpid-jms-client:0.61.0' testImplementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5' testImplementation 'org.apache.httpcomponents:fluent-hc:4.5.14' diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index a4c09f5ffd8..3e3815198c8 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -15,12 +15,12 @@ dependencies { testImplementation 'com.zaxxer:HikariCP:4.0.3' testImplementation 'org.apache.httpcomponents:httpclient:4.5.14' - testRuntimeOnly 'org.postgresql:postgresql:42.5.4' + testRuntimeOnly 'org.postgresql:postgresql:42.6.0' testRuntimeOnly 'mysql:mysql-connector-java:8.0.32' testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.9.2' testRuntimeOnly 'org.junit.platform:junit-platform-testkit:1.9.2' - testCompileOnly 'org.jetbrains:annotations:24.0.0' + testCompileOnly 'org.jetbrains:annotations:24.0.1' } sourceJar { diff --git a/modules/tidb/build.gradle b/modules/tidb/build.gradle index dabcf3cba26..b1105a3e2b0 100644 --- a/modules/tidb/build.gradle +++ b/modules/tidb/build.gradle @@ -6,5 +6,5 @@ dependencies { testImplementation project(':jdbc-test') testImplementation 'mysql:mysql-connector-java:8.0.32' - compileOnly 'org.jetbrains:annotations:24.0.0' + compileOnly 'org.jetbrains:annotations:24.0.1' } diff --git a/modules/trino/build.gradle b/modules/trino/build.gradle index de022d95faf..2b3ccb11a87 100644 --- a/modules/trino/build.gradle +++ b/modules/trino/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testImplementation 'io.trino:trino-jdbc:408' + testImplementation 'io.trino:trino-jdbc:411' compileOnly 'org.jetbrains:annotations:24.0.0' } diff --git a/modules/yugabytedb/build.gradle b/modules/yugabytedb/build.gradle index fa68ba41241..a84b49c1a71 100644 --- a/modules/yugabytedb/build.gradle +++ b/modules/yugabytedb/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') // YCQL driver - testImplementation 'com.yugabyte:java-driver-core:4.6.0-yb-11' + testImplementation 'com.yugabyte:java-driver-core:4.6.0-yb-12' // YSQL driver testImplementation 'com.yugabyte:jdbc-yugabytedb:42.3.5-yb-2' } diff --git a/settings.gradle b/settings.gradle index 9b44be57333..f0e3769d92f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,8 +5,8 @@ buildscript { } } dependencies { - classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.12.3" - classpath "com.gradle:common-custom-user-data-gradle-plugin:1.8.2" + classpath "com.gradle.enterprise:com.gradle.enterprise.gradle.plugin:3.12.6" + classpath "com.gradle:common-custom-user-data-gradle-plugin:1.10" classpath "org.gradle.toolchains:foojay-resolver:0.4.0" } }