From d3d10854a9b116f379dee63310d4dbaa9f36e0f2 Mon Sep 17 00:00:00 2001 From: Yonathan Negussie Mengesha Date: Thu, 1 Feb 2024 16:29:05 +0100 Subject: [PATCH 0001/1430] Fix HiveMQ logo (#8215) --- docs/modules/hivemq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/hivemq.md b/docs/modules/hivemq.md index 2ebdd7a9ad8..c898d58fea8 100644 --- a/docs/modules/hivemq.md +++ b/docs/modules/hivemq.md @@ -1,6 +1,6 @@ # HiveMQ Module -drawing +![hivemq logo](../modules_logos/hivemq-module.png) Automatic starting HiveMQ docker containers for JUnit4 and JUnit5 tests. This enables testing MQTT client applications and integration testing of custom HiveMQ extensions. From 853f657be4c0b1b930b0c298cdc10288f0ac7521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Wed, 7 Feb 2024 14:25:31 -0500 Subject: [PATCH 0002/1430] Increase maximum heap size (#8283) --- gradle.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gradle.properties b/gradle.properties index 4fb587917e9..294a32b507d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,6 @@ org.gradle.parallel=false org.gradle.caching=true org.gradle.configureondemand=true +org.gradle.jvmargs=-Xmx2g + testcontainers.version=1.19.4 From c210afb0b0944d1a96b7a760f93d6601a9058173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Wed, 7 Feb 2024 15:40:01 -0500 Subject: [PATCH 0003/1430] Downgrade commons-compress version to 1.24.0 (#8284) Fixes #8169 --- .github/dependabot.yml | 2 ++ core/build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e3506109406..80a8780f6b2 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -20,6 +20,8 @@ updates: update-types: [ "version-update:semver-major" ] - dependency-name: "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" update-types: [ "version-update:semver-minor", "version-update:semver-patch" ] + - dependency-name: "org.apache.commons:commons-compress" + update-types: [ "version-update:semver-minor" ] - package-ecosystem: "gradle" directory: "/" allow: diff --git a/core/build.gradle b/core/build.gradle index 07cd1932d5a..102d3997b8a 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -73,7 +73,7 @@ dependencies { api 'org.slf4j:slf4j-api:1.7.36' compileOnly 'org.jetbrains:annotations:24.1.0' testCompileOnly 'org.jetbrains:annotations:24.1.0' - api 'org.apache.commons:commons-compress:1.25.0' + api 'org.apache.commons:commons-compress:1.24.0' api ('org.rnorth.duct-tape:duct-tape:1.0.8') { exclude(group: 'org.jetbrains', module: 'annotations') } From 96f19edbd2f9431ca5303c12676f05b999f3c5f3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 10:12:34 -0500 Subject: [PATCH 0004/1430] [create-pull-request] automated change (#8301) Co-authored-by: eddumelendez --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 294a32b507d..cbe03a25ae3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,4 +3,4 @@ org.gradle.caching=true org.gradle.configureondemand=true org.gradle.jvmargs=-Xmx2g -testcontainers.version=1.19.4 +testcontainers.version=1.19.5 From e9cb44c32eb0e1e775fc1f40deeb79cd536177e0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 10:12:49 -0500 Subject: [PATCH 0005/1430] [create-pull-request] automated change (#8300) Co-authored-by: eddumelendez --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index de6030812e6..548efdaf945 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -124,4 +124,4 @@ nav: - bounty.md edit_uri: edit/main/docs/ extra: - latest_version: 1.19.4 + latest_version: 1.19.5 From b1b27c3f7c0c1bfac7333eec1d17535aecb49948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Mon, 12 Feb 2024 12:21:50 -0500 Subject: [PATCH 0006/1430] Fix neo4j custom password docs --- .../java/org/testcontainers/containers/Neo4jContainerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java index 5341b10c599..bdf3639a271 100644 --- a/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java +++ b/modules/neo4j/src/test/java/org/testcontainers/containers/Neo4jContainerTest.java @@ -191,7 +191,7 @@ public void shouldRespectEnvironmentAuth() { @Test public void shouldSetCustomPasswordCorrectly() { - // withoutAuthentication { + // withAdminPassword { Neo4jContainer neo4jContainer = new Neo4jContainer<>("neo4j:4.4").withAdminPassword("verySecret"); // } From a69750c3d796777770bec1920018917dac792e14 Mon Sep 17 00:00:00 2001 From: Christoph Dreis Date: Mon, 12 Feb 2024 21:30:21 +0100 Subject: [PATCH 0007/1430] Remove unused charset constant in GenericContainer (#8304) --- .../java/org/testcontainers/containers/GenericContainer.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 8e2b00d0adb..aff46f3b110 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -71,7 +71,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.UndeclaredThrowableException; -import java.nio.charset.Charset; import java.nio.file.Path; import java.nio.file.Paths; import java.time.Duration; @@ -112,8 +111,6 @@ public class GenericContainer> extends FailureDetectingExternalResource implements Container, AutoCloseable, WaitStrategyTarget, Startable { - private static final Charset UTF8 = Charset.forName("UTF-8"); - public static final int CONTAINER_RUNNING_TIMEOUT_SEC = 30; public static final String INTERNAL_HOST_HOSTNAME = "host.testcontainers.internal"; From a1ea7e07a3e65dfab113e590b7648d89a2424f8a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 22:27:08 +0000 Subject: [PATCH 0008/1430] Bump org.apache.solr:solr-solrj from 8.11.2 to 8.11.3 in /modules/solr Bumps org.apache.solr:solr-solrj from 8.11.2 to 8.11.3. --- updated-dependencies: - dependency-name: org.apache.solr:solr-solrj dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/solr/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/solr/build.gradle b/modules/solr/build.gradle index d4305686141..f4b3c4ac6b3 100644 --- a/modules/solr/build.gradle +++ b/modules/solr/build.gradle @@ -5,6 +5,6 @@ dependencies { // TODO use JDK's HTTP client and/or Apache HttpClient5 shaded 'com.squareup.okhttp3:okhttp:4.12.0' - testImplementation 'org.apache.solr:solr-solrj:8.11.2' + testImplementation 'org.apache.solr:solr-solrj:8.11.3' testImplementation 'org.assertj:assertj-core:3.25.1' } From bd532c30f21a3f1140870cce0e93ab0826da452c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 22:44:23 +0000 Subject: [PATCH 0009/1430] Bump org.apache.solr:solr-solrj from 8.11.2 to 8.11.3 in /examples Bumps org.apache.solr:solr-solrj from 8.11.2 to 8.11.3. --- updated-dependencies: - dependency-name: org.apache.solr:solr-solrj dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- examples/solr-container/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/solr-container/build.gradle b/examples/solr-container/build.gradle index 739a418c995..22873b34a18 100644 --- a/examples/solr-container/build.gradle +++ b/examples/solr-container/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly "org.projectlombok:lombok:1.18.30" annotationProcessor "org.projectlombok:lombok:1.18.30" - implementation 'org.apache.solr:solr-solrj:8.11.2' + implementation 'org.apache.solr:solr-solrj:8.11.3' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.testcontainers:solr' From 0623f1a04d8a32ccf96ca670f22a4bf3994f4da2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Fri, 16 Feb 2024 23:49:53 -0500 Subject: [PATCH 0010/1430] Update Gradle GHA (#8322) --- .github/actions/setup-gradle/action.yml | 2 +- .github/workflows/ci-rootless.yml | 2 +- .github/workflows/ci.yml | 6 +++--- .github/workflows/release.yml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/actions/setup-gradle/action.yml b/.github/actions/setup-gradle/action.yml index 58499f75e57..3cb582c0cf8 100644 --- a/.github/actions/setup-gradle/action.yml +++ b/.github/actions/setup-gradle/action.yml @@ -4,7 +4,7 @@ runs: using: "composite" steps: - name: Setup Gradle Build Action - uses: gradle/gradle-build-action@v2 + uses: gradle/actions/setup-gradle@v3 with: gradle-home-cache-includes: | caches diff --git a/.github/workflows/ci-rootless.yml b/.github/workflows/ci-rootless.yml index fccaef5ede7..21ff4f793c6 100644 --- a/.github/workflows/ci-rootless.yml +++ b/.github/workflows/ci-rootless.yml @@ -52,7 +52,7 @@ jobs: - name: Remove Docket root socket run: sudo rm -rf /var/run/docker.sock - name: Setup Gradle Build Action - uses: gradle/gradle-build-action@v2 + uses: gradle/actions/setup-gradle@v3 - name: Build with Gradle run: ./gradlew --no-daemon --scan testcontainers:test --tests '*GenericContainerRuleTest' - uses: ./.github/actions/setup-junit-report diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 15b1240904b..8e07cd76218 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,7 +87,7 @@ jobs: - uses: actions/checkout@v4 - uses: ./.github/actions/setup-java - name: Setup Gradle Build Action - uses: gradle/gradle-build-action@v2 + uses: gradle/actions/setup-gradle@v3 - id: set-matrix env: # Since we override the tests executor, @@ -122,7 +122,7 @@ jobs: - uses: actions/checkout@v4 - uses: ./.github/actions/setup-java - name: Setup Gradle Build Action - uses: gradle/gradle-build-action@v2 + uses: gradle/actions/setup-gradle@v3 - id: set-matrix working-directory: ./examples/ env: @@ -159,7 +159,7 @@ jobs: - uses: actions/checkout@v4 - uses: ./.github/actions/setup-java - name: Setup Gradle Build Action - uses: gradle/gradle-build-action@v2 + uses: gradle/actions/setup-gradle@v3 - id: set-matrix env: # Since we override the tests executor, diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0fbd63cdbd1..79a0d6856b1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: run: docker image prune -af - name: Setup Gradle Build Action - uses: gradle/gradle-build-action@v2 + uses: gradle/actions/setup-gradle@v3 - name: Run Gradle Build run: ./gradlew build --scan --no-daemon -i -x test From 40378973203b0971fea83d641d3c7e6ecb553b91 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 17 Feb 2024 04:50:42 +0000 Subject: [PATCH 0011/1430] Bump release-drafter/release-drafter from 5.25.0 to 6.0.0 Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 5.25.0 to 6.0.0. - [Release notes](https://github.com/release-drafter/release-drafter/releases) - [Commits](https://github.com/release-drafter/release-drafter/compare/09c613e259eb8d4e7c81c2cb00618eb5fc4575a7...3f0f87098bd6b5c5b9a36d49c41d998ea58f9348) --- updated-dependencies: - dependency-name: release-drafter/release-drafter dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index acbea174645..43e9773f19e 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -18,6 +18,6 @@ jobs: if: github.repository == 'testcontainers/testcontainers-java' runs-on: ubuntu-latest steps: - - uses: release-drafter/release-drafter@09c613e259eb8d4e7c81c2cb00618eb5fc4575a7 # v5.19.0 + - uses: release-drafter/release-drafter@3f0f87098bd6b5c5b9a36d49c41d998ea58f9348 # v5.19.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From b06885fd89973ae7d9ff396737beeac27fddc06c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Mon, 19 Feb 2024 13:41:43 -0500 Subject: [PATCH 0012/1430] Update docker-java version to 3.3.5 (#8325) --- core/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 102d3997b8a..a318ff00b10 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -88,8 +88,8 @@ dependencies { shaded 'org.awaitility:awaitility:4.2.0' - api platform('com.github.docker-java:docker-java-bom:3.3.4') - shaded platform('com.github.docker-java:docker-java-bom:3.3.4') + api platform('com.github.docker-java:docker-java-bom:3.3.5') + shaded platform('com.github.docker-java:docker-java-bom:3.3.5') api "com.github.docker-java:docker-java-api" From 329e972af94b642b286f201d42bf6f3fbe3aa0c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 20 Feb 2024 12:44:45 -0500 Subject: [PATCH 0013/1430] Improve postgres docs (#8340) Display how to use other compatible images such as `pgvector`, `postgis`, `timescaledb`. --- docs/modules/databases/postgres.md | 22 +++++++ .../containers/CompatibleImageTest.java | 64 +++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 modules/postgresql/src/test/java/org/testcontainers/containers/CompatibleImageTest.java diff --git a/docs/modules/databases/postgres.md b/docs/modules/databases/postgres.md index b7632d78293..d07e77937b9 100644 --- a/docs/modules/databases/postgres.md +++ b/docs/modules/databases/postgres.md @@ -2,6 +2,28 @@ See [Database containers](./index.md) for documentation and usage that is common to all relational database container types. +## Compatible images + +`PostgreSQLContainer` can also be used with the following images: + +* [pgvector/pgvector](https://hub.docker.com/r/pgvector/pgvector) + + +[Using pgvector](../../../modules/postgresql/src/test/java/org/testcontainers/containers/CompatibleImageTest.java) inside_block:pgvectorContainer + + +* [postgis/postgis](https://registry.hub.docker.com/r/postgis/postgis) + + +[Using PostGIS](../../../modules/postgresql/src/test/java/org/testcontainers/containers/CompatibleImageTest.java) inside_block:postgisContainer + + +* [timescale/timescaledb](https://hub.docker.com/r/timescale/timescaledb) + + +[Using TimescaleDB](../../../modules/postgresql/src/test/java/org/testcontainers/containers/CompatibleImageTest.java) inside_block:timescaledbContainer + + ## Adding this module to your project dependencies Add the following dependency to your `pom.xml`/`build.gradle` file: diff --git a/modules/postgresql/src/test/java/org/testcontainers/containers/CompatibleImageTest.java b/modules/postgresql/src/test/java/org/testcontainers/containers/CompatibleImageTest.java new file mode 100644 index 00000000000..2bb1c6c3d54 --- /dev/null +++ b/modules/postgresql/src/test/java/org/testcontainers/containers/CompatibleImageTest.java @@ -0,0 +1,64 @@ +package org.testcontainers.containers; + +import org.junit.Test; +import org.testcontainers.db.AbstractContainerDatabaseTest; +import org.testcontainers.utility.DockerImageName; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CompatibleImageTest extends AbstractContainerDatabaseTest { + + @Test + public void pgvector() throws SQLException { + try ( + // pgvectorContainer { + PostgreSQLContainer pgvector = new PostgreSQLContainer<>( + DockerImageName.parse("pgvector/pgvector:pg16").asCompatibleSubstituteFor("postgres") + ) + // } + ) { + pgvector.start(); + + ResultSet resultSet = performQuery(pgvector, "SELECT 1"); + int resultSetInt = resultSet.getInt(1); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); + } + } + + @Test + public void postgis() throws SQLException { + try ( + // postgisContainer { + PostgreSQLContainer postgis = new PostgreSQLContainer<>( + DockerImageName.parse("postgis/postgis:16-3.4-alpine").asCompatibleSubstituteFor("postgres") + ) + // } + ) { + postgis.start(); + + ResultSet resultSet = performQuery(postgis, "SELECT 1"); + int resultSetInt = resultSet.getInt(1); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); + } + } + + @Test + public void timescaledb() throws SQLException { + try ( + // timescaledbContainer { + PostgreSQLContainer timescaledb = new PostgreSQLContainer<>( + DockerImageName.parse("timescale/timescaledb:2.14.2-pg16").asCompatibleSubstituteFor("postgres") + ) + // } + ) { + timescaledb.start(); + + ResultSet resultSet = performQuery(timescaledb, "SELECT 1"); + int resultSetInt = resultSet.getInt(1); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); + } + } +} From f45bb444f0bbe54d791058bb015547ba2919beab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 20 Feb 2024 12:46:01 -0500 Subject: [PATCH 0014/1430] Add Weaviate module (#8337) --- .github/ISSUE_TEMPLATE/bug_report.yaml | 1 + .github/ISSUE_TEMPLATE/enhancement.yaml | 1 + .github/ISSUE_TEMPLATE/feature.yaml | 1 + .github/dependabot.yml | 5 +++ .github/labeler.yml | 4 +++ .github/settings.yml | 3 ++ docs/modules/weaviate.md | 30 ++++++++++++++++ mkdocs.yml | 1 + modules/weaviate/build.gradle | 8 +++++ .../weaviate/WeaviateContainer.java | 36 +++++++++++++++++++ .../weaviate/WeaviateContainerTest.java | 25 +++++++++++++ .../src/test/resources/logback-test.xml | 16 +++++++++ 12 files changed, 131 insertions(+) create mode 100644 docs/modules/weaviate.md create mode 100644 modules/weaviate/build.gradle create mode 100644 modules/weaviate/src/main/java/org/testcontainers/weaviate/WeaviateContainer.java create mode 100644 modules/weaviate/src/test/java/org/testcontainers/weaviate/WeaviateContainerTest.java create mode 100644 modules/weaviate/src/test/resources/logback-test.xml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 81e3dbbd900..a140ad15285 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -55,6 +55,7 @@ body: - ToxiProxy - Trino - Vault + - Weaviate - YugabyteDB validations: required: true diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml index d073f8f1674..7c60044546f 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yaml +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -55,6 +55,7 @@ body: - ToxiProxy - Trino - Vault + - Weaviate - YugabyteDB validations: required: true diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index dedccecd4e5..91c750ef7f8 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -55,6 +55,7 @@ body: - ToxiProxy - Trino - Vault + - Weaviate - YugabyteDB - New Module - type: textarea diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 80a8780f6b2..7111d36c2a6 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -302,6 +302,11 @@ updates: schedule: interval: "weekly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/weaviate" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/yugabytedb" schedule: diff --git a/.github/labeler.yml b/.github/labeler.yml index e3bce388744..0960bf74461 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -192,6 +192,10 @@ - changed-files: - any-glob-to-any-file: - modules/vault/**/* +"modules/weaviate": + - changed-files: + - any-glob-to-any-file: + - modules/weaviate/**/* "modules/yugabytedb": - changed-files: - any-glob-to-any-file: diff --git a/.github/settings.yml b/.github/settings.yml index 3047612d756..aa3b62b90fe 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -238,6 +238,9 @@ labels: - name: modules/vault color: '#006b75' + - name: modules/weaviate + color: '#006b75' + - name: modules/yugabytedb color: '#006b75' diff --git a/docs/modules/weaviate.md b/docs/modules/weaviate.md new file mode 100644 index 00000000000..da028cf3ce1 --- /dev/null +++ b/docs/modules/weaviate.md @@ -0,0 +1,30 @@ +# Weaviate + +Testcontainers module for [Weaviate](https://hub.docker.com/r/semitechnologies/weaviate) + +## WeaviateContainer's usage examples + +You can start a Weaviate container instance from any Java application by using: + + +[Default Weaviate container](../../modules/weaviate/src/test/java/org/testcontainers/weaviate/WeaviateContainerTest.java) inside_block:container + + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +=== "Gradle" +```groovy +testImplementation "org.testcontainers:weaviate:{{latest_version}}" +``` + +=== "Maven" +```xml + +org.testcontainers +weaviate +{{latest_version}} +test + +``` diff --git a/mkdocs.yml b/mkdocs.yml index 548efdaf945..86cfd3a823a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -93,6 +93,7 @@ nav: - modules/solr.md - modules/toxiproxy.md - modules/vault.md + - modules/weaviate.md - modules/webdriver_containers.md - Test framework integration: - test_framework_integration/junit_4.md diff --git a/modules/weaviate/build.gradle b/modules/weaviate/build.gradle new file mode 100644 index 00000000000..06a77aa434a --- /dev/null +++ b/modules/weaviate/build.gradle @@ -0,0 +1,8 @@ +description = "Testcontainers :: Weaviate" + +dependencies { + api project(':testcontainers') + + testImplementation 'org.assertj:assertj-core:3.25.1' + testImplementation 'io.weaviate:client:4.5.1' +} diff --git a/modules/weaviate/src/main/java/org/testcontainers/weaviate/WeaviateContainer.java b/modules/weaviate/src/main/java/org/testcontainers/weaviate/WeaviateContainer.java new file mode 100644 index 00000000000..bd217b13e75 --- /dev/null +++ b/modules/weaviate/src/main/java/org/testcontainers/weaviate/WeaviateContainer.java @@ -0,0 +1,36 @@ +package org.testcontainers.weaviate; + +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; + +/** + * Testcontainers implementation of Weaviate. + *

+ * Supported image: {@code semitechnologies/weaviate} + *

+ * Exposed ports: + *

    + *
  • HTTP: 8080
  • + *
  • gRPC: 50051
  • + *
+ */ +public class WeaviateContainer extends GenericContainer { + + private static final String WEAVIATE_IMAGE = "semitechnologies/weaviate"; + + public WeaviateContainer(String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public WeaviateContainer(DockerImageName dockerImageName) { + super(dockerImageName); + dockerImageName.assertCompatibleWith(DockerImageName.parse(WEAVIATE_IMAGE)); + withExposedPorts(8080, 50051); + withEnv("AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED", "true"); + withEnv("PERSISTENCE_DATA_PATH", "/var/lib/weaviate"); + } + + public String getHttpHostAddress() { + return getHost() + ":" + getMappedPort(8080); + } +} diff --git a/modules/weaviate/src/test/java/org/testcontainers/weaviate/WeaviateContainerTest.java b/modules/weaviate/src/test/java/org/testcontainers/weaviate/WeaviateContainerTest.java new file mode 100644 index 00000000000..562fc36de51 --- /dev/null +++ b/modules/weaviate/src/test/java/org/testcontainers/weaviate/WeaviateContainerTest.java @@ -0,0 +1,25 @@ +package org.testcontainers.weaviate; + +import io.weaviate.client.Config; +import io.weaviate.client.WeaviateClient; +import io.weaviate.client.base.Result; +import io.weaviate.client.v1.misc.model.Meta; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class WeaviateContainerTest { + + @Test + public void test() { + try ( // container { + WeaviateContainer weaviate = new WeaviateContainer("semitechnologies/weaviate:1.22.4") + // } + ) { + weaviate.start(); + WeaviateClient client = new WeaviateClient(new Config("http", weaviate.getHttpHostAddress())); + Result meta = client.misc().metaGetter().run(); + assertThat(meta.getResult().getVersion()).isEqualTo("1.22.4"); + } + } +} diff --git a/modules/weaviate/src/test/resources/logback-test.xml b/modules/weaviate/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..83ef7a1a3ef --- /dev/null +++ b/modules/weaviate/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + From 2c5244db397c7ec2ca03fcc5c7e8cff7211ce384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 20 Feb 2024 12:46:27 -0500 Subject: [PATCH 0015/1430] Add ChromaDB module (#8336) --- .github/ISSUE_TEMPLATE/bug_report.yaml | 1 + .github/ISSUE_TEMPLATE/enhancement.yaml | 1 + .github/ISSUE_TEMPLATE/feature.yaml | 1 + .github/dependabot.yml | 5 +++ .github/labeler.yml | 4 +++ .github/settings.yml | 3 ++ docs/modules/chromadb.md | 30 ++++++++++++++++ mkdocs.yml | 1 + modules/chromadb/build.gradle | 8 +++++ .../chromadb/ChromaDBContainer.java | 34 +++++++++++++++++++ .../chromadb/ChromaDBContainerTest.java | 30 ++++++++++++++++ .../src/test/resources/logback-test.xml | 16 +++++++++ 12 files changed, 134 insertions(+) create mode 100644 docs/modules/chromadb.md create mode 100644 modules/chromadb/build.gradle create mode 100644 modules/chromadb/src/main/java/org/testcontainers/chromadb/ChromaDBContainer.java create mode 100644 modules/chromadb/src/test/java/org/testcontainers/chromadb/ChromaDBContainerTest.java create mode 100644 modules/chromadb/src/test/resources/logback-test.xml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index a140ad15285..216076ee084 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -17,6 +17,7 @@ body: - ActiveMQ - Azure - Cassandra + - ChromaDB - Clickhouse - CockroachDB - Consul diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml index 7c60044546f..80b20178318 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yaml +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -17,6 +17,7 @@ body: - ActiveMQ - Azure - Cassandra + - ChromaDB - Clickhouse - CockroachDB - Consul diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index 91c750ef7f8..96af8c19ea7 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -17,6 +17,7 @@ body: - ActiveMQ - Azure - Cassandra + - ChromaDB - Clickhouse - CockroachDB - CrateDB diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 7111d36c2a6..4f81e37b26b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -51,6 +51,11 @@ updates: ignore: - dependency-name: "io.dropwizard.metrics:metrics-core" update-types: [ "version-update:semver-major" ] + - package-ecosystem: "gradle" + directory: "/modules/chromadb" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/clickhouse" schedule: diff --git a/.github/labeler.yml b/.github/labeler.yml index 0960bf74461..70e69146d25 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -27,6 +27,10 @@ - changed-files: - any-glob-to-any-file: - modules/cassandra/**/* +"modules/chromadb": + - changed-files: + - any-glob-to-any-file: + - modules/chromadb/**/* "modules/clickhouse": - changed-files: - any-glob-to-any-file: diff --git a/.github/settings.yml b/.github/settings.yml index aa3b62b90fe..12629f2f355 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -115,6 +115,9 @@ labels: - name: modules/cassandra color: '#006b75' + - name: modules/chromadb + color: '#006b75' + - name: modules/clickhouse color: '#006b75' diff --git a/docs/modules/chromadb.md b/docs/modules/chromadb.md new file mode 100644 index 00000000000..9b14dfc2970 --- /dev/null +++ b/docs/modules/chromadb.md @@ -0,0 +1,30 @@ +# ChromaDB + +Testcontainers module for [ChromaDB](https://registry.hub.docker.com/r/chromadb/chroma) + +## ChromaDB's usage examples + +You can start a ChromaDB container instance from any Java application by using: + + +[Default ChromaDB container](../../modules/chromadb/src/test/java/org/testcontainers/chromadb/ChromaDBContainerTest.java) inside_block:container + + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +=== "Gradle" +```groovy +testImplementation "org.testcontainers:chromadb:{{latest_version}}" +``` + +=== "Maven" +```xml + +org.testcontainers +chromadb +{{latest_version}} +test + +``` diff --git a/mkdocs.yml b/mkdocs.yml index 86cfd3a823a..cda56106885 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -75,6 +75,7 @@ nav: - modules/databases/yugabytedb.md - modules/activemq.md - modules/azure.md + - modules/chromadb.md - modules/consul.md - modules/docker_compose.md - modules/elasticsearch.md diff --git a/modules/chromadb/build.gradle b/modules/chromadb/build.gradle new file mode 100644 index 00000000000..2b170c21570 --- /dev/null +++ b/modules/chromadb/build.gradle @@ -0,0 +1,8 @@ +description = "Testcontainers :: ChromaDB" + +dependencies { + api project(':testcontainers') + + testImplementation 'org.assertj:assertj-core:3.25.1' + testImplementation 'io.rest-assured:rest-assured:5.4.0' +} diff --git a/modules/chromadb/src/main/java/org/testcontainers/chromadb/ChromaDBContainer.java b/modules/chromadb/src/main/java/org/testcontainers/chromadb/ChromaDBContainer.java new file mode 100644 index 00000000000..a1bccf3904f --- /dev/null +++ b/modules/chromadb/src/main/java/org/testcontainers/chromadb/ChromaDBContainer.java @@ -0,0 +1,34 @@ +package org.testcontainers.chromadb; + +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; + +/** + * Testcontainers implementation of ChromaDB. + *

+ * Supported images: {@code chromadb/chroma}, {@code ghcr.io/chroma-core/chroma} + *

+ * Exposed ports: 8000 + */ +public class ChromaDBContainer extends GenericContainer { + + private static final DockerImageName DEFAULT_DOCKER_IMAGE = DockerImageName.parse("chromadb/chroma"); + + private static final DockerImageName GHCR_DOCKER_IMAGE = DockerImageName.parse("ghcr.io/chroma-core/chroma"); + + public ChromaDBContainer(String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public ChromaDBContainer(DockerImageName dockerImageName) { + super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_DOCKER_IMAGE, GHCR_DOCKER_IMAGE); + withExposedPorts(8000); + waitingFor(Wait.forHttp("/api/v1/heartbeat")); + } + + public String getEndpoint() { + return "http://" + getHost() + ":" + getFirstMappedPort(); + } +} diff --git a/modules/chromadb/src/test/java/org/testcontainers/chromadb/ChromaDBContainerTest.java b/modules/chromadb/src/test/java/org/testcontainers/chromadb/ChromaDBContainerTest.java new file mode 100644 index 00000000000..945af0dcbff --- /dev/null +++ b/modules/chromadb/src/test/java/org/testcontainers/chromadb/ChromaDBContainerTest.java @@ -0,0 +1,30 @@ +package org.testcontainers.chromadb; + +import io.restassured.http.ContentType; +import org.junit.Test; + +import static io.restassured.RestAssured.given; + +public class ChromaDBContainerTest { + + @Test + public void test() { + try ( // container { + ChromaDBContainer chroma = new ChromaDBContainer("chromadb/chroma:0.4.22") + // } + ) { + chroma.start(); + + given() + .baseUri(chroma.getEndpoint()) + .when() + .body("{\"name\": \"test\"}") + .contentType(ContentType.JSON) + .post("/api/v1/databases") + .then() + .statusCode(200); + + given().baseUri(chroma.getEndpoint()).when().get("/api/v1/databases/test").then().statusCode(200); + } + } +} diff --git a/modules/chromadb/src/test/resources/logback-test.xml b/modules/chromadb/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..83ef7a1a3ef --- /dev/null +++ b/modules/chromadb/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + From b7fb9456eb985e38208d8d2dfcd0f44ee9fddfaa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Feb 2024 17:46:53 +0000 Subject: [PATCH 0016/1430] Bump org.assertj:assertj-core from 3.25.1 to 3.25.3 in /modules/chromadb Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.25.1 to 3.25.3. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.25.1...assertj-build-3.25.3) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/chromadb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/chromadb/build.gradle b/modules/chromadb/build.gradle index 2b170c21570..f1642346871 100644 --- a/modules/chromadb/build.gradle +++ b/modules/chromadb/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: ChromaDB" dependencies { api project(':testcontainers') - testImplementation 'org.assertj:assertj-core:3.25.1' + testImplementation 'org.assertj:assertj-core:3.25.3' testImplementation 'io.rest-assured:rest-assured:5.4.0' } From 0c9833ba6c8a2eab1344fef9f25318b11f020ba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Wed, 21 Feb 2024 11:39:58 -0500 Subject: [PATCH 0017/1430] Add Milvus module (#8352) --- .github/ISSUE_TEMPLATE/bug_report.yaml | 1 + .github/ISSUE_TEMPLATE/enhancement.yaml | 1 + .github/ISSUE_TEMPLATE/feature.yaml | 1 + .github/dependabot.yml | 5 ++ .github/labeler.yml | 4 ++ .github/settings.yml | 3 + docs/modules/milvus.md | 36 ++++++++++ mkdocs.yml | 1 + modules/milvus/build.gradle | 8 +++ .../milvus/MilvusContainer.java | 61 +++++++++++++++++ .../resources/testcontainers/embedEtcd.yaml | 2 + .../milvus/MilvusContainerTest.java | 66 +++++++++++++++++++ .../src/test/resources/logback-test.xml | 16 +++++ 13 files changed, 205 insertions(+) create mode 100644 docs/modules/milvus.md create mode 100644 modules/milvus/build.gradle create mode 100644 modules/milvus/src/main/java/org/testcontainers/milvus/MilvusContainer.java create mode 100644 modules/milvus/src/main/resources/testcontainers/embedEtcd.yaml create mode 100644 modules/milvus/src/test/java/org/testcontainers/milvus/MilvusContainerTest.java create mode 100644 modules/milvus/src/test/resources/logback-test.xml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 216076ee084..d7c304a2cd4 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -33,6 +33,7 @@ body: - Kafka - LocalStack - MariaDB + - Milvus - MinIO - MockServer - MongoDB diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml index 80b20178318..2bc0e8a3e20 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yaml +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -33,6 +33,7 @@ body: - Kafka - LocalStack - MariaDB + - Milvus - MinIO - MockServer - MongoDB diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index 96af8c19ea7..02310b638e1 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -33,6 +33,7 @@ body: - Kafka - LocalStack - MariaDB + - Milvus - MinIO - MockServer - MongoDB diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4f81e37b26b..24ced388caf 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -166,6 +166,11 @@ updates: ignore: - dependency-name: "org.mariadb:r2dbc-mariadb" update-types: [ "version-update:semver-minor" ] + - package-ecosystem: "gradle" + directory: "/modules/milvus" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/minio" schedule: diff --git a/.github/labeler.yml b/.github/labeler.yml index 70e69146d25..b7c1aa2ac01 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -99,6 +99,10 @@ - changed-files: - any-glob-to-any-file: - modules/mariadb/**/* +"modules/milvus": + - changed-files: + - any-glob-to-any-file: + - modules/milvus/**/* "modules/minio": - changed-files: - any-glob-to-any-file: diff --git a/.github/settings.yml b/.github/settings.yml index 12629f2f355..fdf582198d2 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -169,6 +169,9 @@ labels: - name: modules/mariadb color: '#006b75' + - name: modules/milvus + color: '#006b75' + - name: modules/minio color: '#006b75' diff --git a/docs/modules/milvus.md b/docs/modules/milvus.md new file mode 100644 index 00000000000..2808f9d2199 --- /dev/null +++ b/docs/modules/milvus.md @@ -0,0 +1,36 @@ +# Milvus + +Testcontainers module for [Milvus](https://hub.docker.com/r/milvusdb/milvus). + +## Milvus's usage examples + +You can start a Milvus container instance from any Java application by using: + + +[Default config](../../modules/milvus/src/test/java/org/testcontainers/milvus/MilvusContainerTest.java) inside_block:milvusContainer + + +With external Etcd: + + +[External Etcd](../../modules/milvus/src/test/java/org/testcontainers/milvus/MilvusContainerTest.java) inside_block:externalEtcd + + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:milvus:{{latest_version}}" + ``` + +=== "Maven" + ```xml + + org.testcontainers + milvus + {{latest_version}} + test + + ``` diff --git a/mkdocs.yml b/mkdocs.yml index cda56106885..bcd53d294d9 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -84,6 +84,7 @@ nav: - modules/k3s.md - modules/kafka.md - modules/localstack.md + - modules/milvus.md - modules/minio.md - modules/mockserver.md - modules/nginx.md diff --git a/modules/milvus/build.gradle b/modules/milvus/build.gradle new file mode 100644 index 00000000000..8826e6764ba --- /dev/null +++ b/modules/milvus/build.gradle @@ -0,0 +1,8 @@ +description = "Testcontainers :: ActiveMQ" + +dependencies { + api project(':testcontainers') + + testImplementation 'org.assertj:assertj-core:3.25.1' + testImplementation 'io.milvus:milvus-sdk-java:2.3.4' +} diff --git a/modules/milvus/src/main/java/org/testcontainers/milvus/MilvusContainer.java b/modules/milvus/src/main/java/org/testcontainers/milvus/MilvusContainer.java new file mode 100644 index 00000000000..57b1b483cf8 --- /dev/null +++ b/modules/milvus/src/main/java/org/testcontainers/milvus/MilvusContainer.java @@ -0,0 +1,61 @@ +package org.testcontainers.milvus; + +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +/** + * Testcontainers implementation for Milvus. + *

+ * Supported image: {@code milvusdb/milvus} + *

+ * Exposed ports: + *

    + *
  • Management port: 9091
  • + *
  • HTTP: 19530
  • + *
+ */ +public class MilvusContainer extends GenericContainer { + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("milvusdb/milvus"); + + private String etcdEndpoint; + + public MilvusContainer(String image) { + this(DockerImageName.parse(image)); + } + + public MilvusContainer(DockerImageName dockerImageName) { + super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + withExposedPorts(9091, 19530); + waitingFor(Wait.forHttp("/healthz").forPort(9091)); + withCommand("milvus", "run", "standalone"); + withCopyFileToContainer( + MountableFile.forClasspathResource("testcontainers/embedEtcd.yaml"), + "/milvus/configs/embedEtcd.yaml" + ); + withEnv("COMMON_STORAGETYPE", "local"); + } + + @Override + protected void configure() { + if (this.etcdEndpoint == null) { + withEnv("ETCD_USE_EMBED", "true"); + withEnv("ETCD_DATA_DIR", "/var/lib/milvus/etcd"); + withEnv("ETCD_CONFIG_PATH", "/milvus/configs/embedEtcd.yaml"); + } else { + withEnv("ETCD_ENDPOINTS", this.etcdEndpoint); + } + } + + public MilvusContainer withEtcdEndpoint(String etcdEndpoint) { + this.etcdEndpoint = etcdEndpoint; + return this; + } + + public String getEndpoint() { + return "http://" + getHost() + ":" + getMappedPort(19530); + } +} diff --git a/modules/milvus/src/main/resources/testcontainers/embedEtcd.yaml b/modules/milvus/src/main/resources/testcontainers/embedEtcd.yaml new file mode 100644 index 00000000000..2bd73bbd59f --- /dev/null +++ b/modules/milvus/src/main/resources/testcontainers/embedEtcd.yaml @@ -0,0 +1,2 @@ +listen-client-urls: http://0.0.0.0:2379 +advertise-client-urls: http://0.0.0.0:2379 diff --git a/modules/milvus/src/test/java/org/testcontainers/milvus/MilvusContainerTest.java b/modules/milvus/src/test/java/org/testcontainers/milvus/MilvusContainerTest.java new file mode 100644 index 00000000000..3a6d6275ec2 --- /dev/null +++ b/modules/milvus/src/test/java/org/testcontainers/milvus/MilvusContainerTest.java @@ -0,0 +1,66 @@ +package org.testcontainers.milvus; + +import io.milvus.client.MilvusServiceClient; +import io.milvus.param.ConnectParam; +import org.junit.Test; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.Network; +import org.testcontainers.containers.wait.strategy.Wait; + +import static org.assertj.core.api.Assertions.assertThat; + +public class MilvusContainerTest { + + @Test + public void withDefaultConfig() { + try ( + // milvusContainer { + MilvusContainer milvus = new MilvusContainer("milvusdb/milvus:v2.3.9") + // } + ) { + milvus.start(); + + assertThat(milvus.getEnvMap()).doesNotContainKey("ETCD_ENDPOINTS"); + assertMilvusVersion(milvus); + } + } + + @Test + public void withExternalEtcd() { + try ( + // externalEtcd { + Network network = Network.newNetwork(); + GenericContainer etcd = new GenericContainer<>("quay.io/coreos/etcd:v3.5.5") + .withNetwork(network) + .withNetworkAliases("etcd") + .withCommand( + "etcd", + "-advertise-client-urls=http://127.0.0.1:2379", + "-listen-client-urls=http://0.0.0.0:2379", + "--data-dir=/etcd" + ) + .withEnv("ETCD_AUTO_COMPACTION_MODE", "revision") + .withEnv("ETCD_AUTO_COMPACTION_RETENTION", "1000") + .withEnv("ETCD_QUOTA_BACKEND_BYTES", "4294967296") + .withEnv("ETCD_SNAPSHOT_COUNT", "50000") + .waitingFor(Wait.forLogMessage(".*ready to serve client requests.*", 1)); + MilvusContainer milvus = new MilvusContainer("milvusdb/milvus:v2.3.9") + .withNetwork(network) + .withEtcdEndpoint("etcd:2379") + .dependsOn(etcd) + // } + ) { + milvus.start(); + + assertThat(milvus.getEnvMap()).doesNotContainKey("ETCD_USE_EMBED"); + assertMilvusVersion(milvus); + } + } + + private static void assertMilvusVersion(MilvusContainer milvus) { + MilvusServiceClient milvusClient = new MilvusServiceClient( + ConnectParam.newBuilder().withUri(milvus.getEndpoint()).build() + ); + assertThat(milvusClient.getVersion().getData().getVersion()).isEqualTo("v2.3.9"); + } +} diff --git a/modules/milvus/src/test/resources/logback-test.xml b/modules/milvus/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..83ef7a1a3ef --- /dev/null +++ b/modules/milvus/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + From 2c987eec1bbae7eb4d7469dfa048bd4fae379a92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Wed, 21 Feb 2024 13:52:04 -0500 Subject: [PATCH 0018/1430] Add Qdrant module (#8353) Co-authored-by: Anush --- .github/ISSUE_TEMPLATE/bug_report.yaml | 1 + .github/ISSUE_TEMPLATE/enhancement.yaml | 1 + .github/ISSUE_TEMPLATE/feature.yaml | 1 + .github/dependabot.yml | 5 +++ .github/labeler.yml | 4 +++ .github/settings.yml | 3 ++ docs/modules/qdrant.md | 30 ++++++++++++++++ mkdocs.yml | 1 + modules/qdrant/build.gradle | 12 +++++++ .../qdrant/QdrantContainer.java | 36 +++++++++++++++++++ .../qdrant/QdrantContainerTest.java | 36 +++++++++++++++++++ .../src/test/resources/logback-test.xml | 16 +++++++++ 12 files changed, 146 insertions(+) create mode 100644 docs/modules/qdrant.md create mode 100644 modules/qdrant/build.gradle create mode 100644 modules/qdrant/src/main/java/org/testcontainers/qdrant/QdrantContainer.java create mode 100644 modules/qdrant/src/test/java/org/testcontainers/qdrant/QdrantContainerTest.java create mode 100644 modules/qdrant/src/test/resources/logback-test.xml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index d7c304a2cd4..8d363cb978f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -47,6 +47,7 @@ body: - PostgreSQL - Presto - Pulsar + - Qdrant - QuestDB - RabbitMQ - Redpanda diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml index 2bc0e8a3e20..6ee160c982b 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yaml +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -47,6 +47,7 @@ body: - PostgreSQL - Presto - Pulsar + - Qdrant - QuestDB - RabbitMQ - Redpanda diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index 02310b638e1..3f8920b4059 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -45,6 +45,7 @@ body: - Oracle XE - OrientDB - PostgreSQL + - Qdrant - QuestDB - Presto - Pulsar diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 24ced388caf..bf9b145f2b3 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -240,6 +240,11 @@ updates: schedule: interval: "weekly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/qdrant" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/questdb" schedule: diff --git a/.github/labeler.yml b/.github/labeler.yml index b7c1aa2ac01..0fd1ec90d29 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -152,6 +152,10 @@ - changed-files: - any-glob-to-any-file: - modules/pulsar/**/* +"modules/qdrant": + - changed-files: + - any-glob-to-any-file: + - modules/qdrant/**/* "modules/questdb": - changed-files: - any-glob-to-any-file: diff --git a/.github/settings.yml b/.github/settings.yml index fdf582198d2..a4589aab643 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -205,6 +205,9 @@ labels: - name: modules/pulsar color: '#006b75' + - name: modules/qdrant + color: '#006b75' + - name: modules/questdb color: '#006b75' diff --git a/docs/modules/qdrant.md b/docs/modules/qdrant.md new file mode 100644 index 00000000000..25aef090c97 --- /dev/null +++ b/docs/modules/qdrant.md @@ -0,0 +1,30 @@ +# Qdrant + +Testcontainers module for [Qdrant](https://registry.hub.docker.com/r/qdrant/qdrant) + +## Qdrant's usage examples + +You can start a Qdrant container instance from any Java application by using: + + +[Default QDrant container](../../modules/qdrant/src/test/java/org/testcontainers/qdrant/QdrantContainerTest.java) inside_block:qdrantContainer + + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:qdrant:{{latest_version}}" + ``` + +=== "Maven" + ```xml + + org.testcontainers + qdrant + {{latest_version}} + test + + ``` diff --git a/mkdocs.yml b/mkdocs.yml index bcd53d294d9..67974735281 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -89,6 +89,7 @@ nav: - modules/mockserver.md - modules/nginx.md - modules/pulsar.md + - modules/qdrant.md - modules/rabbitmq.md - modules/redpanda.md - modules/solace.md diff --git a/modules/qdrant/build.gradle b/modules/qdrant/build.gradle new file mode 100644 index 00000000000..cc856e1d970 --- /dev/null +++ b/modules/qdrant/build.gradle @@ -0,0 +1,12 @@ +description = "Testcontainers :: Qdrant" + +dependencies { + api project(':testcontainers') + + testImplementation 'org.assertj:assertj-core:3.25.1' + testImplementation 'io.qdrant:client:1.7.1' + testImplementation platform('io.grpc:grpc-bom:1.61.1') + testImplementation 'io.grpc:grpc-stub' + testImplementation 'io.grpc:grpc-protobuf' + testImplementation 'io.grpc:grpc-netty-shaded' +} diff --git a/modules/qdrant/src/main/java/org/testcontainers/qdrant/QdrantContainer.java b/modules/qdrant/src/main/java/org/testcontainers/qdrant/QdrantContainer.java new file mode 100644 index 00000000000..341349fe18c --- /dev/null +++ b/modules/qdrant/src/main/java/org/testcontainers/qdrant/QdrantContainer.java @@ -0,0 +1,36 @@ +package org.testcontainers.qdrant; + +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; + +/** + * Testcontainers implementation for Qdrant. + *

+ * Supported image: {@code qdrant/qdrant} + *

+ * Exposed ports: + *

    + *
  • HTTP: 6333
  • + *
  • Grpc: 6334
  • + *
+ */ +public class QdrantContainer extends GenericContainer { + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("qdrant/qdrant"); + + public QdrantContainer(String image) { + this(DockerImageName.parse(image)); + } + + public QdrantContainer(DockerImageName dockerImageName) { + super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + withExposedPorts(6333, 6334); + waitingFor(Wait.forHttp("/readyz").forPort(6333)); + } + + public String getGrpcHostAddress() { + return getHost() + ":" + getMappedPort(6334); + } +} diff --git a/modules/qdrant/src/test/java/org/testcontainers/qdrant/QdrantContainerTest.java b/modules/qdrant/src/test/java/org/testcontainers/qdrant/QdrantContainerTest.java new file mode 100644 index 00000000000..e33582bf552 --- /dev/null +++ b/modules/qdrant/src/test/java/org/testcontainers/qdrant/QdrantContainerTest.java @@ -0,0 +1,36 @@ +package org.testcontainers.qdrant; + +import io.grpc.Grpc; +import io.grpc.InsecureChannelCredentials; +import io.qdrant.client.QdrantGrpcClient; +import io.qdrant.client.grpc.QdrantOuterClass; +import org.junit.Test; + +import java.util.concurrent.ExecutionException; + +import static org.assertj.core.api.Assertions.assertThat; + +public class QdrantContainerTest { + + @Test + public void test() throws ExecutionException, InterruptedException { + try ( + // qdrantContainer { + QdrantContainer qdrant = new QdrantContainer("qdrant/qdrant:v1.7.4") + // } + ) { + qdrant.start(); + + QdrantGrpcClient client = QdrantGrpcClient + .newBuilder( + Grpc.newChannelBuilder(qdrant.getGrpcHostAddress(), InsecureChannelCredentials.create()).build() + ) + .build(); + QdrantOuterClass.HealthCheckReply healthCheckReply = client + .qdrant() + .healthCheck(QdrantOuterClass.HealthCheckRequest.getDefaultInstance()) + .get(); + assertThat(healthCheckReply.getVersion()).isEqualTo("1.7.4"); + } + } +} diff --git a/modules/qdrant/src/test/resources/logback-test.xml b/modules/qdrant/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..83ef7a1a3ef --- /dev/null +++ b/modules/qdrant/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + From 0fd331a12bd14de7186ad8af062e4c5e7d265a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Wed, 21 Feb 2024 15:05:56 -0600 Subject: [PATCH 0019/1430] Fix Milvus description --- modules/milvus/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/milvus/build.gradle b/modules/milvus/build.gradle index 8826e6764ba..9da171def57 100644 --- a/modules/milvus/build.gradle +++ b/modules/milvus/build.gradle @@ -1,4 +1,4 @@ -description = "Testcontainers :: ActiveMQ" +description = "Testcontainers :: Milvus" dependencies { api project(':testcontainers') From 60aacca34a8b1ada84992b3ff9ff53683d6f196a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 21 Feb 2024 18:07:38 -0500 Subject: [PATCH 0020/1430] [create-pull-request] automated change (#8364) Co-authored-by: eddumelendez --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index cbe03a25ae3..26b4b4f0c26 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,4 +3,4 @@ org.gradle.caching=true org.gradle.configureondemand=true org.gradle.jvmargs=-Xmx2g -testcontainers.version=1.19.5 +testcontainers.version=1.19.6 From ef43682bcda26dae644289bf81cea322a07999a3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 21 Feb 2024 18:07:52 -0500 Subject: [PATCH 0021/1430] [create-pull-request] automated change (#8365) Co-authored-by: eddumelendez --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 67974735281..784159e8e57 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -128,4 +128,4 @@ nav: - bounty.md edit_uri: edit/main/docs/ extra: - latest_version: 1.19.5 + latest_version: 1.19.6 From 7bedef7ea7900a96448e3148757dc69067275228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Sun, 25 Feb 2024 21:02:18 -0500 Subject: [PATCH 0022/1430] Add OpenFGA module (#8371) Fixes #8367 --- .github/ISSUE_TEMPLATE/bug_report.yaml | 1 + .github/ISSUE_TEMPLATE/enhancement.yaml | 1 + .github/ISSUE_TEMPLATE/feature.yaml | 1 + .github/dependabot.yml | 4 ++ .github/labeler.yml | 4 ++ .github/settings.yml | 3 ++ docs/modules/openfga.md | 30 +++++++++++++ mkdocs.yml | 1 + modules/openfga/build.gradle | 21 +++++++++ .../openfga/OpenFGAContainer.java | 45 +++++++++++++++++++ .../openfga/OpenFGAContainerTest.java | 33 ++++++++++++++ .../src/test/resources/logback-test.xml | 16 +++++++ 12 files changed, 160 insertions(+) create mode 100644 docs/modules/openfga.md create mode 100644 modules/openfga/build.gradle create mode 100644 modules/openfga/src/main/java/org/testcontainers/openfga/OpenFGAContainer.java create mode 100644 modules/openfga/src/test/java/org/testcontainers/openfga/OpenFGAContainerTest.java create mode 100644 modules/openfga/src/test/resources/logback-test.xml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 8d363cb978f..027a7adc170 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -41,6 +41,7 @@ body: - MySQL - Neo4j - NGINX + - OpenFGA - Oracle Free - Oracle XE - OrientDB diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml index 6ee160c982b..c2f6d7504e8 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yaml +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -41,6 +41,7 @@ body: - MySQL - Neo4j - NGINX + - OpenFGA - Oracle Free - Oracle XE - OrientDB diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index 3f8920b4059..3a03aa09bdd 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -41,6 +41,7 @@ body: - MySQL - Neo4j - NGINX + - OpenFGA - Oracle Free - Oracle XE - OrientDB diff --git a/.github/dependabot.yml b/.github/dependabot.yml index bf9b145f2b3..163bf2db040 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -211,6 +211,10 @@ updates: schedule: interval: "weekly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/openfga" + schedule: + interval: "weekly" - package-ecosystem: "gradle" directory: "/modules/oracle-free" schedule: diff --git a/.github/labeler.yml b/.github/labeler.yml index 0fd1ec90d29..c7eec3b4a6a 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -131,6 +131,10 @@ - changed-files: - any-glob-to-any-file: - modules/nginx/**/* +"modules/openfga": + - changed-files: + - any-glob-to-any-file: + - modules/openfga/**/* "modules/oracle": - changed-files: - any-glob-to-any-file: diff --git a/.github/settings.yml b/.github/settings.yml index a4589aab643..c7458f63fc3 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -190,6 +190,9 @@ labels: - name: modules/nginx color: '#006b75' + - name: modules/openfga + color: '#006b75' + - name: modules/oracle color: '#006b75' diff --git a/docs/modules/openfga.md b/docs/modules/openfga.md new file mode 100644 index 00000000000..e11cae3560a --- /dev/null +++ b/docs/modules/openfga.md @@ -0,0 +1,30 @@ +# OpenFGA + +Testcontainers module for [OpenFGA](https://hub.docker.com/r/"openfga/openfga). + +## OpenFGAContainer's usage examples + +You can start an OpenFGA container instance from any Java application by using: + + +[OpenFGA container](../../modules/openfga/src/test/java/org/testcontainers/openfga/OpenFGAContainerTest.java) inside_block:container + + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:openfga:{{latest_version}}" + ``` + +=== "Maven" + ```xml + + org.testcontainers + openfga + {{latest_version}} + test + + ``` diff --git a/mkdocs.yml b/mkdocs.yml index 784159e8e57..d51576a0bf6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -88,6 +88,7 @@ nav: - modules/minio.md - modules/mockserver.md - modules/nginx.md + - modules/openfga.md - modules/pulsar.md - modules/qdrant.md - modules/rabbitmq.md diff --git a/modules/openfga/build.gradle b/modules/openfga/build.gradle new file mode 100644 index 00000000000..9824603d5bd --- /dev/null +++ b/modules/openfga/build.gradle @@ -0,0 +1,21 @@ +description = "Testcontainers :: OpenFGA" + +dependencies { + api project(':testcontainers') + + testImplementation 'org.assertj:assertj-core:3.25.1' + testImplementation 'dev.openfga:openfga-sdk:0.3.2' +} + +test { + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(11) + } +} + +compileTestJava { + javaCompiler = javaToolchains.compilerFor { + languageVersion = JavaLanguageVersion.of(11) + } + options.release.set(11) +} diff --git a/modules/openfga/src/main/java/org/testcontainers/openfga/OpenFGAContainer.java b/modules/openfga/src/main/java/org/testcontainers/openfga/OpenFGAContainer.java new file mode 100644 index 00000000000..986e385c0d3 --- /dev/null +++ b/modules/openfga/src/main/java/org/testcontainers/openfga/OpenFGAContainer.java @@ -0,0 +1,45 @@ +package org.testcontainers.openfga; + +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; + +/** + * Testcontainers implementation for OpenFGA. + *

+ * Supported image: {@code openfga/openfga} + *

+ * Exposed ports: + *

    + *
  • Playground: 3000
  • + *
  • HTTP: 8080
  • + *
  • gRPC: 8081
  • + *
+ */ +public class OpenFGAContainer extends GenericContainer { + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("openfga/openfga"); + + public OpenFGAContainer(String image) { + this(DockerImageName.parse(image)); + } + + public OpenFGAContainer(DockerImageName dockerImageName) { + super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + + withExposedPorts(3000, 8080, 8081); + withCommand("run"); + waitingFor( + Wait.forHttp("/healthz").forPort(8080).forResponsePredicate(response -> response.contains("SERVING")) + ); + } + + public String getHttpEndpoint() { + return "http://" + getHost() + ":" + getMappedPort(8080); + } + + public String getGrpcEndpoint() { + return "http://" + getHost() + ":" + getMappedPort(8081); + } +} diff --git a/modules/openfga/src/test/java/org/testcontainers/openfga/OpenFGAContainerTest.java b/modules/openfga/src/test/java/org/testcontainers/openfga/OpenFGAContainerTest.java new file mode 100644 index 00000000000..688d4d31f10 --- /dev/null +++ b/modules/openfga/src/test/java/org/testcontainers/openfga/OpenFGAContainerTest.java @@ -0,0 +1,33 @@ +package org.testcontainers.openfga; + +import dev.openfga.sdk.api.client.OpenFgaClient; +import dev.openfga.sdk.api.client.model.ClientCreateStoreResponse; +import dev.openfga.sdk.api.configuration.ClientConfiguration; +import dev.openfga.sdk.api.model.CreateStoreRequest; +import dev.openfga.sdk.errors.FgaInvalidParameterException; +import org.junit.Test; + +import java.util.concurrent.ExecutionException; + +import static org.assertj.core.api.Assertions.assertThat; + +public class OpenFGAContainerTest { + + @Test + public void withDefaultConfig() throws FgaInvalidParameterException, ExecutionException, InterruptedException { + try ( // container + OpenFGAContainer openfga = new OpenFGAContainer("openfga/openfga:v1.4.3") + // } + ) { + openfga.start(); + + ClientConfiguration config = new ClientConfiguration().apiUrl(openfga.getHttpEndpoint()); + OpenFgaClient client = new OpenFgaClient(config); + + assertThat(client.listStores().get().getStores()).isEmpty(); + ClientCreateStoreResponse store = client.createStore(new CreateStoreRequest().name("test")).get(); + assertThat(store.getId()).isNotNull(); + assertThat(client.listStores().get().getStores()).hasSize(1); + } + } +} diff --git a/modules/openfga/src/test/resources/logback-test.xml b/modules/openfga/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..83ef7a1a3ef --- /dev/null +++ b/modules/openfga/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + From fdcc31c720e7704f6b0c69060c25941abc254739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 27 Feb 2024 18:55:15 -0500 Subject: [PATCH 0023/1430] Support mongodb/mongodb-community-server and mongodb/mongodb-enterprise-server (#8386) --- .../containers/MongoDBContainer.java | 12 ++- .../containers/AbstractMongo.java | 66 ++++++++++++++ .../containers/CompatibleImageTest.java | 66 ++++++++++++++ .../containers/MongoDBContainerTest.java | 91 +------------------ 4 files changed, 146 insertions(+), 89 deletions(-) create mode 100644 modules/mongodb/src/test/java/org/testcontainers/containers/AbstractMongo.java create mode 100644 modules/mongodb/src/test/java/org/testcontainers/containers/CompatibleImageTest.java diff --git a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java index 1e6749f8aed..17adc794530 100644 --- a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java +++ b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java @@ -13,7 +13,7 @@ /** * Testcontainers implementation for MongoDB. *

- * Supported image: {@code mongo} + * Supported images: {@code mongo}, {@code mongodb/mongodb-community-server}, {@code mongodb/mongodb-enterprise-server} *

* Exposed ports: 27017 */ @@ -22,6 +22,14 @@ public class MongoDBContainer extends GenericContainer { private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("mongo"); + private static final DockerImageName COMMUNITY_SERVER_IMAGE = DockerImageName.parse( + "mongodb/mongodb-community-server" + ); + + private static final DockerImageName ENTERPRISE_SERVER_IMAGE = DockerImageName.parse( + "mongodb/mongodb-enterprise-server" + ); + private static final String DEFAULT_TAG = "4.0.10"; private static final int CONTAINER_EXIT_CODE_OK = 0; @@ -48,7 +56,7 @@ public MongoDBContainer(@NonNull final String dockerImageName) { public MongoDBContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME, COMMUNITY_SERVER_IMAGE, ENTERPRISE_SERVER_IMAGE); } @Override diff --git a/modules/mongodb/src/test/java/org/testcontainers/containers/AbstractMongo.java b/modules/mongodb/src/test/java/org/testcontainers/containers/AbstractMongo.java new file mode 100644 index 00000000000..4fe23fbb50c --- /dev/null +++ b/modules/mongodb/src/test/java/org/testcontainers/containers/AbstractMongo.java @@ -0,0 +1,66 @@ +package org.testcontainers.containers; + +import com.mongodb.ReadConcern; +import com.mongodb.ReadPreference; +import com.mongodb.TransactionOptions; +import com.mongodb.WriteConcern; +import com.mongodb.client.ClientSession; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.TransactionBody; +import org.bson.Document; + +import static org.assertj.core.api.Assertions.assertThat; + +public class AbstractMongo { + + protected void executeTx(MongoDBContainer mongoDBContainer) { + final MongoClient mongoSyncClientBase = MongoClients.create(mongoDBContainer.getConnectionString()); + final MongoClient mongoSyncClient = MongoClients.create(mongoDBContainer.getReplicaSetUrl()); + mongoSyncClient + .getDatabase("mydb1") + .getCollection("foo") + .withWriteConcern(WriteConcern.MAJORITY) + .insertOne(new Document("abc", 0)); + mongoSyncClient + .getDatabase("mydb2") + .getCollection("bar") + .withWriteConcern(WriteConcern.MAJORITY) + .insertOne(new Document("xyz", 0)); + mongoSyncClientBase + .getDatabase("mydb3") + .getCollection("baz") + .withWriteConcern(WriteConcern.MAJORITY) + .insertOne(new Document("def", 0)); + + final ClientSession clientSession = mongoSyncClient.startSession(); + final TransactionOptions txnOptions = TransactionOptions + .builder() + .readPreference(ReadPreference.primary()) + .readConcern(ReadConcern.LOCAL) + .writeConcern(WriteConcern.MAJORITY) + .build(); + + final String trxResult = "Inserted into collections in different databases"; + + TransactionBody txnBody = () -> { + final MongoCollection coll1 = mongoSyncClient.getDatabase("mydb1").getCollection("foo"); + final MongoCollection coll2 = mongoSyncClient.getDatabase("mydb2").getCollection("bar"); + + coll1.insertOne(clientSession, new Document("abc", 1)); + coll2.insertOne(clientSession, new Document("xyz", 999)); + return trxResult; + }; + + try { + final String trxResultActual = clientSession.withTransaction(txnBody, txnOptions); + assertThat(trxResultActual).isEqualTo(trxResult); + } catch (RuntimeException re) { + throw new IllegalStateException(re.getMessage(), re); + } finally { + clientSession.close(); + mongoSyncClient.close(); + } + } +} diff --git a/modules/mongodb/src/test/java/org/testcontainers/containers/CompatibleImageTest.java b/modules/mongodb/src/test/java/org/testcontainers/containers/CompatibleImageTest.java new file mode 100644 index 00000000000..8113e508aee --- /dev/null +++ b/modules/mongodb/src/test/java/org/testcontainers/containers/CompatibleImageTest.java @@ -0,0 +1,66 @@ +package org.testcontainers.containers; + +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import org.bson.Document; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(Parameterized.class) +public class CompatibleImageTest extends AbstractMongo { + + private final String image; + + public CompatibleImageTest(String image) { + this.image = image; + } + + @Parameterized.Parameters(name = "{0}") + public static String[] image() { + return new String[] { + "mongo:7", + "mongodb/mongodb-community-server:7.0.2-ubi8", + "mongodb/mongodb-enterprise-server:7.0.0-ubi8", + }; + } + + @Test + public void shouldExecuteTransactions() { + try ( + // creatingMongoDBContainer { + final MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:4.0.10") + // } + ) { + // startingMongoDBContainer { + mongoDBContainer.start(); + // } + executeTx(mongoDBContainer); + } + } + + @Test + public void shouldSupportSharding() { + try (final MongoDBContainer mongoDBContainer = new MongoDBContainer(this.image).withSharding()) { + mongoDBContainer.start(); + final MongoClient mongoClient = MongoClients.create(mongoDBContainer.getReplicaSetUrl()); + + mongoClient.getDatabase("mydb1").getCollection("foo").insertOne(new Document("abc", 0)); + + Document shards = mongoClient.getDatabase("config").getCollection("shards").find().first(); + assertThat(shards).isNotNull(); + assertThat(shards).isNotEmpty(); + assertThat(isReplicaSet(mongoClient)).isFalse(); + } + } + + private boolean isReplicaSet(MongoClient mongoClient) { + return runIsMaster(mongoClient).get("setName") != null; + } + + private Document runIsMaster(MongoClient mongoClient) { + return mongoClient.getDatabase("admin").runCommand(new Document("ismaster", 1)); + } +} diff --git a/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java index f5cb4dd5d90..c801dad5378 100644 --- a/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java +++ b/modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java @@ -1,21 +1,10 @@ package org.testcontainers.containers; -import com.mongodb.ReadConcern; -import com.mongodb.ReadPreference; -import com.mongodb.TransactionOptions; -import com.mongodb.WriteConcern; -import com.mongodb.client.ClientSession; -import com.mongodb.client.MongoClient; -import com.mongodb.client.MongoClients; -import com.mongodb.client.MongoCollection; -import com.mongodb.client.TransactionBody; -import org.bson.Document; import org.junit.Test; -import org.testcontainers.utility.DockerImageName; import static org.assertj.core.api.Assertions.assertThat; -public class MongoDBContainerTest { +public class MongoDBContainerTest extends AbstractMongo { /** * Taken from https://docs.mongodb.com @@ -24,7 +13,7 @@ public class MongoDBContainerTest { public void shouldExecuteTransactions() { try ( // creatingMongoDBContainer { - final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10")) + final MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:4.0.10") // } ) { // startingMongoDBContainer { @@ -34,91 +23,19 @@ public void shouldExecuteTransactions() { } } - private void executeTx(MongoDBContainer mongoDBContainer) { - final MongoClient mongoSyncClientBase = MongoClients.create(mongoDBContainer.getConnectionString()); - final MongoClient mongoSyncClient = MongoClients.create(mongoDBContainer.getReplicaSetUrl()); - mongoSyncClient - .getDatabase("mydb1") - .getCollection("foo") - .withWriteConcern(WriteConcern.MAJORITY) - .insertOne(new Document("abc", 0)); - mongoSyncClient - .getDatabase("mydb2") - .getCollection("bar") - .withWriteConcern(WriteConcern.MAJORITY) - .insertOne(new Document("xyz", 0)); - mongoSyncClientBase - .getDatabase("mydb3") - .getCollection("baz") - .withWriteConcern(WriteConcern.MAJORITY) - .insertOne(new Document("def", 0)); - - final ClientSession clientSession = mongoSyncClient.startSession(); - final TransactionOptions txnOptions = TransactionOptions - .builder() - .readPreference(ReadPreference.primary()) - .readConcern(ReadConcern.LOCAL) - .writeConcern(WriteConcern.MAJORITY) - .build(); - - final String trxResult = "Inserted into collections in different databases"; - - TransactionBody txnBody = () -> { - final MongoCollection coll1 = mongoSyncClient.getDatabase("mydb1").getCollection("foo"); - final MongoCollection coll2 = mongoSyncClient.getDatabase("mydb2").getCollection("bar"); - - coll1.insertOne(clientSession, new Document("abc", 1)); - coll2.insertOne(clientSession, new Document("xyz", 999)); - return trxResult; - }; - - try { - final String trxResultActual = clientSession.withTransaction(txnBody, txnOptions); - assertThat(trxResultActual).isEqualTo(trxResult); - } catch (RuntimeException re) { - throw new IllegalStateException(re.getMessage(), re); - } finally { - clientSession.close(); - mongoSyncClient.close(); - } - } - @Test public void supportsMongoDB_4_4() { - try (final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.4"))) { + try (final MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:4.4")) { mongoDBContainer.start(); } } @Test public void shouldTestDatabaseName() { - try (final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.0.10"))) { + try (final MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:4.0.10")) { mongoDBContainer.start(); final String databaseName = "my-db"; assertThat(mongoDBContainer.getReplicaSetUrl(databaseName)).endsWith(databaseName); } } - - @Test - public void shouldSupportSharding() { - try (final MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:6").withSharding()) { - mongoDBContainer.start(); - final MongoClient mongoClient = MongoClients.create(mongoDBContainer.getReplicaSetUrl()); - - mongoClient.getDatabase("mydb1").getCollection("foo").insertOne(new Document("abc", 0)); - - Document shards = mongoClient.getDatabase("config").getCollection("shards").find().first(); - assertThat(shards).isNotNull(); - assertThat(shards).isNotEmpty(); - assertThat(isReplicaSet(mongoClient)).isFalse(); - } - } - - private boolean isReplicaSet(MongoClient mongoClient) { - return runIsMaster(mongoClient).get("setName") != null; - } - - private Document runIsMaster(MongoClient mongoClient) { - return mongoClient.getDatabase("admin").runCommand(new Document("ismaster", 1)); - } } From baa877033605e218c15f8a1ede1d58887eaf08e9 Mon Sep 17 00:00:00 2001 From: Paul Balogh Date: Tue, 27 Feb 2024 18:19:07 -0600 Subject: [PATCH 0024/1430] Add k6 module (#8318) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Eddú Meléndez --- .github/ISSUE_TEMPLATE/bug_report.yaml | 1 + .github/ISSUE_TEMPLATE/enhancement.yaml | 1 + .github/ISSUE_TEMPLATE/feature.yaml | 1 + .github/dependabot.yml | 8 ++ .github/labeler.yml | 4 + .github/settings.yml | 3 + docs/modules/k6.md | 39 ++++++++ mkdocs.yml | 1 + modules/k6/build.gradle | 7 ++ .../org/testcontainers/k6/K6Container.java | 88 +++++++++++++++++++ .../testcontainers/k6/K6ContainerTests.java | 41 +++++++++ .../k6/src/test/resources/logback-test.xml | 16 ++++ modules/k6/src/test/resources/scripts/test.js | 6 ++ 13 files changed, 216 insertions(+) create mode 100644 docs/modules/k6.md create mode 100644 modules/k6/build.gradle create mode 100644 modules/k6/src/main/java/org/testcontainers/k6/K6Container.java create mode 100644 modules/k6/src/test/java/org/testcontainers/k6/K6ContainerTests.java create mode 100644 modules/k6/src/test/resources/logback-test.xml create mode 100644 modules/k6/src/test/resources/scripts/test.js diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 027a7adc170..abb8b0f7901 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -30,6 +30,7 @@ body: - HiveMQ - InfluxDB - K3S + - K6 - Kafka - LocalStack - MariaDB diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml index c2f6d7504e8..54868eea96d 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yaml +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -30,6 +30,7 @@ body: - HiveMQ - InfluxDB - K3S + - K6 - Kafka - LocalStack - MariaDB diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index 3a03aa09bdd..2d28aca91d6 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -30,6 +30,7 @@ body: - HiveMQ - InfluxDB - K3S + - K6 - Kafka - LocalStack - MariaDB diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 163bf2db040..ddf7a8b7d9a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -148,6 +148,14 @@ updates: ignore: - dependency-name: "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml" update-types: [ "version-update:semver-minor", "version-update:semver-patch" ] + - package-ecosystem: "gradle" + directory: "/modules/k6" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + ignore: + - dependency-name: "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml" + update-types: [ "version-update:semver-minor", "version-update:semver-patch" ] - package-ecosystem: "gradle" directory: "/modules/kafka" schedule: diff --git a/.github/labeler.yml b/.github/labeler.yml index c7eec3b4a6a..8107870a59a 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -87,6 +87,10 @@ - changed-files: - any-glob-to-any-file: - modules/k3s/**/* +"modules/k6": + - changed-files: + - any-glob-to-any-file: + - modules/k6/**/* "modules/kafka": - changed-files: - any-glob-to-any-file: diff --git a/.github/settings.yml b/.github/settings.yml index c7458f63fc3..ad711b60307 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -160,6 +160,9 @@ labels: - name: modules/k3s color: '#006b75' + - name: modules/k6 + color: '#006b75' + - name: modules/kafka color: '#006b75' diff --git a/docs/modules/k6.md b/docs/modules/k6.md new file mode 100644 index 00000000000..7d14701aaa3 --- /dev/null +++ b/docs/modules/k6.md @@ -0,0 +1,39 @@ +# k6 Module + +!!! note + This module is INCUBATING. + While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. + See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy. + +Testcontainers module for [k6](https://registry.hub.docker.com/r/grafana/k6). + +[k6](https://k6.io/) is an extensible reliability testing tool built for developer happiness. + +## Basic script execution + +Execute a simple k6 test script, `test.js`, with commandline options and injected script variable. + +Create a simple k6 test script to be executed as part of your tests: + + +[Setup the container](../../modules/k6/src/test/java/org/testcontainers/k6/K6ContainerTests.java) inside_block:standard_k6 +[Content of `scripts/test.js`](../../modules/k6/src/test/resources/scripts/test.js) inside_block:access_script_vars + + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:k6:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + k6 + {{latest_version}} + test + + ``` diff --git a/mkdocs.yml b/mkdocs.yml index d51576a0bf6..8c5a0a769f1 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -82,6 +82,7 @@ nav: - modules/gcloud.md - modules/hivemq.md - modules/k3s.md + - modules/k6.md - modules/kafka.md - modules/localstack.md - modules/milvus.md diff --git a/modules/k6/build.gradle b/modules/k6/build.gradle new file mode 100644 index 00000000000..19945320d3b --- /dev/null +++ b/modules/k6/build.gradle @@ -0,0 +1,7 @@ +description = "Testcontainers :: k6" + +dependencies { + api project(':testcontainers') + + testImplementation 'org.assertj:assertj-core:3.25.2' +} diff --git a/modules/k6/src/main/java/org/testcontainers/k6/K6Container.java b/modules/k6/src/main/java/org/testcontainers/k6/K6Container.java new file mode 100644 index 00000000000..04403ccb4cb --- /dev/null +++ b/modules/k6/src/main/java/org/testcontainers/k6/K6Container.java @@ -0,0 +1,88 @@ +package org.testcontainers.k6; + +import org.apache.commons.io.FilenameUtils; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class K6Container extends GenericContainer { + + /** Standard image for k6, as provided by Grafana. */ + private static final DockerImageName K6_IMAGE = DockerImageName.parse("grafana/k6"); + + private String testScript; + + private List cmdOptions = new ArrayList<>(); + + private Map scriptVars = new HashMap<>(); + + /** + * Creates a new container instance based upon the provided image name. + */ + public K6Container(String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + /** + * Creates a new container instance based upon the provided image. + */ + public K6Container(DockerImageName dockerImageName) { + super(dockerImageName); + dockerImageName.assertCompatibleWith(K6_IMAGE); + } + + /** + * Specifies the test script to be executed within the container. + * @param testScript file to be copied into the container + * @return the builder + */ + public K6Container withTestScript(MountableFile testScript) { + this.testScript = "/home/k6/" + FilenameUtils.getName(testScript.getResolvedPath()); + withCopyFileToContainer(testScript, this.testScript); + return self(); + } + + /** + * Specifies additional command line options to be provided to the k6 command. + * @param options command line options + * @return the builder + */ + public K6Container withCmdOptions(String... options) { + cmdOptions.addAll(Arrays.asList(options)); + return self(); + } + + /** + * Adds a key-value pair for access within test scripts as an environment variable. + * @param key unique identifier for the variable + * @param value value of the variable + * @return the builder + */ + public K6Container withScriptVar(String key, String value) { + scriptVars.put(key, value); + return self(); + } + + /** + * {@inheritDoc} + */ + @Override + protected void configure() { + List commandParts = new ArrayList<>(); + commandParts.add("run"); + commandParts.addAll(cmdOptions); + for (Map.Entry entry : scriptVars.entrySet()) { + commandParts.add("--env"); + commandParts.add(String.format("%s=%s", entry.getKey(), entry.getValue())); + } + commandParts.add(testScript); + + setCommand(commandParts.toArray(new String[] {})); + } +} diff --git a/modules/k6/src/test/java/org/testcontainers/k6/K6ContainerTests.java b/modules/k6/src/test/java/org/testcontainers/k6/K6ContainerTests.java new file mode 100644 index 00000000000..f912fcd7dcf --- /dev/null +++ b/modules/k6/src/test/java/org/testcontainers/k6/K6ContainerTests.java @@ -0,0 +1,41 @@ +package org.testcontainers.k6; + +import org.junit.Test; +import org.testcontainers.containers.output.WaitingConsumer; +import org.testcontainers.utility.MountableFile; + +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + +public class K6ContainerTests { + + @Test + public void k6StandardTest() throws Exception { + try ( + // standard_k6 { + K6Container container = new K6Container("grafana/k6:0.49.0") + .withTestScript(MountableFile.forClasspathResource("scripts/test.js")) + .withScriptVar("MY_SCRIPT_VAR", "are cool!") + .withScriptVar("AN_UNUSED_VAR", "unused") + .withCmdOptions("--quiet", "--no-usage-report") + // } + ) { + container.start(); + + WaitingConsumer consumer = new WaitingConsumer(); + container.followOutput(consumer); + + // Wait for test script results to be collected + consumer.waitUntil( + frame -> { + return frame.getUtf8String().contains("iteration_duration"); + }, + 3, + TimeUnit.SECONDS + ); + + assertThat(container.getLogs()).contains("k6 tests are cool!"); + } + } +} diff --git a/modules/k6/src/test/resources/logback-test.xml b/modules/k6/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..83ef7a1a3ef --- /dev/null +++ b/modules/k6/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + diff --git a/modules/k6/src/test/resources/scripts/test.js b/modules/k6/src/test/resources/scripts/test.js new file mode 100644 index 00000000000..fad0c4b48df --- /dev/null +++ b/modules/k6/src/test/resources/scripts/test.js @@ -0,0 +1,6 @@ +// access_script_vars { +// The most basic of k6 scripts. +export default function(){ + console.log(`k6 tests ${__ENV.MY_SCRIPT_VAR}`) +} +// } From 8b8d50d24b504eea6d9a2eeb862381a5f42866c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Feb 2024 00:19:33 +0000 Subject: [PATCH 0025/1430] Bump org.apache.kafka:kafka-clients in /modules/kafka Bumps org.apache.kafka:kafka-clients from 3.6.1 to 3.7.0. --- updated-dependencies: - dependency-name: org.apache.kafka:kafka-clients dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/kafka/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kafka/build.gradle b/modules/kafka/build.gradle index 01e3551e651..581c1c8d397 100644 --- a/modules/kafka/build.gradle +++ b/modules/kafka/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Kafka" dependencies { api project(':testcontainers') - testImplementation 'org.apache.kafka:kafka-clients:3.6.1' + testImplementation 'org.apache.kafka:kafka-clients:3.7.0' testImplementation 'org.assertj:assertj-core:3.25.1' testImplementation 'com.google.guava:guava:23.0' } From 86e340576795b8002af0cc74b5e5e68d91605089 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Feb 2024 00:19:35 +0000 Subject: [PATCH 0026/1430] Bump org.assertj:assertj-core from 3.25.2 to 3.25.3 in /modules/k6 Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.25.2 to 3.25.3. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.25.2...assertj-build-3.25.3) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/k6/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/k6/build.gradle b/modules/k6/build.gradle index 19945320d3b..e59c07d99e8 100644 --- a/modules/k6/build.gradle +++ b/modules/k6/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: k6" dependencies { api project(':testcontainers') - testImplementation 'org.assertj:assertj-core:3.25.2' + testImplementation 'org.assertj:assertj-core:3.25.3' } From c23eb7f3dde8bbb669a837ae8e8cafb7b72c7ca0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Feb 2024 00:19:36 +0000 Subject: [PATCH 0027/1430] Bump org.apache.kafka:kafka-clients in /modules/redpanda Bumps org.apache.kafka:kafka-clients from 3.6.1 to 3.7.0. --- updated-dependencies: - dependency-name: org.apache.kafka:kafka-clients dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- modules/redpanda/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/redpanda/build.gradle b/modules/redpanda/build.gradle index 0690bcde61c..9e2bc69d139 100644 --- a/modules/redpanda/build.gradle +++ b/modules/redpanda/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':testcontainers') shaded 'org.freemarker:freemarker:2.3.32' - testImplementation 'org.apache.kafka:kafka-clients:3.6.1' + testImplementation 'org.apache.kafka:kafka-clients:3.7.0' testImplementation 'org.assertj:assertj-core:3.25.1' testImplementation 'io.rest-assured:rest-assured:5.4.0' } From e9902d59e482f83edc4d6fdbdd6a18be5e84cb88 Mon Sep 17 00:00:00 2001 From: Roberto Perez Alcolea Date: Wed, 28 Feb 2024 10:47:25 -0800 Subject: [PATCH 0028/1430] openfga.md: fix typo in docker hub link (#8400) --- docs/modules/openfga.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/openfga.md b/docs/modules/openfga.md index e11cae3560a..3df822468f4 100644 --- a/docs/modules/openfga.md +++ b/docs/modules/openfga.md @@ -1,6 +1,6 @@ # OpenFGA -Testcontainers module for [OpenFGA](https://hub.docker.com/r/"openfga/openfga). +Testcontainers module for [OpenFGA](https://hub.docker.com/r/openfga/openfga). ## OpenFGAContainer's usage examples From bfb837b22beca304dadd9b7cbe3f742c1523ce13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Wed, 28 Feb 2024 17:42:40 -0500 Subject: [PATCH 0029/1430] Add pgvector/pgvector as a compatible image (#7898) (#8401) --- .../org/testcontainers/containers/PostgreSQLContainer.java | 6 ++++-- .../org/testcontainers/containers/CompatibleImageTest.java | 4 +--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java index bc276f4cc1b..27b3679b626 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java @@ -11,7 +11,7 @@ /** * Testcontainers implementation for PostgreSQL. *

- * Supported image: {@code postgres} + * Supported images: {@code postgres}, {@code pgvector/pgvector} *

* Exposed ports: 5432 */ @@ -25,6 +25,8 @@ public class PostgreSQLContainer> extends private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("postgres"); + private static final DockerImageName PGVECTOR_IMAGE_NAME = DockerImageName.parse("pgvector/pgvector"); + public static final Integer POSTGRESQL_PORT = 5432; static final String DEFAULT_USER = "test"; @@ -53,7 +55,7 @@ public PostgreSQLContainer(final String dockerImageName) { public PostgreSQLContainer(final DockerImageName dockerImageName) { super(dockerImageName); - dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME, PGVECTOR_IMAGE_NAME); this.waitStrategy = new LogMessageWaitStrategy() diff --git a/modules/postgresql/src/test/java/org/testcontainers/containers/CompatibleImageTest.java b/modules/postgresql/src/test/java/org/testcontainers/containers/CompatibleImageTest.java index 2bb1c6c3d54..76b4a8c1bda 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/containers/CompatibleImageTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/containers/CompatibleImageTest.java @@ -15,9 +15,7 @@ public class CompatibleImageTest extends AbstractContainerDatabaseTest { public void pgvector() throws SQLException { try ( // pgvectorContainer { - PostgreSQLContainer pgvector = new PostgreSQLContainer<>( - DockerImageName.parse("pgvector/pgvector:pg16").asCompatibleSubstituteFor("postgres") - ) + PostgreSQLContainer pgvector = new PostgreSQLContainer<>("pgvector/pgvector:pg16") // } ) { pgvector.start(); From 8bec80c4dc1760d4ac6354c5e0400c5739d31eaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Wed, 28 Feb 2024 16:46:37 -0600 Subject: [PATCH 0030/1430] Update check list in settings --- .github/settings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/settings.yml b/.github/settings.yml index ad711b60307..84f6cee242b 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -382,7 +382,7 @@ branches: # Required. Require branches to be up to date before merging. strict: true # Required. The list of status checks to require in order to merge into this branch - contexts: ["check (:testcontainers:check)", "check (:docs:examples:check)", "in-docker_test", "ci/circleci: minimal_core", "test"] + contexts: ["core", "check_docs_examples", "in-docker_test", "ci/circleci: minimal_core", "test"] # Required. Enforce all configured restrictions for administrators. Set to true to enforce required status checks for repository administrators. Set to null to disable. enforce_admins: false # Prevent merge commits from being pushed to matching branches From af5863cdf041536fb053019a2e0cfbd87be1b533 Mon Sep 17 00:00:00 2001 From: Silvio Giebl Date: Thu, 29 Feb 2024 00:54:09 +0100 Subject: [PATCH 0031/1430] Fix wrong permission setup for HiveMQ container (#8399) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Eddú Meléndez Gonzales --- modules/hivemq/build.gradle | 3 +-- .../testcontainers/hivemq/HiveMQContainer.java | 6 +++--- .../ContainerWithExtensionFromDirectoryIT.java | 17 +++++++++++++---- .../hivemq/ContainerWithExtensionIT.java | 16 ++++++++++++---- .../ContainerWithExtensionSubclassIT.java | 2 +- .../ContainerWithFileInExtensionHomeIT.java | 15 +++++++++++---- .../hivemq/ContainerWithFileInHomeIT.java | 2 +- .../hivemq/ContainerWithLicenseIT.java | 2 +- .../hivemq/CreateFileInCopiedDirectoryIT.java | 2 +- .../CreateFileInExtensionDirectoryIT.java | 15 +++++++++++---- .../hivemq/HiveMQTestContainerCore.java | 2 +- .../hivemq/docs/DemoExtensionTestsIT.java | 2 +- .../testcontainers/hivemq/docs/DemoFilesIT.java | 6 +++--- .../hivemq/docs/DemoHiveMQContainerIT.java | 4 ++-- 14 files changed, 62 insertions(+), 32 deletions(-) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index 7aca932667b..6c03e07254d 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -11,14 +11,13 @@ dependencies { shaded("org.jboss.shrinkwrap:shrinkwrap-impl-base:1.2.6") shaded("net.lingala.zip4j:zip4j:2.11.5") - testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.1") + testImplementation("org.junit.jupiter:junit-jupiter:5.10.1") testImplementation(project(":junit-jupiter")) testImplementation("com.hivemq:hivemq-extension-sdk:4.24.0") testImplementation("com.hivemq:hivemq-mqtt-client:1.3.3") testImplementation("org.apache.httpcomponents:httpclient:4.5.14") testImplementation("ch.qos.logback:logback-classic:1.4.14") testImplementation 'org.assertj:assertj-core:3.25.1' - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.1") } test { diff --git a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java index 4638f758745..29e78920917 100644 --- a/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java +++ b/modules/hivemq/src/main/java/org/testcontainers/hivemq/HiveMQContainer.java @@ -134,9 +134,9 @@ protected void configure() { setCommand( "-c", removeCommand + - "cp -r '/opt/hivemq/temp-extensions/'* /opt/hivemq/extensions/ " + - "; chmod -R 777 /opt/hivemq/extensions " + - "&& /opt/docker-entrypoint.sh /opt/hivemq/bin/run.sh" + "cp -r '/opt/hivemq/temp-extensions/'* /opt/hivemq/extensions/ ; " + + "chmod -R 777 /opt/hivemq/extensions ; " + + "/opt/docker-entrypoint.sh /opt/hivemq/bin/run.sh" ); } diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java index 6fef56c0a2d..a5b6170a228 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionFromDirectoryIT.java @@ -1,7 +1,10 @@ package org.testcontainers.hivemq; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.slf4j.event.Level; import org.testcontainers.hivemq.util.TestPublishModifiedUtil; import org.testcontainers.utility.DockerImageName; @@ -11,12 +14,18 @@ class ContainerWithExtensionFromDirectoryIT { - @Test + @ParameterizedTest + @ValueSource( + strings = { + "2020.1", // first version that provided a container image + "2024.3", // version that runs the image as a non-root user by default + } + ) @Timeout(value = 3, unit = TimeUnit.MINUTES) - void test() throws Exception { + void test(final @NotNull String hivemqCeTag) throws Exception { try ( final HiveMQContainer hivemq = new HiveMQContainer( - DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + DockerImageName.parse("hivemq/hivemq-ce").withTag(hivemqCeTag) ) .withExtension(MountableFile.forClasspathResource("/modifier-extension")) .waitForExtension("Modifier Extension") @@ -33,7 +42,7 @@ void test() throws Exception { void test_wrongDirectoryName() throws Exception { try ( final HiveMQContainer hivemq = new HiveMQContainer( - DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + DockerImageName.parse("hivemq/hivemq-ce").withTag("2024.3") ) .withExtension(MountableFile.forClasspathResource("/modifier-extension-wrong-name")) .waitForExtension("Modifier Extension") diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java index eda3f236e2c..2b255912da9 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionIT.java @@ -1,7 +1,9 @@ package org.testcontainers.hivemq; -import org.junit.jupiter.api.Test; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Timeout; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.testcontainers.hivemq.util.MyExtension; import org.testcontainers.hivemq.util.TestPublishModifiedUtil; import org.testcontainers.utility.DockerImageName; @@ -11,9 +13,15 @@ class ContainerWithExtensionIT { - @Test + @ParameterizedTest + @ValueSource( + strings = { + "2020.1", // first version that provided a container image + "2024.3", // version that runs the image as a non-root user by default + } + ) @Timeout(value = 3, unit = TimeUnit.MINUTES) - void test() throws Exception { + void test(final @NotNull String hivemqCeTag) throws Exception { final HiveMQExtension hiveMQExtension = HiveMQExtension .builder() .id("extension-1") @@ -24,7 +32,7 @@ void test() throws Exception { try ( final HiveMQContainer hivemq = new HiveMQContainer( - DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + DockerImageName.parse("hivemq/hivemq-ce").withTag(hivemqCeTag) ) .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) .waitForExtension(hiveMQExtension) diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java index cd1df9ce8e7..a907b8f2d2e 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithExtensionSubclassIT.java @@ -25,7 +25,7 @@ void test() throws Exception { try ( final HiveMQContainer hivemq = new HiveMQContainer( - DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + DockerImageName.parse("hivemq/hivemq-ce").withTag("2024.3") ) .waitForExtension(hiveMQExtension) .withExtension(hiveMQExtension) diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java index dde5e677a15..c3c74b0dce7 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInExtensionHomeIT.java @@ -9,8 +9,9 @@ import com.hivemq.extension.sdk.api.services.Services; import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.testcontainers.hivemq.util.TestPublishModifiedUtil; import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.MountableFile; @@ -22,9 +23,15 @@ class ContainerWithFileInExtensionHomeIT { - @Test + @ParameterizedTest + @ValueSource( + strings = { + "2020.1", // first version that provided a container image + "2024.3", // version that runs the image as a non-root user by default + } + ) @Timeout(value = 3, unit = TimeUnit.MINUTES) - void test() throws Exception { + void test(final @NotNull String hivemqCeTag) throws Exception { final HiveMQExtension hiveMQExtension = HiveMQExtension .builder() .id("extension-1") @@ -35,7 +42,7 @@ void test() throws Exception { try ( final HiveMQContainer hivemq = new HiveMQContainer( - DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + DockerImageName.parse("hivemq/hivemq-ce").withTag(hivemqCeTag) ) .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) .withExtension(hiveMQExtension) diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java index 78a51398bf3..c8e19316788 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithFileInHomeIT.java @@ -35,7 +35,7 @@ void test() throws Exception { try ( final HiveMQContainer hivemq = new HiveMQContainer( - DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + DockerImageName.parse("hivemq/hivemq-ce").withTag("2024.3") ) .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) .withExtension(hiveMQExtension) diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java index f6aa6ed08f0..3973abddb0b 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/ContainerWithLicenseIT.java @@ -35,7 +35,7 @@ void test() throws Exception { try ( final HiveMQContainer hivemq = new HiveMQContainer( - DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + DockerImageName.parse("hivemq/hivemq-ce").withTag("2024.3") ) .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) .withExtension(hiveMQExtension) diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java index c0e95f61cf6..df0f3ef3b9c 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInCopiedDirectoryIT.java @@ -47,7 +47,7 @@ void test() throws Exception { try ( final HiveMQContainer hivemq = new HiveMQContainer( - DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + DockerImageName.parse("hivemq/hivemq-ce").withTag("2024.3") ) .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) .withExtension(extension) diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java index 3e7bec94e6e..6f65ebb1e9f 100755 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/CreateFileInExtensionDirectoryIT.java @@ -9,8 +9,9 @@ import com.hivemq.extension.sdk.api.services.Services; import com.hivemq.extension.sdk.api.services.intializer.ClientInitializer; import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.testcontainers.hivemq.util.TestPublishModifiedUtil; import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.MountableFile; @@ -23,9 +24,15 @@ class CreateFileInExtensionDirectoryIT { - @Test + @ParameterizedTest + @ValueSource( + strings = { + "2020.1", // first version that provided a container image + "2024.3", // version that runs the image as a non-root user by default + } + ) @Timeout(value = 3, unit = TimeUnit.MINUTES) - void test() throws Exception { + void test(final @NotNull String hivemqCeTag) throws Exception { final HiveMQExtension hiveMQExtension = HiveMQExtension .builder() .id("extension-1") @@ -36,7 +43,7 @@ void test() throws Exception { try ( final HiveMQContainer hivemq = new HiveMQContainer( - DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + DockerImageName.parse("hivemq/hivemq-ce").withTag(hivemqCeTag) ) .withHiveMQConfig(MountableFile.forClasspathResource("/inMemoryConfig.xml")) .waitForExtension(hiveMQExtension) diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java index 32097e52641..ede972e957d 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/HiveMQTestContainerCore.java @@ -16,7 +16,7 @@ class HiveMQTestContainerCore { @NotNull - final HiveMQContainer container = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")); + final HiveMQContainer container = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2024.3")); @TempDir File tempDir; diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java index f3289413a36..a1ff664649d 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoExtensionTestsIT.java @@ -38,7 +38,7 @@ class DemoExtensionTestsIT { @Container final HiveMQContainer hivemqWithClasspathExtension = new HiveMQContainer( - DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + DockerImageName.parse("hivemq/hivemq-ce").withTag("2024.3") ) .waitForExtension(hiveMQEClasspathxtension) .withExtension(hiveMQEClasspathxtension) diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java index a76fa60576f..8fe08b24750 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoFilesIT.java @@ -19,7 +19,7 @@ class DemoFilesIT { // hivemqHome { final HiveMQContainer hivemqFileInHome = new HiveMQContainer( - DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + DockerImageName.parse("hivemq/hivemq-ce").withTag("2024.3") ) .withFileInHomeFolder( MountableFile.forHostPath("src/test/resources/additionalFile.txt"), @@ -31,7 +31,7 @@ class DemoFilesIT { // extensionHome { @Container final HiveMQContainer hivemqFileInExtensionHome = new HiveMQContainer( - DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3") + DockerImageName.parse("hivemq/hivemq-ce").withTag("2024.3") ) .withExtension( HiveMQExtension @@ -52,7 +52,7 @@ class DemoFilesIT { // withLicenses { @Container - final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + final HiveMQContainer hivemq = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2024.3")) .withLicense(MountableFile.forHostPath("src/test/resources/myLicense.lic")) .withLicense(MountableFile.forHostPath("src/test/resources/myExtensionLicense.elic")); diff --git a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java index db6e3e58251..ed063617537 100644 --- a/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java +++ b/modules/hivemq/src/test/java/org/testcontainers/hivemq/docs/DemoHiveMQContainerIT.java @@ -18,7 +18,7 @@ class DemoHiveMQContainerIT { // ceVersion { @Container - final HiveMQContainer hivemqCe = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2021.3")) + final HiveMQContainer hivemqCe = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce").withTag("2024.3")) .withLogLevel(Level.DEBUG); // } @@ -43,7 +43,7 @@ class DemoHiveMQContainerIT { // specificVersion { @Container - final HiveMQContainer hivemqSpecificVersion = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce:2021.3")); + final HiveMQContainer hivemqSpecificVersion = new HiveMQContainer(DockerImageName.parse("hivemq/hivemq-ce:2024.3")); // } From 87814115b63a58c5485929fae3a556ae2eee1d9b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Feb 2024 23:54:52 +0000 Subject: [PATCH 0032/1430] Bump org.assertj:assertj-core from 3.25.1 to 3.25.3 in /modules/hivemq Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.25.1 to 3.25.3. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.25.1...assertj-build-3.25.3) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/hivemq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index 6c03e07254d..f85842f8988 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -17,7 +17,7 @@ dependencies { testImplementation("com.hivemq:hivemq-mqtt-client:1.3.3") testImplementation("org.apache.httpcomponents:httpclient:4.5.14") testImplementation("ch.qos.logback:logback-classic:1.4.14") - testImplementation 'org.assertj:assertj-core:3.25.1' + testImplementation 'org.assertj:assertj-core:3.25.3' } test { From f23c1ecd7c91ffdc0a0f476d64851fa39406d6fc Mon Sep 17 00:00:00 2001 From: He Wang Date: Thu, 29 Feb 2024 07:59:32 +0800 Subject: [PATCH 0033/1430] Add oceanbase module (#7502) --- .github/ISSUE_TEMPLATE/bug_report.yaml | 1 + .github/ISSUE_TEMPLATE/enhancement.yaml | 1 + .github/ISSUE_TEMPLATE/feature.yaml | 1 + .github/dependabot.yml | 5 ++ .github/labeler.yml | 4 + .github/settings.yml | 3 + docs/modules/databases/jdbc.md | 4 + docs/modules/databases/oceanbase.md | 25 ++++++ mkdocs.yml | 1 + modules/oceanbase/build.gradle | 8 ++ .../oceanbase/OceanBaseCEContainer.java | 82 +++++++++++++++++++ .../OceanBaseCEContainerProvider.java | 32 ++++++++ .../oceanbase/OceanBaseJdbcUtils.java | 45 ++++++++++ ...s.containers.JdbcDatabaseContainerProvider | 1 + .../oceanbase/OceanBaseJdbcDriverTest.java | 19 +++++ .../oceanbase/SimpleOceanBaseCETest.java | 69 ++++++++++++++++ modules/oceanbase/src/test/resources/init.sql | 45 ++++++++++ .../src/test/resources/logback-test.xml | 16 ++++ 18 files changed, 362 insertions(+) create mode 100644 docs/modules/databases/oceanbase.md create mode 100644 modules/oceanbase/build.gradle create mode 100644 modules/oceanbase/src/main/java/org/testcontainers/oceanbase/OceanBaseCEContainer.java create mode 100644 modules/oceanbase/src/main/java/org/testcontainers/oceanbase/OceanBaseCEContainerProvider.java create mode 100644 modules/oceanbase/src/main/java/org/testcontainers/oceanbase/OceanBaseJdbcUtils.java create mode 100644 modules/oceanbase/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider create mode 100644 modules/oceanbase/src/test/java/org/testcontainers/oceanbase/OceanBaseJdbcDriverTest.java create mode 100644 modules/oceanbase/src/test/java/org/testcontainers/oceanbase/SimpleOceanBaseCETest.java create mode 100644 modules/oceanbase/src/test/resources/init.sql create mode 100644 modules/oceanbase/src/test/resources/logback-test.xml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index abb8b0f7901..270f292dcf7 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -42,6 +42,7 @@ body: - MySQL - Neo4j - NGINX + - OceanBase - OpenFGA - Oracle Free - Oracle XE diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml index 54868eea96d..97297c9ddb2 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yaml +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -42,6 +42,7 @@ body: - MySQL - Neo4j - NGINX + - OceanBase - OpenFGA - Oracle Free - Oracle XE diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index 2d28aca91d6..80048f00fb0 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -42,6 +42,7 @@ body: - MySQL - Neo4j - NGINX + - OceanBase - OpenFGA - Oracle Free - Oracle XE diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ddf7a8b7d9a..22cbe2c2748 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -219,6 +219,11 @@ updates: schedule: interval: "weekly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/oceanbase" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/openfga" schedule: diff --git a/.github/labeler.yml b/.github/labeler.yml index 8107870a59a..2b9dd3bc899 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -135,6 +135,10 @@ - changed-files: - any-glob-to-any-file: - modules/nginx/**/* +"modules/oceanbase": + - changed-files: + - any-glob-to-any-file: + - modules/oceanbase/**/* "modules/openfga": - changed-files: - any-glob-to-any-file: diff --git a/.github/settings.yml b/.github/settings.yml index 84f6cee242b..6ac8714a40c 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -193,6 +193,9 @@ labels: - name: modules/nginx color: '#006b75' + - name: modules/oceanbase + color: '#006b75' + - name: modules/openfga color: '#006b75' diff --git a/docs/modules/databases/jdbc.md b/docs/modules/databases/jdbc.md index dc11954153a..c1d0171c59e 100644 --- a/docs/modules/databases/jdbc.md +++ b/docs/modules/databases/jdbc.md @@ -55,6 +55,10 @@ Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database `jdbc:tc:sqlserver:2017-CU12:///databasename` +#### Using OceanBase + +`jdbc:tc:oceanbasece:4.2.2:///databasename` + #### Using Oracle `jdbc:tc:oracle:21-slim-faststart:///databasename` diff --git a/docs/modules/databases/oceanbase.md b/docs/modules/databases/oceanbase.md new file mode 100644 index 00000000000..b90a492a6e4 --- /dev/null +++ b/docs/modules/databases/oceanbase.md @@ -0,0 +1,25 @@ +# OceanBase Module + +See [Database containers](./index.md) for documentation and usage that is common to all relational database container types. + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:oceanbase:{{latest_version}}" + ``` + +=== "Maven" + ```xml + + org.testcontainers + oceanbase + {{latest_version}} + test + + ``` + +!!! hint +Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency. diff --git a/mkdocs.yml b/mkdocs.yml index 8c5a0a769f1..ce0c33dcf16 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -64,6 +64,7 @@ nav: - modules/databases/mssqlserver.md - modules/databases/mysql.md - modules/databases/neo4j.md + - modules/databases/oceanbase.md - modules/databases/oraclefree.md - modules/databases/oraclexe.md - modules/databases/orientdb.md diff --git a/modules/oceanbase/build.gradle b/modules/oceanbase/build.gradle new file mode 100644 index 00000000000..e1f13a7a6a1 --- /dev/null +++ b/modules/oceanbase/build.gradle @@ -0,0 +1,8 @@ +description = "Testcontainers :: JDBC :: OceanBase" + +dependencies { + api project(':jdbc') + + testImplementation project(':jdbc-test') + testRuntimeOnly 'mysql:mysql-connector-java:8.0.33' +} diff --git a/modules/oceanbase/src/main/java/org/testcontainers/oceanbase/OceanBaseCEContainer.java b/modules/oceanbase/src/main/java/org/testcontainers/oceanbase/OceanBaseCEContainer.java new file mode 100644 index 00000000000..6c08ff165f2 --- /dev/null +++ b/modules/oceanbase/src/main/java/org/testcontainers/oceanbase/OceanBaseCEContainer.java @@ -0,0 +1,82 @@ +package org.testcontainers.oceanbase; + +import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.utility.DockerImageName; + +/** + * Testcontainers implementation for OceanBase Community Edition. + *

+ * Supported image: {@code oceanbase/oceanbase-ce} + *

+ * Exposed ports: + *

    + *
  • SQL: 2881
  • + *
  • RPC: 2882
  • + *
+ */ +public class OceanBaseCEContainer extends JdbcDatabaseContainer { + + static final String NAME = "oceanbasece"; + + static final String DOCKER_IMAGE_NAME = "oceanbase/oceanbase-ce"; + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse(DOCKER_IMAGE_NAME); + + private static final Integer SQL_PORT = 2881; + + private static final Integer RPC_PORT = 2882; + + private static final String DEFAULT_TEST_TENANT_NAME = "test"; + + private static final String DEFAULT_USERNAME = "root"; + + private static final String DEFAULT_PASSWORD = ""; + + private static final String DEFAULT_DATABASE_NAME = "test"; + + public OceanBaseCEContainer(String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public OceanBaseCEContainer(DockerImageName dockerImageName) { + super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + + addExposedPorts(SQL_PORT, RPC_PORT); + } + + @Override + public String getDriverClassName() { + return OceanBaseJdbcUtils.getDriverClass(); + } + + @Override + public String getJdbcUrl() { + String additionalUrlParams = constructUrlParameters("?", "&"); + String prefix = OceanBaseJdbcUtils.isMySQLDriver(getDriverClassName()) ? "jdbc:mysql://" : "jdbc:oceanbase://"; + return prefix + getHost() + ":" + getMappedPort(SQL_PORT) + "/" + DEFAULT_DATABASE_NAME + additionalUrlParams; + } + + @Override + public String getDatabaseName() { + return DEFAULT_DATABASE_NAME; + } + + @Override + public String getUsername() { + // In OceanBase, the jdbc username is related to the name of user, tenant and cluster, + // if a tenant name other than the default value 'test' is used, you should manually + // construct the jdbc username by yourself. + return DEFAULT_USERNAME + "@" + DEFAULT_TEST_TENANT_NAME; + } + + @Override + public String getPassword() { + return DEFAULT_PASSWORD; + } + + @Override + protected String getTestQueryString() { + return "SELECT 1"; + } +} diff --git a/modules/oceanbase/src/main/java/org/testcontainers/oceanbase/OceanBaseCEContainerProvider.java b/modules/oceanbase/src/main/java/org/testcontainers/oceanbase/OceanBaseCEContainerProvider.java new file mode 100644 index 00000000000..d0f651bc338 --- /dev/null +++ b/modules/oceanbase/src/main/java/org/testcontainers/oceanbase/OceanBaseCEContainerProvider.java @@ -0,0 +1,32 @@ +package org.testcontainers.oceanbase; + +import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.containers.JdbcDatabaseContainerProvider; +import org.testcontainers.utility.DockerImageName; + +/** + * Factory for OceanBase Community Edition containers. + */ +public class OceanBaseCEContainerProvider extends JdbcDatabaseContainerProvider { + + private static final String DEFAULT_TAG = "4.2.2"; + + @Override + public boolean supports(String databaseType) { + return databaseType.equals(OceanBaseCEContainer.NAME); + } + + @Override + public JdbcDatabaseContainer newInstance() { + return newInstance(DEFAULT_TAG); + } + + @Override + public JdbcDatabaseContainer newInstance(String tag) { + if (tag != null) { + return new OceanBaseCEContainer(DockerImageName.parse(OceanBaseCEContainer.DOCKER_IMAGE_NAME).withTag(tag)); + } else { + return newInstance(); + } + } +} diff --git a/modules/oceanbase/src/main/java/org/testcontainers/oceanbase/OceanBaseJdbcUtils.java b/modules/oceanbase/src/main/java/org/testcontainers/oceanbase/OceanBaseJdbcUtils.java new file mode 100644 index 00000000000..d2e90f48ee6 --- /dev/null +++ b/modules/oceanbase/src/main/java/org/testcontainers/oceanbase/OceanBaseJdbcUtils.java @@ -0,0 +1,45 @@ +package org.testcontainers.oceanbase; + +import java.util.Arrays; +import java.util.List; + +/** + * Utils for OceanBase Jdbc Connection. + */ +class OceanBaseJdbcUtils { + + static final String MYSQL_JDBC_DRIVER = "com.mysql.cj.jdbc.Driver"; + + static final String MYSQL_LEGACY_JDBC_DRIVER = "com.mysql.jdbc.Driver"; + + static final String OCEANBASE_JDBC_DRIVER = "com.oceanbase.jdbc.Driver"; + + static final String OCEANBASE_LEGACY_JDBC_DRIVER = "com.alipay.oceanbase.jdbc.Driver"; + + static final List SUPPORTED_DRIVERS = Arrays.asList( + OCEANBASE_JDBC_DRIVER, + OCEANBASE_LEGACY_JDBC_DRIVER, + MYSQL_JDBC_DRIVER, + MYSQL_LEGACY_JDBC_DRIVER + ); + + static String getDriverClass() { + for (String driverClass : SUPPORTED_DRIVERS) { + try { + Class.forName(driverClass); + return driverClass; + } catch (ClassNotFoundException e) { + // try to load next driver + } + } + throw new RuntimeException("Can't find valid driver class for OceanBase"); + } + + static boolean isMySQLDriver(String driverClassName) { + return MYSQL_JDBC_DRIVER.equals(driverClassName) || MYSQL_LEGACY_JDBC_DRIVER.equals(driverClassName); + } + + static boolean isOceanBaseDriver(String driverClassName) { + return OCEANBASE_JDBC_DRIVER.equals(driverClassName) || OCEANBASE_LEGACY_JDBC_DRIVER.equals(driverClassName); + } +} diff --git a/modules/oceanbase/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider b/modules/oceanbase/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider new file mode 100644 index 00000000000..505bfe5e088 --- /dev/null +++ b/modules/oceanbase/src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider @@ -0,0 +1 @@ +org.testcontainers.oceanbase.OceanBaseCEContainerProvider diff --git a/modules/oceanbase/src/test/java/org/testcontainers/oceanbase/OceanBaseJdbcDriverTest.java b/modules/oceanbase/src/test/java/org/testcontainers/oceanbase/OceanBaseJdbcDriverTest.java new file mode 100644 index 00000000000..a4f63b1eb90 --- /dev/null +++ b/modules/oceanbase/src/test/java/org/testcontainers/oceanbase/OceanBaseJdbcDriverTest.java @@ -0,0 +1,19 @@ +package org.testcontainers.oceanbase; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.testcontainers.jdbc.AbstractJDBCDriverTest; + +import java.util.Arrays; +import java.util.EnumSet; + +@RunWith(Parameterized.class) +public class OceanBaseJdbcDriverTest extends AbstractJDBCDriverTest { + + @Parameterized.Parameters(name = "{index} - {0}") + public static Iterable data() { + return Arrays.asList( + new Object[][] { { "jdbc:tc:oceanbasece://hostname/databasename", EnumSet.noneOf(Options.class) } } + ); + } +} diff --git a/modules/oceanbase/src/test/java/org/testcontainers/oceanbase/SimpleOceanBaseCETest.java b/modules/oceanbase/src/test/java/org/testcontainers/oceanbase/SimpleOceanBaseCETest.java new file mode 100644 index 00000000000..7c4f20e4943 --- /dev/null +++ b/modules/oceanbase/src/test/java/org/testcontainers/oceanbase/SimpleOceanBaseCETest.java @@ -0,0 +1,69 @@ +package org.testcontainers.oceanbase; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.containers.output.Slf4jLogConsumer; +import org.testcontainers.db.AbstractContainerDatabaseTest; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SimpleOceanBaseCETest extends AbstractContainerDatabaseTest { + + private static final Logger logger = LoggerFactory.getLogger(SimpleOceanBaseCETest.class); + + private final OceanBaseCEContainerProvider containerProvider = new OceanBaseCEContainerProvider(); + + @SuppressWarnings("resource") + private OceanBaseCEContainer testContainer() { + return ((OceanBaseCEContainer) containerProvider.newInstance()).withEnv("MODE", "slim") + .withEnv("FASTBOOT", "true") + .withLogConsumer(new Slf4jLogConsumer(logger)); + } + + @Test + public void testSimple() throws SQLException { + try (OceanBaseCEContainer container = testContainer()) { + container.start(); + + ResultSet resultSet = performQuery(container, "SELECT 1"); + int resultSetInt = resultSet.getInt(1); + assertThat(resultSetInt).as("A basic SELECT query succeeds").isEqualTo(1); + assertHasCorrectExposedAndLivenessCheckPorts(container); + } + } + + @Test + public void testExplicitInitScript() throws SQLException { + try (OceanBaseCEContainer container = testContainer().withInitScript("init.sql")) { + container.start(); + + ResultSet resultSet = performQuery(container, "SELECT foo FROM bar"); + String firstColumnValue = resultSet.getString(1); + assertThat(firstColumnValue).as("Value from init script should equal real value").isEqualTo("hello world"); + } + } + + @Test + public void testWithAdditionalUrlParamInJdbcUrl() { + try (OceanBaseCEContainer container = testContainer().withUrlParam("useSSL", "false")) { + container.start(); + + String jdbcUrl = container.getJdbcUrl(); + assertThat(jdbcUrl).contains("?"); + assertThat(jdbcUrl).contains("useSSL=false"); + } + } + + private void assertHasCorrectExposedAndLivenessCheckPorts(OceanBaseCEContainer container) { + int sqlPort = 2881; + int rpcPort = 2882; + + assertThat(container.getExposedPorts()).containsExactlyInAnyOrder(sqlPort, rpcPort); + assertThat(container.getLivenessCheckPortNumbers()) + .containsExactlyInAnyOrder(container.getMappedPort(sqlPort), container.getMappedPort(rpcPort)); + } +} diff --git a/modules/oceanbase/src/test/resources/init.sql b/modules/oceanbase/src/test/resources/init.sql new file mode 100644 index 00000000000..98d6889b078 --- /dev/null +++ b/modules/oceanbase/src/test/resources/init.sql @@ -0,0 +1,45 @@ +CREATE TABLE bar ( + foo VARCHAR(255) +); + +DROP PROCEDURE IF EXISTS -- ; + count_foo; + +SELECT "a /* string literal containing comment characters like -- here"; +SELECT "a 'quoting' \"scenario ` involving BEGIN keyword\" here"; +SELECT * from `bar`; + +-- What about a line comment containing imbalanced string delimiters? " + +CREATE PROCEDURE count_foo() +BEGIN + + BEGIN + SELECT * + FROM bar; + SELECT 1 + FROM dual; + END; + + BEGIN + select * from bar; + END; + + -- we can do comments + + /* including block + comments + */ + + /* what if BEGIN appears inside a comment? */ + + select "or what if BEGIN appears inside a literal?"; + +END /*; */; + +/* or a block comment + containing imbalanced string delimiters? + ' " + */ + +INSERT INTO bar (foo) /* ; */ VALUES ('hello world'); diff --git a/modules/oceanbase/src/test/resources/logback-test.xml b/modules/oceanbase/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..83ef7a1a3ef --- /dev/null +++ b/modules/oceanbase/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + From 33c904ed9c23088d725dd0b5f017cdab2384edae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 29 Feb 2024 18:07:13 -0500 Subject: [PATCH 0034/1430] Update docker-java version to 3.3.6 (#8410) --- core/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index a318ff00b10..13152748815 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -88,8 +88,8 @@ dependencies { shaded 'org.awaitility:awaitility:4.2.0' - api platform('com.github.docker-java:docker-java-bom:3.3.5') - shaded platform('com.github.docker-java:docker-java-bom:3.3.5') + api platform('com.github.docker-java:docker-java-bom:3.3.6') + shaded platform('com.github.docker-java:docker-java-bom:3.3.6') api "com.github.docker-java:docker-java-api" From cab8b2f79c4f80767b6923107a2c34a8ed3f972a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 23:08:58 +0000 Subject: [PATCH 0035/1430] Bump org.assertj:assertj-core from 3.25.1 to 3.25.3 in /core Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.25.1 to 3.25.3. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.25.1...assertj-build-3.25.3) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/build.gradle b/core/build.gradle index 13152748815..a1c361030cb 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -120,12 +120,12 @@ dependencies { // Synthetic JAR used for MountableFileTest and DirectoryTarResourceTest testImplementation files('testlib/repo/fakejar/fakejar/0/fakejar-0.jar') - testImplementation 'org.assertj:assertj-core:3.25.1' + testImplementation 'org.assertj:assertj-core:3.25.3' jarFileTestCompileOnly "org.projectlombok:lombok:${lombok.version}" jarFileTestAnnotationProcessor "org.projectlombok:lombok:${lombok.version}" jarFileTestImplementation 'junit:junit:4.13.2' - jarFileTestImplementation 'org.assertj:assertj-core:3.25.1' + jarFileTestImplementation 'org.assertj:assertj-core:3.25.3' jarFileTestImplementation 'org.ow2.asm:asm-debug-all:5.2' } From 93ca7cd7345145de315e1d3c60f8b1ad07442cb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Fri, 1 Mar 2024 19:13:45 -0500 Subject: [PATCH 0036/1430] Add Ollama module (#8369) Co-authored-by: Kevin Wittek --- .github/ISSUE_TEMPLATE/bug_report.yaml | 1 + .github/ISSUE_TEMPLATE/enhancement.yaml | 1 + .github/ISSUE_TEMPLATE/feature.yaml | 1 + .github/dependabot.yml | 5 ++ .github/labeler.yml | 4 + .github/settings.yml | 3 + docs/modules/ollama.md | 30 +++++++ mkdocs.yml | 1 + modules/ollama/build.gradle | 8 ++ .../ollama/OllamaContainer.java | 80 +++++++++++++++++++ .../ollama/OllamaContainerTest.java | 56 +++++++++++++ .../src/test/resources/logback-test.xml | 16 ++++ 12 files changed, 206 insertions(+) create mode 100644 docs/modules/ollama.md create mode 100644 modules/ollama/build.gradle create mode 100644 modules/ollama/src/main/java/org/testcontainers/ollama/OllamaContainer.java create mode 100644 modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java create mode 100644 modules/ollama/src/test/resources/logback-test.xml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 270f292dcf7..1458b89d2f7 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -43,6 +43,7 @@ body: - Neo4j - NGINX - OceanBase + - Ollama - OpenFGA - Oracle Free - Oracle XE diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml index 97297c9ddb2..2baf2be99eb 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yaml +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -43,6 +43,7 @@ body: - Neo4j - NGINX - OceanBase + - Ollama - OpenFGA - Oracle Free - Oracle XE diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index 80048f00fb0..fb5013a41d3 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -43,6 +43,7 @@ body: - Neo4j - NGINX - OceanBase + - Ollama - OpenFGA - Oracle Free - Oracle XE diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 22cbe2c2748..0bb82dce9f4 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -224,6 +224,11 @@ updates: schedule: interval: "weekly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/ollama" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/openfga" schedule: diff --git a/.github/labeler.yml b/.github/labeler.yml index 2b9dd3bc899..387b1644801 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -139,6 +139,10 @@ - changed-files: - any-glob-to-any-file: - modules/oceanbase/**/* +"modules/ollama": + - changed-files: + - any-glob-to-any-file: + - modules/ollama/**/* "modules/openfga": - changed-files: - any-glob-to-any-file: diff --git a/.github/settings.yml b/.github/settings.yml index 6ac8714a40c..9cf3d27d5d4 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -196,6 +196,9 @@ labels: - name: modules/oceanbase color: '#006b75' + - name: modules/ollama + color: '#006b75' + - name: modules/openfga color: '#006b75' diff --git a/docs/modules/ollama.md b/docs/modules/ollama.md new file mode 100644 index 00000000000..97e8865bdc1 --- /dev/null +++ b/docs/modules/ollama.md @@ -0,0 +1,30 @@ +# Ollama + +Testcontainers module for [Ollama](https://hub.docker.com/r/ollama/ollama) . + +## Ollama's usage examples + +You can start an Ollama container instance from any Java application by using: + + +[Ollama container](../../modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java) inside_block:container + + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:ollama:{{latest_version}}" + ``` + +=== "Maven" + ```xml + + org.testcontainers + ollama + {{latest_version}} + test + + ``` diff --git a/mkdocs.yml b/mkdocs.yml index ce0c33dcf16..d5f5b275288 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -90,6 +90,7 @@ nav: - modules/minio.md - modules/mockserver.md - modules/nginx.md + - modules/ollama.md - modules/openfga.md - modules/pulsar.md - modules/qdrant.md diff --git a/modules/ollama/build.gradle b/modules/ollama/build.gradle new file mode 100644 index 00000000000..b64083062ec --- /dev/null +++ b/modules/ollama/build.gradle @@ -0,0 +1,8 @@ +description = "Testcontainers :: Ollama" + +dependencies { + api project(':testcontainers') + + testImplementation 'org.assertj:assertj-core:3.25.1' + testImplementation 'io.rest-assured:rest-assured:5.4.0' +} diff --git a/modules/ollama/src/main/java/org/testcontainers/ollama/OllamaContainer.java b/modules/ollama/src/main/java/org/testcontainers/ollama/OllamaContainer.java new file mode 100644 index 00000000000..1c739b95a6b --- /dev/null +++ b/modules/ollama/src/main/java/org/testcontainers/ollama/OllamaContainer.java @@ -0,0 +1,80 @@ +package org.testcontainers.ollama; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.model.DeviceRequest; +import com.github.dockerjava.api.model.Image; +import com.github.dockerjava.api.model.Info; +import com.github.dockerjava.api.model.RuntimeInfo; +import org.testcontainers.DockerClientFactory; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * Testcontainers implementation for Ollama. + *

+ * Supported image: {@code ollama/ollama} + *

+ * Exposed ports: 11434 + */ +public class OllamaContainer extends GenericContainer { + + private static final DockerImageName DOCKER_IMAGE_NAME = DockerImageName.parse("ollama/ollama"); + + public OllamaContainer(String image) { + this(DockerImageName.parse(image)); + } + + public OllamaContainer(DockerImageName dockerImageName) { + super(dockerImageName); + dockerImageName.assertCompatibleWith(DOCKER_IMAGE_NAME); + + Info info = this.dockerClient.infoCmd().exec(); + Map runtimes = info.getRuntimes(); + if (runtimes != null) { + if (runtimes.containsKey("nvidia")) { + withCreateContainerCmdModifier(cmd -> { + cmd + .getHostConfig() + .withDeviceRequests( + Collections.singletonList( + new DeviceRequest() + .withCapabilities(Collections.singletonList(Collections.singletonList("gpu"))) + .withCount(-1) + ) + ); + }); + } + } + withExposedPorts(11434); + } + + /** + * Commits the current file system changes in the container into a new image. + * Should be used for creating an image that contains a loaded model. + * @param imageName the name of the new image + */ + public void commitToImage(String imageName) { + DockerImageName dockerImageName = DockerImageName.parse(getDockerImageName()); + if (!dockerImageName.equals(DockerImageName.parse(imageName))) { + DockerClient dockerClient = DockerClientFactory.instance().client(); + List images = dockerClient.listImagesCmd().withReferenceFilter(imageName).exec(); + if (images.isEmpty()) { + DockerImageName imageModel = DockerImageName.parse(imageName); + dockerClient + .commitCmd(getContainerId()) + .withRepository(imageModel.getUnversionedPart()) + .withLabels(Collections.singletonMap("org.testcontainers.sessionId", "")) + .withTag(imageModel.getVersionPart()) + .exec(); + } + } + } + + public String getEndpoint() { + return "http://" + getHost() + ":" + getMappedPort(11434); + } +} diff --git a/modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java b/modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java new file mode 100644 index 00000000000..d33660b40b0 --- /dev/null +++ b/modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java @@ -0,0 +1,56 @@ +package org.testcontainers.ollama; + +import org.junit.Test; +import org.testcontainers.utility.Base58; +import org.testcontainers.utility.DockerImageName; + +import java.io.IOException; + +import static io.restassured.RestAssured.given; +import static org.assertj.core.api.Assertions.assertThat; + +public class OllamaContainerTest { + + @Test + public void withDefaultConfig() { + try ( // container { + OllamaContainer ollama = new OllamaContainer("ollama/ollama:0.1.26") + // } + ) { + ollama.start(); + + String version = given().baseUri(ollama.getEndpoint()).get("/api/version").jsonPath().get("version"); + assertThat(version).isEqualTo("0.1.26"); + } + } + + @Test + public void downloadModelAndCommitToImage() throws IOException, InterruptedException { + String newImageName = "tc-ollama-allminilm-" + Base58.randomString(4).toLowerCase(); + try (OllamaContainer ollama = new OllamaContainer("ollama/ollama:0.1.26")) { + ollama.start(); + ollama.execInContainer("ollama", "pull", "all-minilm"); + + String modelName = given() + .baseUri(ollama.getEndpoint()) + .get("/api/tags") + .jsonPath() + .getString("models[0].name"); + assertThat(modelName).contains("all-minilm"); + ollama.commitToImage(newImageName); + } + try ( + OllamaContainer ollama = new OllamaContainer( + DockerImageName.parse(newImageName).asCompatibleSubstituteFor("ollama/ollama") + ) + ) { + ollama.start(); + String modelName = given() + .baseUri(ollama.getEndpoint()) + .get("/api/tags") + .jsonPath() + .getString("models[0].name"); + assertThat(modelName).contains("all-minilm"); + } + } +} diff --git a/modules/ollama/src/test/resources/logback-test.xml b/modules/ollama/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..83ef7a1a3ef --- /dev/null +++ b/modules/ollama/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + From 4a0d27edeb5749c2c6777ff08303d342eefb06c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 2 Mar 2024 00:14:26 +0000 Subject: [PATCH 0037/1430] Bump org.assertj:assertj-core from 3.25.1 to 3.25.3 in /modules/ollama Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.25.1 to 3.25.3. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.25.1...assertj-build-3.25.3) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/ollama/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ollama/build.gradle b/modules/ollama/build.gradle index b64083062ec..1f65324bf10 100644 --- a/modules/ollama/build.gradle +++ b/modules/ollama/build.gradle @@ -3,6 +3,6 @@ description = "Testcontainers :: Ollama" dependencies { api project(':testcontainers') - testImplementation 'org.assertj:assertj-core:3.25.1' + testImplementation 'org.assertj:assertj-core:3.25.3' testImplementation 'io.rest-assured:rest-assured:5.4.0' } From 198b7fa45e9954eae1ad861c7a23a822ce07f463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Mon, 4 Mar 2024 11:59:13 -0600 Subject: [PATCH 0038/1430] Fix openfga doc --- .../java/org/testcontainers/openfga/OpenFGAContainerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/openfga/src/test/java/org/testcontainers/openfga/OpenFGAContainerTest.java b/modules/openfga/src/test/java/org/testcontainers/openfga/OpenFGAContainerTest.java index 688d4d31f10..6f444b697f0 100644 --- a/modules/openfga/src/test/java/org/testcontainers/openfga/OpenFGAContainerTest.java +++ b/modules/openfga/src/test/java/org/testcontainers/openfga/OpenFGAContainerTest.java @@ -15,7 +15,7 @@ public class OpenFGAContainerTest { @Test public void withDefaultConfig() throws FgaInvalidParameterException, ExecutionException, InterruptedException { - try ( // container + try ( // container { OpenFGAContainer openfga = new OpenFGAContainer("openfga/openfga:v1.4.3") // } ) { From 184680507f420922a2b18b86f5a07efeba7c589f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Mon, 4 Mar 2024 16:52:42 -0500 Subject: [PATCH 0039/1430] Improve Ollama docs (#8417) --- docs/modules/ollama.md | 22 +++++++++++++++++++ .../ollama/OllamaContainerTest.java | 6 +++++ 2 files changed, 28 insertions(+) diff --git a/docs/modules/ollama.md b/docs/modules/ollama.md index 97e8865bdc1..98d9c204966 100644 --- a/docs/modules/ollama.md +++ b/docs/modules/ollama.md @@ -10,6 +10,28 @@ You can start an Ollama container instance from any Java application by using: [Ollama container](../../modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java) inside_block:container +### Pulling the model + +Testcontainers allows [executing commands in the container](../features/commands.md). So, pulling the model is as simple as: + + +[Pull model](../../modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java) inside_block:pullModel + + +### Create a new Image + +In order to create a new image that contains the model, you can use the following code: + + +[Commit Image](../../modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java) inside_block:commitToImage + + +And use the new image along with [Image name Substitution](../features/image_name_substitution.md#manual-substitution) + + +[Use new Image](../../modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java) inside_block:containerSubstitute + + ## Adding this module to your project dependencies Add the following dependency to your `pom.xml`/`build.gradle` file: diff --git a/modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java b/modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java index d33660b40b0..cefd665b044 100644 --- a/modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java +++ b/modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java @@ -29,7 +29,9 @@ public void downloadModelAndCommitToImage() throws IOException, InterruptedExcep String newImageName = "tc-ollama-allminilm-" + Base58.randomString(4).toLowerCase(); try (OllamaContainer ollama = new OllamaContainer("ollama/ollama:0.1.26")) { ollama.start(); + // pullModel { ollama.execInContainer("ollama", "pull", "all-minilm"); + // } String modelName = given() .baseUri(ollama.getEndpoint()) @@ -37,12 +39,16 @@ public void downloadModelAndCommitToImage() throws IOException, InterruptedExcep .jsonPath() .getString("models[0].name"); assertThat(modelName).contains("all-minilm"); + // commitToImage { ollama.commitToImage(newImageName); + // } } try ( + // containerSubstitute { OllamaContainer ollama = new OllamaContainer( DockerImageName.parse(newImageName).asCompatibleSubstituteFor("ollama/ollama") ) + // } ) { ollama.start(); String modelName = given() From 4b5b34a8ec1af9eee3a6a4f5e53fc4eda8e4bb62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Przyby=C5=82?= <23506256+pioorg@users.noreply.github.com> Date: Mon, 4 Mar 2024 23:18:40 +0100 Subject: [PATCH 0040/1430] Enable lazy certificates for Elasticsearch (#7991) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Eddú Meléndez Gonzales --- modules/elasticsearch/build.gradle | 6 ++ .../elasticsearch/ElasticsearchContainer.java | 60 ++++++++++--------- .../ElasticsearchContainerTest.java | 44 ++++++++++++++ 3 files changed, 83 insertions(+), 27 deletions(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 56399a509d9..550e9a9b23a 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -6,3 +6,9 @@ dependencies { testImplementation "org.elasticsearch.client:transport:7.17.17" testImplementation 'org.assertj:assertj-core:3.25.2' } + +tasks.japicmp { + methodExcludes = [ + "org.testcontainers.elasticsearch.ElasticsearchContainer#containerIsStarted(com.github.dockerjava.api.command.InspectContainerResponse)", + ] +} diff --git a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java index 940d6924c5e..e96ae26c02f 100644 --- a/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java +++ b/modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/ElasticsearchContainer.java @@ -1,6 +1,5 @@ package org.testcontainers.elasticsearch; -import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.exception.NotFoundException; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; @@ -66,6 +65,9 @@ public class ElasticsearchContainer extends GenericContainer= 8 + private static final String DEFAULT_CERT_PATH = "/usr/share/elasticsearch/config/certs/http_ca.crt"; + /** * Elasticsearch Default version */ @@ -77,9 +79,7 @@ public class ElasticsearchContainer extends GenericContainer caCertAsBytes = Optional.empty(); - - private String certPath = "/usr/share/elasticsearch/config/certs/http_ca.crt"; + private String certPath = ""; /** * @deprecated use {@link #ElasticsearchContainer(DockerImageName)} instead @@ -91,6 +91,7 @@ public ElasticsearchContainer() { /** * Create an Elasticsearch Container by passing the full docker image name + * * @param dockerImageName Full docker image name as a {@link String}, like: docker.elastic.co/elasticsearch/elasticsearch:7.9.2 */ public ElasticsearchContainer(String dockerImageName) { @@ -99,6 +100,7 @@ public ElasticsearchContainer(String dockerImageName) { /** * Create an Elasticsearch Container by passing the full docker image name + * * @param dockerImageName Full docker image name as a {@link DockerImageName}, like: DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch:7.9.2") */ public ElasticsearchContainer(final DockerImageName dockerImageName) { @@ -136,23 +138,7 @@ public ElasticsearchContainer(final DockerImageName dockerImageName) { setWaitStrategy(new LogMessageWaitStrategy().withRegEx(regex)); if (isAtLeastMajorVersion8) { withPassword(ELASTICSEARCH_DEFAULT_PASSWORD); - } - } - - @Override - protected void containerIsStarted(InspectContainerResponse containerInfo) { - if (isAtLeastMajorVersion8 && StringUtils.isNotEmpty(certPath)) { - try { - byte[] bytes = copyFileFromContainer(certPath, IOUtils::toByteArray); - if (bytes.length > 0) { - this.caCertAsBytes = Optional.of(bytes); - } - } catch (NotFoundException e) { - // just emit an error message, but do not throw an exception - // this might be ok, if the docker image is accidentally looking like version 8 or latest - // can happen if Elasticsearch is repackaged, i.e. with custom plugins - log.warn("CA cert under " + certPath + " not found."); - } + withCertPath(DEFAULT_CERT_PATH); } } @@ -162,17 +148,36 @@ protected void containerIsStarted(InspectContainerResponse containerInfo) { * @return byte array optional containing the CA cert extracted from the docker container */ public Optional caCertAsBytes() { - return caCertAsBytes; + if (StringUtils.isBlank(certPath)) { + return Optional.empty(); + } + try { + byte[] bytes = copyFileFromContainer(certPath, IOUtils::toByteArray); + if (bytes.length > 0) { + return Optional.of(bytes); + } + } catch (NotFoundException e) { + // just emit an error message, but do not throw an exception + // this might be ok, if the docker image is accidentally looking like version 8 or latest + // can happen if Elasticsearch is repackaged, i.e. with custom plugins + log.warn("CA cert under " + certPath + " not found."); + } + return Optional.empty(); } /** - * A SSL context based on the self signed CA, so that using this SSL Context allows to connect to the Elasticsearch service + * A SSL context based on the self-signed CA, so that using this SSL Context allows to connect to the Elasticsearch service * @return a customized SSL Context */ public SSLContext createSslContextFromCa() { try { CertificateFactory factory = CertificateFactory.getInstance("X.509"); - Certificate trustedCa = factory.generateCertificate(new ByteArrayInputStream(caCertAsBytes.get())); + Certificate trustedCa = factory.generateCertificate( + new ByteArrayInputStream( + caCertAsBytes() + .orElseThrow(() -> new IllegalStateException("CA cert under " + certPath + " not found.")) + ) + ); KeyStore trustStore = KeyStore.getInstance("pkcs12"); trustStore.load(null, null); trustStore.setCertificateEntry("ca", trustedCa); @@ -190,13 +195,13 @@ public SSLContext createSslContextFromCa() { /** * Define the Elasticsearch password to set. It enables security behind the scene for major version below 8.0.0. * It's not possible to use security with the oss image. - * @param password Password to set + * @param password Password to set * @return this */ public ElasticsearchContainer withPassword(String password) { if (isOss) { throw new IllegalArgumentException( - "You can not activate security on Elastic OSS Image. " + "Please switch to the default distribution" + "You can not activate security on Elastic OSS Image. Please switch to the default distribution" ); } withEnv("ELASTIC_PASSWORD", password); @@ -222,7 +227,8 @@ public String getHttpHostAddress() { return getHost() + ":" + getMappedPort(ELASTICSEARCH_DEFAULT_PORT); } - @Deprecated // The TransportClient will be removed in Elasticsearch 8. No need to expose this port anymore in the future. + // The TransportClient will be removed in Elasticsearch 8. No need to expose this port anymore in the future. + @Deprecated public InetSocketAddress getTcpHost() { return new InetSocketAddress(getHost(), getMappedPort(ELASTICSEARCH_DEFAULT_TCP_PORT)); } diff --git a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java index 2b832f28a16..555cec58083 100644 --- a/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java +++ b/modules/elasticsearch/src/test/java/org/testcontainers/elasticsearch/ElasticsearchContainerTest.java @@ -23,6 +23,7 @@ import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.images.RemoteDockerImage; +import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.DockerImageName; import org.testcontainers.utility.MountableFile; @@ -375,6 +376,49 @@ public void testElasticsearch8SecureByDefaultFailsSilentlyOnLatestImages() throw } } + @Test + public void testElasticsearch7CanHaveSecurityEnabledAndUseSslContext() throws Exception { + String customizedCertPath = "/usr/share/elasticsearch/config/certs/http_ca_customized.crt"; + try ( + ElasticsearchContainer container = new ElasticsearchContainer( + "docker.elastic.co/elasticsearch/elasticsearch:7.17.15" + ) + .withPassword(ElasticsearchContainer.ELASTICSEARCH_DEFAULT_PASSWORD) + .withEnv("xpack.security.enabled", "true") + .withEnv("xpack.security.http.ssl.enabled", "true") + .withEnv("xpack.security.http.ssl.key", "/usr/share/elasticsearch/config/certs/elasticsearch.key") + .withEnv( + "xpack.security.http.ssl.certificate", + "/usr/share/elasticsearch/config/certs/elasticsearch.crt" + ) + .withEnv("xpack.security.http.ssl.certificate_authorities", customizedCertPath) + // these lines show how certificates can be created self-made way + // obviously this shouldn't be done in prod environment, where proper and officially signed keys should be present + .withCopyToContainer( + Transferable.of( + "#!/bin/bash\n" + + "mkdir -p /usr/share/elasticsearch/config/certs;" + + "openssl req -x509 -newkey rsa:4096 -keyout /usr/share/elasticsearch/config/certs/elasticsearch.key -out /usr/share/elasticsearch/config/certs/elasticsearch.crt -days 365 -nodes -subj \"/CN=localhost\";" + + "openssl x509 -outform der -in /usr/share/elasticsearch/config/certs/elasticsearch.crt -out " + + customizedCertPath + + "; chown -R elasticsearch /usr/share/elasticsearch/config/certs/", + 555 + ), + "/usr/share/elasticsearch/generate-certs.sh" + ) + // because we need to generate the certificates before Elasticsearch starts, the entry command has to be tuned accordingly + .withCommand( + "sh", + "-c", + "/usr/share/elasticsearch/generate-certs.sh && /usr/local/bin/docker-entrypoint.sh" + ) + .withCertPath(customizedCertPath) + ) { + container.start(); + assertClusterHealthResponse(container); + } + } + @Test public void testElasticsearchDefaultMaxHeapSize() throws Exception { long defaultHeapSize = 2147483648L; From 5eea807d1285b28a80f8cb2698dd9bb74cfad4ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 22:35:49 +0000 Subject: [PATCH 0041/1430] Bump com.orientechnologies:orientdb-client in /modules/orientdb Bumps [com.orientechnologies:orientdb-client](https://github.com/orientechnologies/orientdb) from 3.2.26 to 3.2.29. - [Release notes](https://github.com/orientechnologies/orientdb/releases) - [Changelog](https://github.com/orientechnologies/orientdb/blob/3.2.29/history.txt) - [Commits](https://github.com/orientechnologies/orientdb/compare/3.2.26...3.2.29) --- updated-dependencies: - dependency-name: com.orientechnologies:orientdb-client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/orientdb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/orientdb/build.gradle b/modules/orientdb/build.gradle index 09e47b14ce7..af3dd5c8890 100644 --- a/modules/orientdb/build.gradle +++ b/modules/orientdb/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Orientdb" dependencies { api project(":testcontainers") - api "com.orientechnologies:orientdb-client:3.2.26" + api "com.orientechnologies:orientdb-client:3.2.29" testImplementation 'org.assertj:assertj-core:3.25.1' testImplementation 'org.apache.tinkerpop:gremlin-driver:3.7.1' From ce3315d56c2975077c9c4e769d29534e262d93be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Tue, 5 Mar 2024 14:38:47 -0600 Subject: [PATCH 0042/1430] Fix ollama docs --- docs/modules/ollama.md | 2 +- .../java/org/testcontainers/ollama/OllamaContainerTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/modules/ollama.md b/docs/modules/ollama.md index 98d9c204966..e54ee824938 100644 --- a/docs/modules/ollama.md +++ b/docs/modules/ollama.md @@ -29,7 +29,7 @@ In order to create a new image that contains the model, you can use the followin And use the new image along with [Image name Substitution](../features/image_name_substitution.md#manual-substitution) -[Use new Image](../../modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java) inside_block:containerSubstitute +[Use new Image](../../modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java) inside_block:substitute ## Adding this module to your project dependencies diff --git a/modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java b/modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java index cefd665b044..96118f50be6 100644 --- a/modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java +++ b/modules/ollama/src/test/java/org/testcontainers/ollama/OllamaContainerTest.java @@ -44,7 +44,7 @@ public void downloadModelAndCommitToImage() throws IOException, InterruptedExcep // } } try ( - // containerSubstitute { + // substitute { OllamaContainer ollama = new OllamaContainer( DockerImageName.parse(newImageName).asCompatibleSubstituteFor("ollama/ollama") ) From 57468bbec46bc62336bb522b98132ef2ed6eb0d4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 5 Mar 2024 18:41:47 -0500 Subject: [PATCH 0043/1430] Update testcontainers version to 1.19.7 (#8429) Co-authored-by: eddumelendez --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 26b4b4f0c26..a8d90824f3b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,4 +3,4 @@ org.gradle.caching=true org.gradle.configureondemand=true org.gradle.jvmargs=-Xmx2g -testcontainers.version=1.19.6 +testcontainers.version=1.19.7 From eb7af26593226d88be58c2d85e8411f82449b076 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 5 Mar 2024 18:42:08 -0500 Subject: [PATCH 0044/1430] Update docs version to 1.19.7 (#8428) Co-authored-by: eddumelendez --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index d5f5b275288..0beb5e182a3 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -132,4 +132,4 @@ nav: - bounty.md edit_uri: edit/main/docs/ extra: - latest_version: 1.19.6 + latest_version: 1.19.7 From d3b0df2d89ee349890c94b0ce220a167c82ddf51 Mon Sep 17 00:00:00 2001 From: colin lee <39513055@qq.com> Date: Thu, 7 Mar 2024 03:42:18 +0800 Subject: [PATCH 0045/1430] Add getDatabaseName() method to ClickHouseContainer (#8339) --- .../org/testcontainers/clickhouse/ClickHouseContainer.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/clickhouse/src/main/java/org/testcontainers/clickhouse/ClickHouseContainer.java b/modules/clickhouse/src/main/java/org/testcontainers/clickhouse/ClickHouseContainer.java index ffa1307204a..f65177ce68a 100644 --- a/modules/clickhouse/src/main/java/org/testcontainers/clickhouse/ClickHouseContainer.java +++ b/modules/clickhouse/src/main/java/org/testcontainers/clickhouse/ClickHouseContainer.java @@ -97,6 +97,11 @@ public String getPassword() { return password; } + @Override + public String getDatabaseName() { + return databaseName; + } + @Override public String getTestQueryString() { return TEST_QUERY; From 5bb96072a1d469d96d273dc48db15db8ca8ab5b9 Mon Sep 17 00:00:00 2001 From: Marcin Antas Date: Sat, 9 Mar 2024 23:50:38 +0100 Subject: [PATCH 0046/1430] Add method for getting Weaviate's gRPC port (#8431) --- modules/weaviate/build.gradle | 2 +- .../org/testcontainers/weaviate/WeaviateContainer.java | 4 ++++ .../testcontainers/weaviate/WeaviateContainerTest.java | 8 +++++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/modules/weaviate/build.gradle b/modules/weaviate/build.gradle index 06a77aa434a..b96c4075d25 100644 --- a/modules/weaviate/build.gradle +++ b/modules/weaviate/build.gradle @@ -4,5 +4,5 @@ dependencies { api project(':testcontainers') testImplementation 'org.assertj:assertj-core:3.25.1' - testImplementation 'io.weaviate:client:4.5.1' + testImplementation 'io.weaviate:client:4.6.0' } diff --git a/modules/weaviate/src/main/java/org/testcontainers/weaviate/WeaviateContainer.java b/modules/weaviate/src/main/java/org/testcontainers/weaviate/WeaviateContainer.java index bd217b13e75..c8920a4cfb9 100644 --- a/modules/weaviate/src/main/java/org/testcontainers/weaviate/WeaviateContainer.java +++ b/modules/weaviate/src/main/java/org/testcontainers/weaviate/WeaviateContainer.java @@ -33,4 +33,8 @@ public WeaviateContainer(DockerImageName dockerImageName) { public String getHttpHostAddress() { return getHost() + ":" + getMappedPort(8080); } + + public String getGrpcHostAddress() { + return getHost() + ":" + getMappedPort(50051); + } } diff --git a/modules/weaviate/src/test/java/org/testcontainers/weaviate/WeaviateContainerTest.java b/modules/weaviate/src/test/java/org/testcontainers/weaviate/WeaviateContainerTest.java index 562fc36de51..9aa8fe19f61 100644 --- a/modules/weaviate/src/test/java/org/testcontainers/weaviate/WeaviateContainerTest.java +++ b/modules/weaviate/src/test/java/org/testcontainers/weaviate/WeaviateContainerTest.java @@ -13,13 +13,15 @@ public class WeaviateContainerTest { @Test public void test() { try ( // container { - WeaviateContainer weaviate = new WeaviateContainer("semitechnologies/weaviate:1.22.4") + WeaviateContainer weaviate = new WeaviateContainer("semitechnologies/weaviate:1.24.1") // } ) { weaviate.start(); - WeaviateClient client = new WeaviateClient(new Config("http", weaviate.getHttpHostAddress())); + Config config = new Config("http", weaviate.getHttpHostAddress()); + config.setGRPCHost(weaviate.getGrpcHostAddress()); + WeaviateClient client = new WeaviateClient(config); Result meta = client.misc().metaGetter().run(); - assertThat(meta.getResult().getVersion()).isEqualTo("1.22.4"); + assertThat(meta.getResult().getVersion()).isEqualTo("1.24.1"); } } } From 267d609cd839d9b84b1dbcd139f1326c329772ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 22:07:37 +0000 Subject: [PATCH 0047/1430] Bump redis.clients:jedis from 5.1.0 to 5.1.2 in /modules/junit-jupiter Bumps [redis.clients:jedis](https://github.com/redis/jedis) from 5.1.0 to 5.1.2. - [Release notes](https://github.com/redis/jedis/releases) - [Commits](https://github.com/redis/jedis/compare/v5.1.0...v5.1.2) --- updated-dependencies: - dependency-name: redis.clients:jedis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 95e0e7b1223..04a2f584acc 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:5.1.0' + testImplementation 'redis.clients:jedis:5.1.2' testImplementation 'org.apache.httpcomponents:httpclient:4.5.14' testImplementation ('org.mockito:mockito-core:4.11.0') { exclude(module: 'hamcrest-core') From 59267693e66da68e10a636f5752f5827c0725e1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Wed, 13 Mar 2024 13:32:58 -0500 Subject: [PATCH 0048/1430] [redpanda] Override entrypoint (#8450) Currently, cmd has declared the full command. Overriding the entrypoint will fix the container execution with other container runtimes. Fixes #8432 --- .../java/org/testcontainers/redpanda/RedpandaContainer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 cc1d07c883a..8960487e39b 100644 --- a/modules/redpanda/src/main/java/org/testcontainers/redpanda/RedpandaContainer.java +++ b/modules/redpanda/src/main/java/org/testcontainers/redpanda/RedpandaContainer.java @@ -92,7 +92,7 @@ public RedpandaContainer(DockerImageName imageName) { withExposedPorts(REDPANDA_PORT, REDPANDA_ADMIN_PORT, SCHEMA_REGISTRY_PORT, REST_PROXY_PORT); withCreateContainerCmdModifier(cmd -> { - cmd.withEntrypoint(); + cmd.withEntrypoint("/entrypoint-tc.sh"); cmd.withUser("root:root"); }); waitingFor(Wait.forLogMessage(".*Successfully started Redpanda!.*", 1)); @@ -100,7 +100,7 @@ public RedpandaContainer(DockerImageName imageName) { MountableFile.forClasspathResource("testcontainers/entrypoint-tc.sh", 0700), "/entrypoint-tc.sh" ); - withCommand("/entrypoint-tc.sh", "redpanda", "start", "--mode=dev-container", "--smp=1", "--memory=1G"); + withCommand("redpanda", "start", "--mode=dev-container", "--smp=1", "--memory=1G"); } @Override From 358f68a63a8450ca22626071232b044824f93564 Mon Sep 17 00:00:00 2001 From: Silvio Giebl Date: Wed, 13 Mar 2024 20:50:45 +0100 Subject: [PATCH 0049/1430] Handle `Created` empty field from image inspect (#8302) - For docker engine versions up to 24.0.x: Created="0001-01-01T00:00:00Z" for all API versions (max 1.43) - For docker engine versions 25.0.0-25.0.3: Created="" for all API versions (max 1.44) => this is considered a bug - For docker engine versions 25.0.4+: - Created="0001-01-01T00:00:00Z" for API versions up to 1.43 (backwards compatibility) - Created is absent for API versions 1.44+ --- .../java/org/testcontainers/images/ImageData.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/testcontainers/images/ImageData.java b/core/src/main/java/org/testcontainers/images/ImageData.java index 694b7ef6528..5b9f8227924 100644 --- a/core/src/main/java/org/testcontainers/images/ImageData.java +++ b/core/src/main/java/org/testcontainers/images/ImageData.java @@ -17,13 +17,16 @@ public class ImageData { Instant createdAt; static ImageData from(InspectImageResponse inspectImageResponse) { - return ImageData - .builder() - .createdAt(ZonedDateTime.parse(inspectImageResponse.getCreated()).toInstant()) - .build(); + final String created = inspectImageResponse.getCreated(); + final Instant createdInstant = ((created == null) || created.isEmpty()) + ? Instant.EPOCH + : ZonedDateTime.parse(created).toInstant(); + return ImageData.builder().createdAt(createdInstant).build(); } static ImageData from(Image image) { - return ImageData.builder().createdAt(Instant.ofEpochSecond(image.getCreated())).build(); + final Long created = image.getCreated(); + final Instant createdInstant = (created == null) ? Instant.EPOCH : Instant.ofEpochSecond(created); + return ImageData.builder().createdAt(createdInstant).build(); } } From 8c3cce2b2c38d555eeecfcd7f754d3231d7a6f78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 14 Mar 2024 02:18:40 -0500 Subject: [PATCH 0050/1430] Update ryuk version to 0.7.0 (#8451) --- .../src/main/java/org/testcontainers/utility/RyukContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/utility/RyukContainer.java b/core/src/main/java/org/testcontainers/utility/RyukContainer.java index 01c68f4b8a3..61bceb60b0b 100644 --- a/core/src/main/java/org/testcontainers/utility/RyukContainer.java +++ b/core/src/main/java/org/testcontainers/utility/RyukContainer.java @@ -9,7 +9,7 @@ class RyukContainer extends GenericContainer { RyukContainer() { - super("testcontainers/ryuk:0.6.0"); + super("testcontainers/ryuk:0.7.0"); withExposedPorts(8080); withCreateContainerCmdModifier(cmd -> { cmd.withName("testcontainers-ryuk-" + DockerClientFactory.SESSION_ID); From 6e5fbe62d5c52aac62d630f21652c59fbff50d3d Mon Sep 17 00:00:00 2001 From: Nateckert Date: Fri, 15 Mar 2024 00:57:51 +0100 Subject: [PATCH 0051/1430] Avoid usage of the non monotonic clock System.currentTimeMillis() in favor of System.nanoTime() (#6392) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Eddú Meléndez Gonzales --- .../containers/output/WaitingConsumer.java | 18 +++++++++++------- .../junit/GenericContainerRuleTest.java | 8 ++++---- .../org/testcontainers/ext/ScriptUtils.java | 5 +++-- .../containers/JdbcDatabaseContainer.java | 9 +++++---- .../containers/ToxiproxyTest.java | 7 ++++--- 5 files changed, 27 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/output/WaitingConsumer.java b/core/src/main/java/org/testcontainers/containers/output/WaitingConsumer.java index b7a12167597..e79c234058e 100644 --- a/core/src/main/java/org/testcontainers/containers/output/WaitingConsumer.java +++ b/core/src/main/java/org/testcontainers/containers/output/WaitingConsumer.java @@ -42,7 +42,7 @@ public LinkedBlockingDeque getFrames() { * @param predicate a predicate to test against each frame */ public void waitUntil(Predicate predicate) throws TimeoutException { - // ~2.9 million centuries ought to be enough for anyone + // ~2.9 thousands centuries ought to be enough for anyone waitUntil(predicate, Long.MAX_VALUE, 1); } @@ -73,14 +73,18 @@ public void waitUntil(Predicate predicate, int limit, TimeUnit limi */ public void waitUntil(Predicate predicate, long limit, TimeUnit limitUnit, int times) throws TimeoutException { - long expiry = limitUnit.toMillis(limit) + System.currentTimeMillis(); + long timeoutLimitInNanos = limitUnit.toNanos(limit); - waitUntil(predicate, expiry, times); + waitUntil(predicate, timeoutLimitInNanos, times); } - private void waitUntil(Predicate predicate, long expiry, int times) throws TimeoutException { + private void waitUntil(Predicate predicate, long timeoutLimitInNanos, int times) + throws TimeoutException { int numberOfMatches = 0; - while (System.currentTimeMillis() < expiry) { + + final long startTime = System.nanoTime(); + + while (System.nanoTime() - startTime < timeoutLimitInNanos) { try { final OutputFrame frame = frames.pollLast(100, TimeUnit.MILLISECONDS); @@ -128,13 +132,13 @@ public void waitUntilEnd() { * @param limitUnit maximum time to wait (units) */ public void waitUntilEnd(long limit, TimeUnit limitUnit) throws TimeoutException { - long expiry = limitUnit.toMillis(limit) + System.currentTimeMillis(); + long expiry = limitUnit.toNanos(limit) + System.nanoTime(); waitUntilEnd(expiry); } private void waitUntilEnd(Long expiry) throws TimeoutException { - while (System.currentTimeMillis() < expiry) { + while (System.nanoTime() < expiry) { try { OutputFrame frame = frames.pollLast(100, TimeUnit.MILLISECONDS); diff --git a/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java b/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java index fc08e11107a..5a9d7c1616d 100644 --- a/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java +++ b/core/src/test/java/org/testcontainers/junit/GenericContainerRuleTest.java @@ -333,7 +333,7 @@ protected static void writeStringToFile(File contentFolder, String filename, Str @Test @Ignore //TODO investigate intermittent failures public void failFastWhenContainerHaltsImmediately() { - long startingTimeMs = System.currentTimeMillis(); + long startingTimeNano = System.nanoTime(); final GenericContainer failsImmediately = new GenericContainer<>(TestImages.ALPINE_IMAGE) .withCommand("/bin/sh", "-c", "return false") .withMinimumRunningDuration(Duration.ofMillis(100)); @@ -345,11 +345,11 @@ public void failFastWhenContainerHaltsImmediately() { // Check how long it took, to verify that we ARE bailing out early. // Want to strike a balance here; too short and this test will fail intermittently - // on slow systems and/or due to GC variation, too long and we won't properly test + // on slow systems and/or due to GC variation, too long, and we won't properly test // what we're intending to test. int allowedSecondsToFailure = GenericContainer.CONTAINER_RUNNING_TIMEOUT_SEC / 2; - long completedTimeMs = System.currentTimeMillis(); - assertThat(completedTimeMs - startingTimeMs < 1000L * allowedSecondsToFailure) + long completedTimeNano = System.nanoTime(); + assertThat(completedTimeNano - startingTimeNano < TimeUnit.SECONDS.toNanos(allowedSecondsToFailure)) .as("container should not take long to start up") .isTrue(); } finally { diff --git a/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java b/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java index 419bcbf9e9a..b78ac4d63c4 100644 --- a/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java +++ b/modules/database-commons/src/main/java/org/testcontainers/ext/ScriptUtils.java @@ -27,6 +27,7 @@ import java.nio.charset.StandardCharsets; import java.util.LinkedList; import java.util.List; +import java.util.concurrent.TimeUnit; import javax.script.ScriptException; @@ -273,7 +274,7 @@ public static void executeDatabaseScript( LOGGER.info("Executing database script from " + scriptPath); } - long startTime = System.currentTimeMillis(); + long startTime = System.nanoTime(); List statements = new LinkedList<>(); if (separator == null) { @@ -306,7 +307,7 @@ public static void executeDatabaseScript( closeableDelegate.execute(statements, scriptPath, continueOnError, ignoreFailedDrops); } - long elapsedTime = System.currentTimeMillis() - startTime; + long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime); if (LOGGER.isInfoEnabled()) { LOGGER.info("Executed database script from " + scriptPath + " in " + elapsedTime + " ms."); } diff --git a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java index 9533a4c7d10..2247b2e867f 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java +++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java @@ -21,6 +21,7 @@ import java.util.Map; import java.util.Properties; import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** @@ -148,10 +149,10 @@ protected void waitUntilContainerStarted() { ); // Repeatedly try and open a connection to the DB and execute a test query - long start = System.currentTimeMillis(); + long start = System.nanoTime(); Exception lastConnectionException = null; - while (System.currentTimeMillis() < start + (1000 * startupTimeoutSeconds)) { + while ((System.nanoTime() - start) < TimeUnit.SECONDS.toNanos(startupTimeoutSeconds)) { if (!isRunning()) { Thread.sleep(100L); } else { @@ -238,9 +239,9 @@ public Connection createConnection(String queryString, Properties info) SQLException lastException = null; try { - long start = System.currentTimeMillis(); + long start = System.nanoTime(); // give up if we hit the time limit or the container stops running for some reason - while (System.currentTimeMillis() < start + (1000 * connectTimeoutSeconds) && isRunning()) { + while ((System.nanoTime() - start < TimeUnit.SECONDS.toNanos(connectTimeoutSeconds)) && isRunning()) { try { logger() .debug( diff --git a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java index f1010758fba..34068e5e49e 100644 --- a/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java +++ b/modules/toxiproxy/src/test/java/org/testcontainers/containers/ToxiproxyTest.java @@ -10,6 +10,7 @@ import java.io.IOException; import java.time.Duration; +import java.util.concurrent.TimeUnit; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; @@ -181,10 +182,10 @@ private void checkCallWithLatency( int expectedMinLatency, long expectedMaxLatency ) { - final long start = System.currentTimeMillis(); + final long start = System.nanoTime(); String s = jedis.get("somekey"); - final long end = System.currentTimeMillis(); - final long duration = end - start; + final long end = System.nanoTime(); + final long duration = TimeUnit.NANOSECONDS.toMillis(end - start); assertThat(s).as(String.format("access to the container %s works OK", description)).isEqualTo("somevalue"); assertThat(duration >= expectedMinLatency) From 13c2641ff1ff8e74f37594bff96275811a7d809b Mon Sep 17 00:00:00 2001 From: Gabriel Luciano de Souza <66069864+gabrielluciano@users.noreply.github.com> Date: Fri, 15 Mar 2024 03:14:36 -0300 Subject: [PATCH 0052/1430] [mongodb] Fix getConnectionString javadoc (#8129) --- .../java/org/testcontainers/containers/MongoDBContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java index 17adc794530..1dbf1fcc74e 100644 --- a/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java +++ b/modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java @@ -95,7 +95,7 @@ protected void containerIsStarted(InspectContainerResponse containerInfo, boolea } /** - * Gets a connection string url, unlike {@link #getReplicaSetUrl} this does point to a + * Gets a connection string url, unlike {@link #getReplicaSetUrl} this does not point to a * database * @return a connection url pointing to a mongodb instance */ From 285aac92c62542e7b99a0f04f65cb28e2d0606ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:04:02 +0000 Subject: [PATCH 0053/1430] Bump org.postgresql:postgresql in /modules/postgresql Bumps [org.postgresql:postgresql](https://github.com/pgjdbc/pgjdbc) from 42.7.1 to 42.7.3. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.7.1...REL42.7.3) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/postgresql/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/postgresql/build.gradle b/modules/postgresql/build.gradle index 0177c8c6b0e..aa06a2d0249 100644 --- a/modules/postgresql/build.gradle +++ b/modules/postgresql/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'io.r2dbc:r2dbc-postgresql:0.8.13.RELEASE' testImplementation project(':jdbc-test') - testRuntimeOnly 'org.postgresql:postgresql:42.7.1' + testRuntimeOnly 'org.postgresql:postgresql:42.7.3' testImplementation testFixtures(project(':r2dbc')) testRuntimeOnly 'io.r2dbc:r2dbc-postgresql:0.8.13.RELEASE' From 8f9608b8f908d23b27e8fd6d6eaf8a3dd0a1ea40 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:08:51 +0000 Subject: [PATCH 0054/1430] Bump org.postgresql:postgresql from 42.7.1 to 42.7.3 in /modules/cratedb Bumps [org.postgresql:postgresql](https://github.com/pgjdbc/pgjdbc) from 42.7.1 to 42.7.3. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.7.1...REL42.7.3) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/cratedb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cratedb/build.gradle b/modules/cratedb/build.gradle index 683b9c1a373..8240d805b13 100644 --- a/modules/cratedb/build.gradle +++ b/modules/cratedb/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testRuntimeOnly 'org.postgresql:postgresql:42.7.1' + testRuntimeOnly 'org.postgresql:postgresql:42.7.3' compileOnly 'org.jetbrains:annotations:24.1.0' } From bb6e87337eaf1ceb347e32745c798d7d0fa095f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:25:02 +0000 Subject: [PATCH 0055/1430] Bump org.awaitility:awaitility from 4.2.0 to 4.2.1 in /modules/solace Bumps [org.awaitility:awaitility](https://github.com/awaitility/awaitility) from 4.2.0 to 4.2.1. - [Changelog](https://github.com/awaitility/awaitility/blob/master/changelog.txt) - [Commits](https://github.com/awaitility/awaitility/compare/awaitility-4.2.0...awaitility-4.2.1) --- updated-dependencies: - dependency-name: org.awaitility:awaitility dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/solace/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/solace/build.gradle b/modules/solace/build.gradle index c4a231c4aec..e2597bc62fa 100644 --- a/modules/solace/build.gradle +++ b/modules/solace/build.gradle @@ -3,7 +3,7 @@ description = "Testcontainers :: Solace" dependencies { api project(':testcontainers') - shaded 'org.awaitility:awaitility:4.2.0' + shaded 'org.awaitility:awaitility:4.2.1' testImplementation 'org.assertj:assertj-core:3.25.1' testImplementation 'com.solacesystems:sol-jcsmp:10.22.0' From 569892f41574c0e1968f9c914537a229e22bf898 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:33:11 +0000 Subject: [PATCH 0056/1430] Bump org.awaitility:awaitility from 4.2.0 to 4.2.1 in /modules/questdb Bumps [org.awaitility:awaitility](https://github.com/awaitility/awaitility) from 4.2.0 to 4.2.1. - [Changelog](https://github.com/awaitility/awaitility/blob/master/changelog.txt) - [Commits](https://github.com/awaitility/awaitility/compare/awaitility-4.2.0...awaitility-4.2.1) --- updated-dependencies: - dependency-name: org.awaitility:awaitility dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/questdb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/questdb/build.gradle b/modules/questdb/build.gradle index 1850ed0fe34..7ebf29cb551 100644 --- a/modules/questdb/build.gradle +++ b/modules/questdb/build.gradle @@ -8,7 +8,7 @@ dependencies { testImplementation project(':jdbc-test') testImplementation 'org.assertj:assertj-core:3.25.2' testImplementation 'org.questdb:questdb:7.3.9' - testImplementation 'org.awaitility:awaitility:4.2.0' + testImplementation 'org.awaitility:awaitility:4.2.1' testImplementation 'org.apache.httpcomponents:httpclient:4.5.14' } From ca1f973cda1c0344be4eb2613c02e38ff7ca87cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:33:15 +0000 Subject: [PATCH 0057/1430] Bump org.postgresql:postgresql from 42.7.1 to 42.7.3 in /modules/questdb Bumps [org.postgresql:postgresql](https://github.com/pgjdbc/pgjdbc) from 42.7.1 to 42.7.3. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.7.1...REL42.7.3) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/questdb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/questdb/build.gradle b/modules/questdb/build.gradle index 1850ed0fe34..54d6ff2233f 100644 --- a/modules/questdb/build.gradle +++ b/modules/questdb/build.gradle @@ -4,7 +4,7 @@ dependencies { api project(':testcontainers') api project(':jdbc') - testRuntimeOnly 'org.postgresql:postgresql:42.7.1' + testRuntimeOnly 'org.postgresql:postgresql:42.7.3' testImplementation project(':jdbc-test') testImplementation 'org.assertj:assertj-core:3.25.2' testImplementation 'org.questdb:questdb:7.3.9' From 2ea4a0dbd979a1a2b7f0a667742e4079a0b70e06 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:37:38 +0000 Subject: [PATCH 0058/1430] Bump org.postgresql:postgresql in /modules/cockroachdb Bumps [org.postgresql:postgresql](https://github.com/pgjdbc/pgjdbc) from 42.7.1 to 42.7.3. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.7.1...REL42.7.3) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/cockroachdb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cockroachdb/build.gradle b/modules/cockroachdb/build.gradle index 82b55fd7e5e..e7a4d963c51 100644 --- a/modules/cockroachdb/build.gradle +++ b/modules/cockroachdb/build.gradle @@ -4,6 +4,6 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') - testRuntimeOnly 'org.postgresql:postgresql:42.7.1' + testRuntimeOnly 'org.postgresql:postgresql:42.7.3' testImplementation 'org.assertj:assertj-core:3.25.1' } From 5d97d9b30ab5fee9bceabcfc4787a04fc4c07a23 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:39:58 +0000 Subject: [PATCH 0059/1430] Bump org.postgresql:postgresql in /modules/junit-jupiter Bumps [org.postgresql:postgresql](https://github.com/pgjdbc/pgjdbc) from 42.7.1 to 42.7.3. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.7.1...REL42.7.3) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/junit-jupiter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/junit-jupiter/build.gradle b/modules/junit-jupiter/build.gradle index 95e0e7b1223..723eef713e6 100644 --- a/modules/junit-jupiter/build.gradle +++ b/modules/junit-jupiter/build.gradle @@ -16,7 +16,7 @@ dependencies { testImplementation 'org.assertj:assertj-core:3.25.1' testImplementation 'org.junit.jupiter:junit-jupiter' - testRuntimeOnly 'org.postgresql:postgresql:42.7.1' + testRuntimeOnly 'org.postgresql:postgresql:42.7.3' testRuntimeOnly 'mysql:mysql-connector-java:8.0.33' } From b0befbfa433951fc44ea974291d611b69eacf343 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:42:30 +0000 Subject: [PATCH 0060/1430] Bump org.postgresql:postgresql from 42.7.1 to 42.7.3 in /modules/spock Bumps [org.postgresql:postgresql](https://github.com/pgjdbc/pgjdbc) from 42.7.1 to 42.7.3. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.7.1...REL42.7.3) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/spock/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/spock/build.gradle b/modules/spock/build.gradle index 98ff9b6520b..5c9c6adabbc 100644 --- a/modules/spock/build.gradle +++ b/modules/spock/build.gradle @@ -15,7 +15,7 @@ dependencies { testImplementation 'com.zaxxer:HikariCP:4.0.3' testImplementation 'org.apache.httpcomponents:httpclient:4.5.14' - testRuntimeOnly 'org.postgresql:postgresql:42.7.1' + testRuntimeOnly 'org.postgresql:postgresql:42.7.3' testRuntimeOnly 'mysql:mysql-connector-java:8.0.33' testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.10.1' testRuntimeOnly 'org.junit.platform:junit-platform-testkit:1.10.1' From c177fb2938a25b128338edcc83d96c779ff0af3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:56:46 +0000 Subject: [PATCH 0061/1430] Bump org.awaitility:awaitility from 4.2.0 to 4.2.1 in /core Bumps [org.awaitility:awaitility](https://github.com/awaitility/awaitility) from 4.2.0 to 4.2.1. - [Changelog](https://github.com/awaitility/awaitility/blob/master/changelog.txt) - [Commits](https://github.com/awaitility/awaitility/compare/awaitility-4.2.0...awaitility-4.2.1) --- updated-dependencies: - dependency-name: org.awaitility:awaitility dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- core/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/build.gradle b/core/build.gradle index 13152748815..9ba4c6a8760 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -86,7 +86,7 @@ dependencies { exclude group: 'org.apache.commons', module: 'commons-compress' } - shaded 'org.awaitility:awaitility:4.2.0' + shaded 'org.awaitility:awaitility:4.2.1' api platform('com.github.docker-java:docker-java-bom:3.3.6') shaded platform('com.github.docker-java:docker-java-bom:3.3.6') From c187c36d3753e82fb5d7f851f0673cd943388d18 Mon Sep 17 00:00:00 2001 From: sullis Date: Thu, 21 Mar 2024 09:38:30 -0700 Subject: [PATCH 0062/1430] Update actions/setup-java version to v4 (#8475) --- .github/actions/setup-java/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup-java/action.yml b/.github/actions/setup-java/action.yml index 8d9733f02ba..053b7ebe23b 100644 --- a/.github/actions/setup-java/action.yml +++ b/.github/actions/setup-java/action.yml @@ -3,7 +3,7 @@ description: Sets up Java version runs: using: "composite" steps: - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: java-version: '8' distribution: temurin From 030ce5afaf12617c0db2eb1a4f064c25f3eb5c7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Thu, 21 Mar 2024 15:25:28 -0600 Subject: [PATCH 0063/1430] Update check list in settings --- .github/settings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/settings.yml b/.github/settings.yml index 9cf3d27d5d4..bcf94d2d711 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -388,7 +388,7 @@ branches: # Required. Require branches to be up to date before merging. strict: true # Required. The list of status checks to require in order to merge into this branch - contexts: ["core", "check_docs_examples", "in-docker_test", "ci/circleci: minimal_core", "test"] + contexts: ["core", "check_docs_examples (:docs:examples:check)", "in-docker_test", "ci/circleci: minimal_core", "test"] # Required. Enforce all configured restrictions for administrators. Set to true to enforce required status checks for repository administrators. Set to null to disable. enforce_admins: false # Prevent merge commits from being pushed to matching branches From 021c71fb3b110526dc6be7b854757a0e4731e878 Mon Sep 17 00:00:00 2001 From: Jared Komoroski Date: Thu, 21 Mar 2024 18:11:20 -0600 Subject: [PATCH 0064/1430] Add an interval for pull attempts (#8453) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without an interval attempt limit, thousands of docker pull requests can be attempted the default 2 minute time limit. Fixes #8454 --------- Co-authored-by: Eddú Meléndez --- .../images/RemoteDockerImage.java | 122 ++++++++++++------ 1 file changed, 80 insertions(+), 42 deletions(-) diff --git a/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java b/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java index 78a0e2a583c..af3ed08984a 100644 --- a/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java +++ b/core/src/main/java/org/testcontainers/images/RemoteDockerImage.java @@ -11,6 +11,9 @@ import lombok.SneakyThrows; import lombok.ToString; import lombok.With; +import org.awaitility.Awaitility; +import org.awaitility.pollinterval.IterativePollInterval; +import org.awaitility.pollinterval.PollInterval; import org.slf4j.Logger; import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.ContainerFetchException; @@ -21,9 +24,11 @@ import java.time.Duration; import java.time.Instant; +import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicReference; @ToString @AllArgsConstructor(access = AccessLevel.PACKAGE) @@ -65,7 +70,7 @@ public RemoteDockerImage(@NonNull Future imageFuture) { @SneakyThrows({ InterruptedException.class, ExecutionException.class }) protected final String resolve() { final DockerImageName imageName = getImageName(); - Logger logger = DockerLoggerFactory.getLogger(imageName.toString()); + final Logger logger = DockerLoggerFactory.getLogger(imageName.toString()); try { if (!imagePullPolicy.shouldPull(imageName)) { return imageName.asCanonicalNameString(); @@ -77,55 +82,88 @@ protected final String resolve() { imageName ); - Exception lastFailure = null; + final Instant startedAt = Instant.now(); final Instant lastRetryAllowed = Instant.now().plus(PULL_RETRY_TIME_LIMIT); - - Instant startedAt = Instant.now(); - while (Instant.now().isBefore(lastRetryAllowed)) { - try { - PullImageCmd pullImageCmd = dockerClient - .pullImageCmd(imageName.getUnversionedPart()) - .withTag(imageName.getVersionPart()); - - try { - pullImageCmd.exec(new TimeLimitedLoggedPullImageResultCallback(logger)).awaitCompletion(); - } catch (DockerClientException e) { - // Try to fallback to x86 - pullImageCmd - .withPlatform("linux/amd64") - .exec(new TimeLimitedLoggedPullImageResultCallback(logger)) - .awaitCompletion(); - } - String dockerImageName = imageName.asCanonicalNameString(); - logger.info("Image {} pull took {}", dockerImageName, Duration.between(startedAt, Instant.now())); - - LocalImagesCache.INSTANCE.refreshCache(imageName); - - return dockerImageName; - } catch (InterruptedException | InternalServerErrorException e) { - // these classes of exception often relate to timeout/connection errors so should be retried - lastFailure = e; - logger.warn( - "Retrying pull for image: {} ({}s remaining)", - imageName, - Duration.between(Instant.now(), lastRetryAllowed).getSeconds() - ); - } + final AtomicReference lastFailure = new AtomicReference<>(); + final PullImageCmd pullImageCmd = dockerClient + .pullImageCmd(imageName.getUnversionedPart()) + .withTag(imageName.getVersionPart()); + final AtomicReference dockerImageName = new AtomicReference<>(); + + // The following poll interval in ms: 50, 100, 200, 400, 800.... + // Results in ~70 requests in over 2 minutes + final PollInterval interval = IterativePollInterval + .iterative(duration -> duration.multipliedBy(2)) + .startDuration(Duration.ofMillis(50)); + + Awaitility + .await() + .pollInSameThread() + .pollDelay(Duration.ZERO) // start checking immediately + .atMost(PULL_RETRY_TIME_LIMIT) + .pollInterval(interval) + .until( + tryImagePullCommand(pullImageCmd, logger, dockerImageName, imageName, lastFailure, lastRetryAllowed) + ); + + if (dockerImageName.get() == null) { + final Exception lastException = lastFailure.get(); + logger.error( + "Failed to pull image: {}. Please check output of `docker pull {}`", + imageName, + imageName, + lastException + ); + throw new ContainerFetchException("Failed to pull image: " + imageName, lastException); } - logger.error( - "Failed to pull image: {}. Please check output of `docker pull {}`", - imageName, - imageName, - lastFailure - ); - - throw new ContainerFetchException("Failed to pull image: " + imageName, lastFailure); + logger.info("Image {} pull took {}", dockerImageName.get(), Duration.between(startedAt, Instant.now())); + LocalImagesCache.INSTANCE.refreshCache(imageName); + return dockerImageName.get(); } catch (DockerClientException e) { throw new ContainerFetchException("Failed to get Docker client for " + imageName, e); } } + private Callable tryImagePullCommand( + PullImageCmd pullImageCmd, + Logger logger, + AtomicReference dockerImageName, + DockerImageName imageName, + AtomicReference lastFailure, + Instant lastRetryAllowed + ) { + return () -> { + try { + pullImage(pullImageCmd, logger); + dockerImageName.set(imageName.asCanonicalNameString()); + return true; + } catch (InterruptedException | InternalServerErrorException e) { + // these classes of exception often relate to timeout/connection errors so should be retried + lastFailure.set(e); + logger.warn( + "Retrying pull for image: {} ({}s remaining)", + imageName, + Duration.between(Instant.now(), lastRetryAllowed).getSeconds() + ); + return false; + } + }; + } + + private TimeLimitedLoggedPullImageResultCallback pullImage(PullImageCmd pullImageCmd, Logger logger) + throws InterruptedException { + try { + return pullImageCmd.exec(new TimeLimitedLoggedPullImageResultCallback(logger)).awaitCompletion(); + } catch (DockerClientException e) { + // Try to fallback to x86 + return pullImageCmd + .withPlatform("linux/amd64") + .exec(new TimeLimitedLoggedPullImageResultCallback(logger)) + .awaitCompletion(); + } + } + private DockerImageName getImageName() throws InterruptedException, ExecutionException { final DockerImageName specifiedImageName = imageNameFuture.get(); From a52eadb3adb580f8d0472f811576e29e8ac00e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Thu, 21 Mar 2024 21:00:47 -0500 Subject: [PATCH 0065/1430] Update alpine image version to 3.17 (#8476) Fixes #8430 --- .../main/java/org/testcontainers/DockerClientFactory.java | 2 +- core/src/test/java/org/testcontainers/TestImages.java | 4 ++-- .../testcontainers/containers/DockerComposeFilesTest.java | 2 +- .../testcontainers/containers/GenericContainerTest.java | 2 +- .../containers/ParsedDockerComposeFileValidationTest.java | 8 ++++---- .../containers/output/ToStringConsumerTest.java | 8 ++++---- .../org/testcontainers/dockerclient/ImagePullTest.java | 2 +- .../java/org/testcontainers/junit/DockerfileTest.java | 6 +++--- .../testcontainers/junit/FixedHostPortContainerTest.java | 2 +- .../testcontainers/utility/DirectoryTarResourceTest.java | 6 +++--- core/src/test/resources/compose-dockerfile/Dockerfile | 2 +- .../resources/compose-scaling-multiple-containers.yml | 2 +- .../src/test/java/generic/ContainerCreationTest.java | 2 +- .../generic/src/test/java/generic/ContainerLabelTest.java | 4 ++-- .../junit4/generic/src/test/java/generic/ExecTest.java | 2 +- docs/features/configuration.md | 2 +- docs/features/creating_images.md | 2 +- .../org/testcontainers/spock/SpockTestImages.groovy | 2 +- 18 files changed, 30 insertions(+), 30 deletions(-) diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 6f0c744cedf..c4707aad0b7 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -77,7 +77,7 @@ static Map markerLabels() { return Collections.unmodifiableMap(labels); } - private static final DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.16"); + private static final DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.17"); private static DockerClientFactory instance; diff --git a/core/src/test/java/org/testcontainers/TestImages.java b/core/src/test/java/org/testcontainers/TestImages.java index 5308f341100..21511a0d72f 100644 --- a/core/src/test/java/org/testcontainers/TestImages.java +++ b/core/src/test/java/org/testcontainers/TestImages.java @@ -6,7 +6,7 @@ public interface TestImages { DockerImageName REDIS_IMAGE = DockerImageName.parse("redis:3.0.2"); DockerImageName RABBITMQ_IMAGE = DockerImageName.parse("rabbitmq:3.5.3"); DockerImageName MONGODB_IMAGE = DockerImageName.parse("mongo:3.1.5"); - DockerImageName ALPINE_IMAGE = DockerImageName.parse("alpine:3.16"); + DockerImageName ALPINE_IMAGE = DockerImageName.parse("alpine:3.17"); DockerImageName DOCKER_REGISTRY_IMAGE = DockerImageName.parse("registry:2.7.0"); - DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.16"); + DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.17"); } diff --git a/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java b/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java index 41870eb593d..9ae02a676c4 100644 --- a/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java +++ b/core/src/test/java/org/testcontainers/containers/DockerComposeFilesTest.java @@ -27,6 +27,6 @@ public void shouldGetDependencyImagesWhenOverriding() { ) ); assertThat(dockerComposeFiles.getDependencyImages()) - .containsExactlyInAnyOrder("alpine:3.16", "redis:b", "mysql:b", "aservice:latest"); + .containsExactlyInAnyOrder("alpine:3.17", "redis:b", "mysql:b", "aservice:latest"); } } diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index 8baf8d6e987..56a70e83c46 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -229,7 +229,7 @@ public void shouldReturnTheProvidedImage() { GenericContainer container = new GenericContainer(TestImages.REDIS_IMAGE); assertThat(container.getImage().get()).isEqualTo("redis:3.0.2"); container.setImage(new RemoteDockerImage(TestImages.ALPINE_IMAGE)); - assertThat(container.getImage().get()).isEqualTo("alpine:3.16"); + assertThat(container.getImage().get()).isEqualTo("alpine:3.17"); } @Test diff --git a/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java b/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java index c362cd28f8c..15bca203e31 100644 --- a/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java +++ b/core/src/test/java/org/testcontainers/containers/ParsedDockerComposeFileValidationTest.java @@ -113,8 +113,8 @@ public void shouldObtainImageFromDockerfileBuild() { .contains( entry("mysql", Sets.newHashSet("mysql")), entry("redis", Sets.newHashSet("redis")), - entry("custom", Sets.newHashSet("alpine:3.16")) - ); // r/ redis, mysql from compose file, alpine:3.16 from Dockerfile build + entry("custom", Sets.newHashSet("alpine:3.17")) + ); // r/ redis, mysql from compose file, alpine:3.17 from Dockerfile build } @Test @@ -126,7 +126,7 @@ public void shouldObtainImageFromDockerfileBuildWithContext() { .contains( entry("mysql", Sets.newHashSet("mysql")), entry("redis", Sets.newHashSet("redis")), - entry("custom", Sets.newHashSet("alpine:3.16")) - ); // redis, mysql from compose file, alpine:3.16 from Dockerfile build + entry("custom", Sets.newHashSet("alpine:3.17")) + ); // redis, mysql from compose file, alpine:3.17 from Dockerfile build } } diff --git a/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java b/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java index 2755f4142d4..eaab250141c 100644 --- a/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java +++ b/core/src/test/java/org/testcontainers/containers/output/ToStringConsumerTest.java @@ -23,7 +23,7 @@ public class ToStringConsumerTest { @Test public void newlines_are_not_added_to_exec_output() throws Exception { - try (GenericContainer container = new GenericContainer<>("alpine:3.16")) { + try (GenericContainer container = new GenericContainer<>("alpine:3.17")) { container.withCommand("sleep", "2m"); container.start(); @@ -34,7 +34,7 @@ public void newlines_are_not_added_to_exec_output() throws Exception { @Test(timeout = 60_000L) public void newlines_are_not_added_to_exec_output_with_tty() throws Exception { - try (GenericContainer container = new GenericContainer<>("alpine:3.16")) { + try (GenericContainer container = new GenericContainer<>("alpine:3.17")) { container.withCreateContainerCmdModifier(cmd -> { cmd.withAttachStdin(true).withStdinOpen(true).withTty(true); }); @@ -48,7 +48,7 @@ public void newlines_are_not_added_to_exec_output_with_tty() throws Exception { @Test public void newlines_are_not_added_to_container_output() { - try (GenericContainer container = new GenericContainer<>("alpine:3.16")) { + try (GenericContainer container = new GenericContainer<>("alpine:3.17")) { container.withCommand("echo", "-n", LARGE_PAYLOAD); container.setStartupCheckStrategy(new OneShotStartupCheckStrategy()); container.start(); @@ -61,7 +61,7 @@ public void newlines_are_not_added_to_container_output() { @Test public void newlines_are_not_added_to_container_output_with_tty() { - try (GenericContainer container = new GenericContainer<>("alpine:3.16")) { + try (GenericContainer container = new GenericContainer<>("alpine:3.17")) { container.withCreateContainerCmdModifier(cmd -> { cmd.withTty(true); }); diff --git a/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java b/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java index e1c2a56e8a9..db3f81d9b54 100644 --- a/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java +++ b/core/src/test/java/org/testcontainers/dockerclient/ImagePullTest.java @@ -16,7 +16,7 @@ public class ImagePullTest { public static String[] parameters() { return new String[] { "alpine:latest", - "alpine:3.16", + "alpine:3.17", "alpine", // omitting the tag should work and default to latest "alpine@sha256:1775bebec23e1f3ce486989bfc9ff3c4e951690df84aa9f926497d82f2ffca9d", "quay.io/testcontainers/ryuk:latest", diff --git a/core/src/test/java/org/testcontainers/junit/DockerfileTest.java b/core/src/test/java/org/testcontainers/junit/DockerfileTest.java index 86292bcf9ac..113fd7f4c63 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerfileTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerfileTest.java @@ -38,7 +38,7 @@ protected void configure(BuildImageCmd buildImageCmd) { super.configure(buildImageCmd); List dockerfile = Arrays.asList( - "FROM alpine:3.16", + "FROM alpine:3.17", "RUN echo 'hello from Docker build process'", "CMD yes" ); @@ -58,7 +58,7 @@ public void dockerfileBuilderWorks() { .withFileFromString("folder/someFile.txt", "hello") .withDockerfileFromBuilder(builder -> { builder - .from("alpine:3.16") + .from("alpine:3.17") .workDir("/app") .add("test.txt", "test file.txt") .run("ls", "-la", "/app/test file.txt") @@ -101,7 +101,7 @@ public int getFileMode() { ) .withDockerfileFromBuilder(builder -> { builder - .from("alpine:3.16") // + .from("alpine:3.17") // .copy("someFile.txt", "/someFile.txt") .cmd("stat -c \"%a\" /someFile.txt"); }); diff --git a/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java b/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java index 45feb85b359..72fc4b70519 100644 --- a/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/FixedHostPortContainerTest.java @@ -23,7 +23,7 @@ */ public class FixedHostPortContainerTest { - private static final String TEST_IMAGE = "alpine:3.16"; + private static final String TEST_IMAGE = "alpine:3.17"; /** * Default http server port (just something different from default) diff --git a/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java b/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java index 6215f84520b..a56315085ae 100644 --- a/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java +++ b/core/src/test/java/org/testcontainers/utility/DirectoryTarResourceTest.java @@ -22,7 +22,7 @@ public void simpleRecursiveFileTest() { new ImageFromDockerfile() .withDockerfileFromBuilder(builder -> { builder - .from("alpine:3.16") + .from("alpine:3.17") .copy("/tmp/foo", "/foo") .cmd("cat /foo/test/resources/test-recursive-file.txt") .build(); @@ -47,7 +47,7 @@ public void simpleRecursiveFileWithPermissionTest() { new ImageFromDockerfile() .withDockerfileFromBuilder(builder -> { builder - .from("alpine:3.16") // + .from("alpine:3.17") // .copy("/tmp/foo", "/foo") .cmd("ls", "-al", "/") .build(); @@ -75,7 +75,7 @@ public void simpleRecursiveClasspathResourceTest() { new ImageFromDockerfile() .withDockerfileFromBuilder(builder -> { builder - .from("alpine:3.16") // + .from("alpine:3.17") // .copy("/tmp/foo", "/foo") .cmd("ls -lRt /foo") .build(); diff --git a/core/src/test/resources/compose-dockerfile/Dockerfile b/core/src/test/resources/compose-dockerfile/Dockerfile index 566428fa97f..7450ebde82c 100644 --- a/core/src/test/resources/compose-dockerfile/Dockerfile +++ b/core/src/test/resources/compose-dockerfile/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.16 +FROM alpine:3.17 ADD passthrough.sh /passthrough.sh diff --git a/core/src/test/resources/compose-scaling-multiple-containers.yml b/core/src/test/resources/compose-scaling-multiple-containers.yml index fc498a9fd42..ce3f002f1e8 100644 --- a/core/src/test/resources/compose-scaling-multiple-containers.yml +++ b/core/src/test/resources/compose-scaling-multiple-containers.yml @@ -3,5 +3,5 @@ services: redis: image: redis other: - image: alpine:3.16 + image: alpine:3.17 command: sleep 10000 diff --git a/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java b/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java index d98e09ff036..09149091c23 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java @@ -20,7 +20,7 @@ public class ContainerCreationTest { // } // spotless:on - public static final DockerImageName ALPINE_IMAGE = DockerImageName.parse("alpine:3.16"); + public static final DockerImageName ALPINE_IMAGE = DockerImageName.parse("alpine:3.17"); // spotless:off // withOptions { diff --git a/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java b/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java index 868b8ec44f7..73dac2bda9b 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java @@ -9,7 +9,7 @@ public class ContainerLabelTest { // single_label { - public GenericContainer containerWithLabel = new GenericContainer(DockerImageName.parse("alpine:3.16")) + public GenericContainer containerWithLabel = new GenericContainer(DockerImageName.parse("alpine:3.17")) .withLabel("key", "value"); // } @@ -17,7 +17,7 @@ public class ContainerLabelTest { private Map mapOfLabels = new HashMap<>(); // populate map, e.g. mapOfLabels.put("key1", "value1"); - public GenericContainer containerWithMultipleLabels = new GenericContainer(DockerImageName.parse("alpine:3.16")) + public GenericContainer containerWithMultipleLabels = new GenericContainer(DockerImageName.parse("alpine:3.17")) .withLabels(mapOfLabels); // } } diff --git a/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java b/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java index 7ccb0f2cc54..078e177242f 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java @@ -13,7 +13,7 @@ public class ExecTest { @Rule - public GenericContainer container = new GenericContainer<>(DockerImageName.parse("alpine:3.16")) + public GenericContainer container = new GenericContainer<>(DockerImageName.parse("alpine:3.17")) .withCommand("top"); @Test diff --git a/docs/features/configuration.md b/docs/features/configuration.md index fe78e317120..d874b16ad7b 100644 --- a/docs/features/configuration.md +++ b/docs/features/configuration.md @@ -49,7 +49,7 @@ Some companies disallow the usage of Docker Hub, but you can override `*.image` > **ryuk.container.image = testcontainers/ryuk:0.3.3** > Performs fail-safe cleanup of containers, and always required (unless [Ryuk is disabled](#disabling-ryuk)) -> **tinyimage.container.image = alpine:3.16** +> **tinyimage.container.image = alpine:3.17** > Used to check whether images can be pulled at startup, and always required (unless [startup checks are disabled](#disabling-the-startup-checks)) > **sshd.container.image = testcontainers/sshd:1.1.0** diff --git a/docs/features/creating_images.md b/docs/features/creating_images.md index e4e6315a405..6f1988ed28e 100644 --- a/docs/features/creating_images.md +++ b/docs/features/creating_images.md @@ -51,7 +51,7 @@ new GenericContainer( new ImageFromDockerfile() .withDockerfileFromBuilder(builder -> builder - .from("alpine:3.16") + .from("alpine:3.17") .run("apk add --update nginx") .cmd("nginx", "-g", "daemon off;") .build())) diff --git a/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy b/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy index 43cda0b3313..ce16e963548 100644 --- a/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy +++ b/modules/spock/src/test/groovy/org/testcontainers/spock/SpockTestImages.groovy @@ -6,5 +6,5 @@ interface SpockTestImages { DockerImageName MYSQL_IMAGE = DockerImageName.parse("mysql:8.0.36") DockerImageName POSTGRES_TEST_IMAGE = DockerImageName.parse("postgres:9.6.12") DockerImageName HTTPD_IMAGE = DockerImageName.parse("httpd:2.4-alpine") - DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.16") + DockerImageName TINY_IMAGE = DockerImageName.parse("alpine:3.17") } From e4c533a00a6c41201f56207d10f7a44bd7c3c833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Fri, 22 Mar 2024 18:32:12 -0600 Subject: [PATCH 0066/1430] Polish oracle-free --- .../org/testcontainers/oracle/OracleContainer.java | 13 ++++++------- .../junit/oracle/SimpleOracleTest.java | 6 +++--- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/modules/oracle-free/src/main/java/org/testcontainers/oracle/OracleContainer.java b/modules/oracle-free/src/main/java/org/testcontainers/oracle/OracleContainer.java index 1130072be12..90d772f0328 100644 --- a/modules/oracle-free/src/main/java/org/testcontainers/oracle/OracleContainer.java +++ b/modules/oracle-free/src/main/java/org/testcontainers/oracle/OracleContainer.java @@ -3,11 +3,10 @@ import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.testcontainers.containers.JdbcDatabaseContainer; -import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy; +import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.utility.DockerImageName; import java.time.Duration; -import java.time.temporal.ChronoUnit; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -68,11 +67,11 @@ public OracleContainer(String dockerImageName) { public OracleContainer(final DockerImageName dockerImageName) { super(dockerImageName); dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); - this.waitStrategy = - new LogMessageWaitStrategy() - .withRegEx(".*DATABASE IS READY TO USE!.*\\s") - .withTimes(1) - .withStartupTimeout(Duration.of(DEFAULT_STARTUP_TIMEOUT_SECONDS, ChronoUnit.SECONDS)); + waitingFor( + Wait + .forLogMessage(".*DATABASE IS READY TO USE!.*\\s", 1) + .withStartupTimeout(Duration.ofSeconds(DEFAULT_STARTUP_TIMEOUT_SECONDS)) + ); withConnectTimeoutSeconds(DEFAULT_CONNECT_TIMEOUT_SECONDS); addExposedPorts(ORACLE_PORT); } diff --git a/modules/oracle-free/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java b/modules/oracle-free/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java index 5ef276c0157..45ed72cb622 100644 --- a/modules/oracle-free/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java +++ b/modules/oracle-free/src/test/java/org/testcontainers/junit/oracle/SimpleOracleTest.java @@ -33,7 +33,7 @@ private void runTest(OracleContainer container, String databaseName, String user @Test public void testDefaultSettings() throws SQLException { - try (OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME);) { + try (OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME)) { runTest(oracle, "freepdb1", "test", "test"); // Match against the last '/' @@ -76,7 +76,7 @@ public void testCustomUser() throws SQLException { @Test public void testSID() throws SQLException { - try (OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME).usingSid();) { + try (OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME).usingSid()) { runTest(oracle, "freepdb1", "system", "test"); // Match against the last ':' @@ -90,7 +90,7 @@ public void testSIDAndCustomPassword() throws SQLException { try ( OracleContainer oracle = new OracleContainer(ORACLE_DOCKER_IMAGE_NAME) .usingSid() - .withPassword("testPassword"); + .withPassword("testPassword") ) { runTest(oracle, "freepdb1", "system", "testPassword"); } From 3b6517148c71c44c73863f8b178ebb1bed89eb6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Mon, 25 Mar 2024 18:52:42 -0600 Subject: [PATCH 0067/1430] Update mikepenz/action-junit-report verstion to v4 --- .github/actions/setup-junit-report/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup-junit-report/action.yml b/.github/actions/setup-junit-report/action.yml index 86092d06bcc..538af9af21f 100644 --- a/.github/actions/setup-junit-report/action.yml +++ b/.github/actions/setup-junit-report/action.yml @@ -4,7 +4,7 @@ runs: using: "composite" steps: - name: Publish Test Report - uses: mikepenz/action-junit-report@v3 + uses: mikepenz/action-junit-report@v4 if: always() # always run even if the previous step fails with: report_paths: '**/build/test-results/test/TEST-*.xml' From eadc9d6ec7777562d3b335b0e3ecd655e803e8c8 Mon Sep 17 00:00:00 2001 From: Marcin Antas Date: Tue, 26 Mar 2024 02:14:40 +0100 Subject: [PATCH 0068/1430] Add tests with Weaviate modules (#8481) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Eddú Meléndez --- .../weaviate/WeaviateContainerTest.java | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/modules/weaviate/src/test/java/org/testcontainers/weaviate/WeaviateContainerTest.java b/modules/weaviate/src/test/java/org/testcontainers/weaviate/WeaviateContainerTest.java index 9aa8fe19f61..4acaa3b98fd 100644 --- a/modules/weaviate/src/test/java/org/testcontainers/weaviate/WeaviateContainerTest.java +++ b/modules/weaviate/src/test/java/org/testcontainers/weaviate/WeaviateContainerTest.java @@ -4,16 +4,22 @@ import io.weaviate.client.WeaviateClient; import io.weaviate.client.base.Result; import io.weaviate.client.v1.misc.model.Meta; +import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.Test; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import static org.assertj.core.api.Assertions.assertThat; public class WeaviateContainerTest { @Test - public void test() { + public void testWeaviate() { try ( // container { - WeaviateContainer weaviate = new WeaviateContainer("semitechnologies/weaviate:1.24.1") + WeaviateContainer weaviate = new WeaviateContainer("semitechnologies/weaviate:1.24.5") // } ) { weaviate.start(); @@ -21,7 +27,38 @@ public void test() { config.setGRPCHost(weaviate.getGrpcHostAddress()); WeaviateClient client = new WeaviateClient(config); Result meta = client.misc().metaGetter().run(); - assertThat(meta.getResult().getVersion()).isEqualTo("1.24.1"); + assertThat(meta.getResult().getVersion()).isEqualTo("1.24.5"); + } + } + + @Test + public void testWeaviateWithModules() { + List enableModules = Arrays.asList( + "backup-filesystem", + "text2vec-openai", + "text2vec-cohere", + "text2vec-huggingface", + "generative-openai" + ); + Map env = new HashMap<>(); + env.put("ENABLE_MODULES", String.join(",", enableModules)); + env.put("BACKUP_FILESYSTEM_PATH", "/tmp/backups"); + try (WeaviateContainer weaviate = new WeaviateContainer("semitechnologies/weaviate:1.24.5").withEnv(env)) { + weaviate.start(); + Config config = new Config("http", weaviate.getHttpHostAddress()); + config.setGRPCHost(weaviate.getGrpcHostAddress()); + WeaviateClient client = new WeaviateClient(config); + Result meta = client.misc().metaGetter().run(); + assertThat(meta.getResult().getVersion()).isEqualTo("1.24.5"); + Object modules = meta.getResult().getModules(); + assertThat(modules) + .isNotNull() + .asInstanceOf(InstanceOfAssertFactories.map(String.class, Object.class)) + .extracting(Map::keySet) + .satisfies(keys -> { + assertThat(keys.size()).isEqualTo(enableModules.size()); + keys.forEach(key -> assertThat(enableModules.contains(key)).isTrue()); + }); } } } From e2b2d85be79c120155089b789022a6ec659669dc Mon Sep 17 00:00:00 2001 From: Michael Musenbrock Date: Fri, 29 Mar 2024 02:32:21 +0100 Subject: [PATCH 0069/1430] Fix Docker compose stop command by adding environment (#8493) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This issue was introduced in 7112db5. `DockerComposeContainer` and `ComposeContainer` now passes the env to the stop command in both implementations. Fixes #8492 --------- Signed-off-by: Michael Musenbrock Co-authored-by: Eddú Meléndez Gonzales --- .../containers/ComposeContainer.java | 2 +- .../containers/DockerComposeContainer.java | 2 +- .../junit/ComposeContainerPortViaEnvTest.java | 21 +++++++++++++++++++ .../DockerComposeContainerPortViaEnvTest.java | 21 +++++++++++++++++++ .../v2-compose-test-port-via-env.yml | 5 +++++ 5 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 core/src/test/java/org/testcontainers/junit/ComposeContainerPortViaEnvTest.java create mode 100644 core/src/test/java/org/testcontainers/junit/DockerComposeContainerPortViaEnvTest.java create mode 100644 core/src/test/resources/v2-compose-test-port-via-env.yml diff --git a/core/src/main/java/org/testcontainers/containers/ComposeContainer.java b/core/src/main/java/org/testcontainers/containers/ComposeContainer.java index 081c71b3338..a865e744dd6 100644 --- a/core/src/main/java/org/testcontainers/containers/ComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/ComposeContainer.java @@ -165,7 +165,7 @@ public void stop() { if (removeImages != null) { cmd += " --rmi " + removeImages.dockerRemoveImagesType(); } - this.composeDelegate.runWithCompose(this.localCompose, cmd); + this.composeDelegate.runWithCompose(this.localCompose, cmd, this.env); } finally { this.project = this.composeDelegate.randomProjectId(); } diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index 3a8ab5b4ddc..68f9ec26ba6 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -172,7 +172,7 @@ public void stop() { if (removeImages != null) { cmd += " --rmi " + removeImages.dockerRemoveImagesType(); } - this.composeDelegate.runWithCompose(this.localCompose, cmd); + this.composeDelegate.runWithCompose(this.localCompose, cmd, this.env); } finally { this.project = this.composeDelegate.randomProjectId(); } diff --git a/core/src/test/java/org/testcontainers/junit/ComposeContainerPortViaEnvTest.java b/core/src/test/java/org/testcontainers/junit/ComposeContainerPortViaEnvTest.java new file mode 100644 index 00000000000..b27f4b080da --- /dev/null +++ b/core/src/test/java/org/testcontainers/junit/ComposeContainerPortViaEnvTest.java @@ -0,0 +1,21 @@ +package org.testcontainers.junit; + +import org.junit.Rule; +import org.testcontainers.containers.ComposeContainer; + +import java.io.File; + +public class ComposeContainerPortViaEnvTest extends BaseComposeTest { + + @Rule + public ComposeContainer environment = new ComposeContainer( + new File("src/test/resources/v2-compose-test-port-via-env.yml") + ) + .withExposedService("redis-1", REDIS_PORT) + .withEnv("REDIS_PORT", String.valueOf(REDIS_PORT)); + + @Override + protected ComposeContainer getEnvironment() { + return environment; + } +} diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeContainerPortViaEnvTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerPortViaEnvTest.java new file mode 100644 index 00000000000..849e2a8e6a6 --- /dev/null +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeContainerPortViaEnvTest.java @@ -0,0 +1,21 @@ +package org.testcontainers.junit; + +import org.junit.Rule; +import org.testcontainers.containers.DockerComposeContainer; + +import java.io.File; + +public class DockerComposeContainerPortViaEnvTest extends BaseDockerComposeTest { + + @Rule + public DockerComposeContainer environment = new DockerComposeContainer( + new File("src/test/resources/v2-compose-test-port-via-env.yml") + ) + .withExposedService("redis_1", REDIS_PORT) + .withEnv("REDIS_PORT", String.valueOf(REDIS_PORT)); + + @Override + protected DockerComposeContainer getEnvironment() { + return environment; + } +} diff --git a/core/src/test/resources/v2-compose-test-port-via-env.yml b/core/src/test/resources/v2-compose-test-port-via-env.yml new file mode 100644 index 00000000000..2b4929594be --- /dev/null +++ b/core/src/test/resources/v2-compose-test-port-via-env.yml @@ -0,0 +1,5 @@ +services: + redis: + image: redis + ports: + - ${REDIS_PORT} From 04c2eb08f9381420b68eb99128905432f2468de9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Apr 2024 22:28:32 +0000 Subject: [PATCH 0070/1430] Bump org.junit.jupiter:junit-jupiter in /modules/hivemq Bumps [org.junit.jupiter:junit-jupiter](https://github.com/junit-team/junit5) from 5.10.1 to 5.10.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.10.1...r5.10.2) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/hivemq/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hivemq/build.gradle b/modules/hivemq/build.gradle index 6c03e07254d..7f18e867fef 100644 --- a/modules/hivemq/build.gradle +++ b/modules/hivemq/build.gradle @@ -11,7 +11,7 @@ dependencies { shaded("org.jboss.shrinkwrap:shrinkwrap-impl-base:1.2.6") shaded("net.lingala.zip4j:zip4j:2.11.5") - testImplementation("org.junit.jupiter:junit-jupiter:5.10.1") + testImplementation("org.junit.jupiter:junit-jupiter:5.10.2") testImplementation(project(":junit-jupiter")) testImplementation("com.hivemq:hivemq-extension-sdk:4.24.0") testImplementation("com.hivemq:hivemq-mqtt-client:1.3.3") From 09d9dad7b4747fc76ae8b29cb73dcba4c001c0cd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Apr 2024 22:30:02 +0000 Subject: [PATCH 0071/1430] Bump org.assertj:assertj-core from 3.25.1 to 3.25.3 in /modules/nginx Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.25.1 to 3.25.3. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.25.1...assertj-build-3.25.3) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/nginx/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nginx/build.gradle b/modules/nginx/build.gradle index 406fc608f08..3021ff03241 100644 --- a/modules/nginx/build.gradle +++ b/modules/nginx/build.gradle @@ -3,5 +3,5 @@ description = "Testcontainers :: Nginx" dependencies { api project(':testcontainers') compileOnly 'org.jetbrains:annotations:24.1.0' - testImplementation 'org.assertj:assertj-core:3.25.1' + testImplementation 'org.assertj:assertj-core:3.25.3' } From e74dd733231cff1150140c0034de48a9b9da8217 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Apr 2024 22:30:21 +0000 Subject: [PATCH 0072/1430] Bump org.assertj:assertj-core from 3.25.1 to 3.25.3 in /modules/consul Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.25.1 to 3.25.3. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.25.1...assertj-build-3.25.3) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/consul/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/consul/build.gradle b/modules/consul/build.gradle index 9c1195525ff..81b449d6b7e 100644 --- a/modules/consul/build.gradle +++ b/modules/consul/build.gradle @@ -5,5 +5,5 @@ dependencies { testImplementation 'com.ecwid.consul:consul-api:1.4.5' testImplementation 'io.rest-assured:rest-assured:5.4.0' - testImplementation 'org.assertj:assertj-core:3.25.1' + testImplementation 'org.assertj:assertj-core:3.25.3' } From db75ec93a021d88654f08615089ef7782c087560 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Apr 2024 22:30:38 +0000 Subject: [PATCH 0073/1430] Bump com.yugabyte:java-driver-core in /modules/yugabytedb Bumps [com.yugabyte:java-driver-core](https://github.com/yugabyte/cassandra-java-driver) from 4.15.0-yb-1 to 4.15.0-yb-2-TESTFIX.0. - [Release notes](https://github.com/yugabyte/cassandra-java-driver/releases) - [Commits](https://github.com/yugabyte/cassandra-java-driver/compare/4.15.0-yb-1...4.15.0-yb-2-TESTFIX.0) --- updated-dependencies: - dependency-name: com.yugabyte:java-driver-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- modules/yugabytedb/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/yugabytedb/build.gradle b/modules/yugabytedb/build.gradle index 100620ab6f9..2ab71ef9cc6 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.15.0-yb-1' + testImplementation 'com.yugabyte:java-driver-core:4.15.0-yb-2-TESTFIX.0' // YSQL driver testRuntimeOnly 'com.yugabyte:jdbc-yugabytedb:42.3.5-yb-4' } From cda56090b749569b7aed288045bf921e5fc8de01 Mon Sep 17 00:00:00 2001 From: Ilia Beliaev Date: Wed, 3 Apr 2024 03:42:55 +0200 Subject: [PATCH 0074/1430] Fix zookeeper initialization (#8433) --- .../org/testcontainers/containers/KafkaContainer.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) 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 d76154505c2..a7144c0861b 100644 --- a/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java +++ b/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java @@ -182,15 +182,14 @@ protected void containerIsStarting(InspectContainerResponse containerInfo) { // exporting KAFKA_ADVERTISED_LISTENERS with the container hostname command += String.format("export KAFKA_ADVERTISED_LISTENERS=%s\n", kafkaAdvertisedListeners); - if (this.kraftEnabled && isLessThanCP740()) { + 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"; + if (this.kraftEnabled) { + command += commandKraft(); + } else if (this.externalZookeeperConnect == null) { command += commandZookeeper(); } From 8db891a386782a682f64650f536aa2a18445a239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 2 Apr 2024 21:52:15 -0500 Subject: [PATCH 0075/1430] Add support for apache/kafka (#8416) Fixes #8398 --- docs/modules/kafka.md | 12 +- .../testcontainers/kafka/KafkaContainer.java | 93 +++++++++++++ .../org/testcontainers/AbstractKafka.java | 126 ++++++++++++++++++ .../containers/KafkaContainerTest.java | 112 +--------------- .../kafka/KafkaContainerTest.java | 15 +++ 5 files changed, 246 insertions(+), 112 deletions(-) create mode 100644 modules/kafka/src/main/java/org/testcontainers/kafka/KafkaContainer.java create mode 100644 modules/kafka/src/test/java/org/testcontainers/AbstractKafka.java create mode 100644 modules/kafka/src/test/java/org/testcontainers/kafka/KafkaContainerTest.java diff --git a/docs/modules/kafka.md b/docs/modules/kafka.md index fb953716225..6ec63126387 100644 --- a/docs/modules/kafka.md +++ b/docs/modules/kafka.md @@ -1,7 +1,12 @@ -# Kafka Containers +# Kafka Module Testcontainers can be used to automatically instantiate and manage [Apache Kafka](https://kafka.apache.org) containers. -More precisely Testcontainers uses the official Docker images for [Confluent OSS Platform](https://hub.docker.com/r/confluentinc/cp-kafka/) + +Currently, two different Kafka images are supported: + +* `org.testcontainers.containers.KafkaContainer` supports +[confluentinc/cp-kafka](https://hub.docker.com/r/confluentinc/cp-kafka/) +* `org.testcontainers.kafka.KafkaContainer` supports [apache/kafka](https://hub.docker.com/r/apache/kafka/) ## Benefits @@ -24,6 +29,9 @@ Now your tests or any other process running on your machine can get access to ru ## Options + +!!! note + The options below are only available for `org.testcontainers.containers.KafkaContainer` ### Using external Zookeeper diff --git a/modules/kafka/src/main/java/org/testcontainers/kafka/KafkaContainer.java b/modules/kafka/src/main/java/org/testcontainers/kafka/KafkaContainer.java new file mode 100644 index 00000000000..547a7dc7960 --- /dev/null +++ b/modules/kafka/src/main/java/org/testcontainers/kafka/KafkaContainer.java @@ -0,0 +1,93 @@ +package org.testcontainers.kafka; + +import com.github.dockerjava.api.command.InspectContainerResponse; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.images.builder.Transferable; +import org.testcontainers.utility.DockerImageName; + +import java.util.ArrayList; +import java.util.List; + +/** + * Testcontainers implementation for Apache Kafka. + *

+ * Supported image: {@code apache/kafka} + *

+ * Exposed ports: 9092 + */ +public class KafkaContainer extends GenericContainer { + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("apache/kafka"); + + private static final int KAFKA_PORT = 9092; + + private static final String DEFAULT_INTERNAL_TOPIC_RF = "1"; + + private static final String STARTER_SCRIPT = "/testcontainers_start.sh"; + + private static final String DEFAULT_CLUSTER_ID = "4L6g3nShT-eMCtK--X86sw"; + + public KafkaContainer(String imageName) { + this(DockerImageName.parse(imageName)); + } + + public KafkaContainer(DockerImageName dockerImageName) { + super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + + withExposedPorts(KAFKA_PORT); + withEnv("CLUSTER_ID", DEFAULT_CLUSTER_ID); + + withEnv( + "KAFKA_LISTENERS", + "PLAINTEXT://0.0.0.0:" + KAFKA_PORT + ",BROKER://0.0.0.0:9093, CONTROLLER://0.0.0.0:9094" + ); + withEnv("KAFKA_LISTENER_SECURITY_PROTOCOL_MAP", "BROKER:PLAINTEXT,PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT"); + withEnv("KAFKA_INTER_BROKER_LISTENER_NAME", "BROKER"); + withEnv("KAFKA_PROCESS_ROLES", "broker,controller"); + withEnv("KAFKA_CONTROLLER_LISTENER_NAMES", "CONTROLLER"); + + withEnv("KAFKA_NODE_ID", "1"); + withEnv("KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR", DEFAULT_INTERNAL_TOPIC_RF); + withEnv("KAFKA_OFFSETS_TOPIC_NUM_PARTITIONS", DEFAULT_INTERNAL_TOPIC_RF); + withEnv("KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR", DEFAULT_INTERNAL_TOPIC_RF); + withEnv("KAFKA_TRANSACTION_STATE_LOG_MIN_ISR", DEFAULT_INTERNAL_TOPIC_RF); + withEnv("KAFKA_LOG_FLUSH_INTERVAL_MESSAGES", Long.MAX_VALUE + ""); + withEnv("KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS", "0"); + + withCommand("sh", "-c", "while [ ! -f " + STARTER_SCRIPT + " ]; do sleep 0.1; done; " + STARTER_SCRIPT); + waitingFor(Wait.forLogMessage(".*Transitioning from RECOVERY to RUNNING.*", 1)); + } + + @Override + protected void configure() { + String firstNetworkAlias = getNetworkAliases().stream().findFirst().orElse(null); + String networkAlias = getNetwork() != null ? firstNetworkAlias : "localhost"; + String controllerQuorumVoters = String.format("%s@%s:9094", getEnvMap().get("KAFKA_NODE_ID"), networkAlias); + withEnv("KAFKA_CONTROLLER_QUORUM_VOTERS", controllerQuorumVoters); + } + + @Override + protected void containerIsStarting(InspectContainerResponse containerInfo) { + String brokerAdvertisedListener = String.format( + "BROKER://%s:%s", + containerInfo.getConfig().getHostName(), + "9093" + ); + List advertisedListeners = new ArrayList<>(); + advertisedListeners.add("PLAINTEXT://" + getBootstrapServers()); + advertisedListeners.add(brokerAdvertisedListener); + String kafkaAdvertisedListeners = String.join(",", advertisedListeners); + String command = "#!/bin/bash\n"; + // exporting KAFKA_ADVERTISED_LISTENERS with the container hostname + command += String.format("export KAFKA_ADVERTISED_LISTENERS=%s\n", kafkaAdvertisedListeners); + + command += "/etc/kafka/docker/run \n"; + copyFileToContainer(Transferable.of(command, 0777), STARTER_SCRIPT); + } + + public String getBootstrapServers() { + return String.format("%s:%s", getHost(), getMappedPort(KAFKA_PORT)); + } +} diff --git a/modules/kafka/src/test/java/org/testcontainers/AbstractKafka.java b/modules/kafka/src/test/java/org/testcontainers/AbstractKafka.java new file mode 100644 index 00000000000..f7e9dcedb30 --- /dev/null +++ b/modules/kafka/src/test/java/org/testcontainers/AbstractKafka.java @@ -0,0 +1,126 @@ +package org.testcontainers; + +import com.google.common.collect.ImmutableMap; +import org.apache.kafka.clients.admin.AdminClient; +import org.apache.kafka.clients.admin.AdminClientConfig; +import org.apache.kafka.clients.admin.NewTopic; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.clients.consumer.ConsumerRecords; +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.common.config.SaslConfigs; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.apache.kafka.common.serialization.StringSerializer; +import org.rnorth.ducttape.unreliables.Unreliables; + +import java.time.Duration; +import java.util.Collection; +import java.util.Collections; +import java.util.Properties; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; + +public class AbstractKafka { + + private final ImmutableMap properties = ImmutableMap.of( + AdminClientConfig.SECURITY_PROTOCOL_CONFIG, + "SASL_PLAINTEXT", + SaslConfigs.SASL_MECHANISM, + "PLAIN", + SaslConfigs.SASL_JAAS_CONFIG, + "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"admin\" password=\"admin\";" + ); + + protected void testKafkaFunctionality(String bootstrapServers) throws Exception { + testKafkaFunctionality(bootstrapServers, false, 1, 1); + } + + protected void testSecureKafkaFunctionality(String bootstrapServers) throws Exception { + testKafkaFunctionality(bootstrapServers, true, 1, 1); + } + + protected void testKafkaFunctionality(String bootstrapServers, boolean authenticated, int partitions, int rf) + throws Exception { + ImmutableMap adminClientDefaultProperties = ImmutableMap.of( + AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, + bootstrapServers + ); + Properties adminClientProperties = new Properties(); + adminClientProperties.putAll(adminClientDefaultProperties); + + ImmutableMap consumerDefaultProperties = ImmutableMap.of( + ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, + bootstrapServers, + ConsumerConfig.GROUP_ID_CONFIG, + "tc-" + UUID.randomUUID(), + ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, + "earliest" + ); + Properties consumerProperties = new Properties(); + consumerProperties.putAll(consumerDefaultProperties); + + ImmutableMap producerDefaultProperties = ImmutableMap.of( + ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, + bootstrapServers, + ProducerConfig.CLIENT_ID_CONFIG, + UUID.randomUUID().toString() + ); + Properties producerProperties = new Properties(); + producerProperties.putAll(producerDefaultProperties); + + if (authenticated) { + adminClientProperties.putAll(this.properties); + consumerProperties.putAll(this.properties); + producerProperties.putAll(this.properties); + } + try ( + AdminClient adminClient = AdminClient.create(adminClientProperties); + KafkaProducer producer = new KafkaProducer<>( + producerProperties, + new StringSerializer(), + new StringSerializer() + ); + KafkaConsumer consumer = new KafkaConsumer<>( + consumerProperties, + new StringDeserializer(), + new StringDeserializer() + ); + ) { + String topicName = "messages-" + UUID.randomUUID(); + + Collection topics = Collections.singletonList(new NewTopic(topicName, partitions, (short) rf)); + adminClient.createTopics(topics).all().get(30, TimeUnit.SECONDS); + + consumer.subscribe(Collections.singletonList(topicName)); + + producer.send(new ProducerRecord<>(topicName, "testcontainers", "rulezzz")).get(); + + Unreliables.retryUntilTrue( + 10, + TimeUnit.SECONDS, + () -> { + ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); + + if (records.isEmpty()) { + return false; + } + + assertThat(records) + .hasSize(1) + .extracting(ConsumerRecord::topic, ConsumerRecord::key, ConsumerRecord::value) + .containsExactly(tuple(topicName, "testcontainers", "rulezzz")); + + return true; + } + ); + + consumer.unsubscribe(); + } + } +} 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 e5d1617298b..5284209a76d 100644 --- a/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java +++ b/modules/kafka/src/test/java/org/testcontainers/containers/KafkaContainerTest.java @@ -5,37 +5,25 @@ import org.apache.kafka.clients.admin.AdminClient; import org.apache.kafka.clients.admin.AdminClientConfig; import org.apache.kafka.clients.admin.NewTopic; -import org.apache.kafka.clients.consumer.ConsumerConfig; -import org.apache.kafka.clients.consumer.ConsumerRecord; -import org.apache.kafka.clients.consumer.ConsumerRecords; -import org.apache.kafka.clients.consumer.KafkaConsumer; -import org.apache.kafka.clients.producer.KafkaProducer; -import org.apache.kafka.clients.producer.ProducerConfig; -import org.apache.kafka.clients.producer.ProducerRecord; import org.apache.kafka.common.config.SaslConfigs; import org.apache.kafka.common.errors.SaslAuthenticationException; import org.apache.kafka.common.errors.TopicAuthorizationException; -import org.apache.kafka.common.serialization.StringDeserializer; -import org.apache.kafka.common.serialization.StringSerializer; import org.awaitility.Awaitility; import org.junit.Test; -import org.rnorth.ducttape.unreliables.Unreliables; +import org.testcontainers.AbstractKafka; import org.testcontainers.Testcontainers; import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.DockerImageName; -import java.time.Duration; import java.util.Collection; import java.util.Collections; -import java.util.Properties; import java.util.UUID; import java.util.concurrent.TimeUnit; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.api.Assertions.tuple; -public class KafkaContainerTest { +public class KafkaContainerTest extends AbstractKafka { private static final DockerImageName KAFKA_TEST_IMAGE = DockerImageName.parse("confluentinc/cp-kafka:6.2.1"); @@ -45,15 +33,6 @@ public class KafkaContainerTest { "confluentinc/cp-zookeeper:4.0.0" ); - private final ImmutableMap properties = ImmutableMap.of( - AdminClientConfig.SECURITY_PROTOCOL_CONFIG, - "SASL_PLAINTEXT", - SaslConfigs.SASL_MECHANISM, - "PLAIN", - SaslConfigs.SASL_JAAS_CONFIG, - "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"admin\" password=\"admin\";" - ); - @Test public void testUsage() throws Exception { try (KafkaContainer kafka = new KafkaContainer(KAFKA_TEST_IMAGE)) { @@ -344,91 +323,4 @@ private static String getJaasConfig() { "user_test=\"secret\";"; return jaasConfig; } - - private void testKafkaFunctionality(String bootstrapServers) throws Exception { - testKafkaFunctionality(bootstrapServers, false, 1, 1); - } - - private void testSecureKafkaFunctionality(String bootstrapServers) throws Exception { - testKafkaFunctionality(bootstrapServers, true, 1, 1); - } - - private void testKafkaFunctionality(String bootstrapServers, boolean authenticated, int partitions, int rf) - throws Exception { - ImmutableMap adminClientDefaultProperties = ImmutableMap.of( - AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, - bootstrapServers - ); - Properties adminClientProperties = new Properties(); - adminClientProperties.putAll(adminClientDefaultProperties); - - ImmutableMap consumerDefaultProperties = ImmutableMap.of( - ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, - bootstrapServers, - ConsumerConfig.GROUP_ID_CONFIG, - "tc-" + UUID.randomUUID(), - ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, - "earliest" - ); - Properties consumerProperties = new Properties(); - consumerProperties.putAll(consumerDefaultProperties); - - ImmutableMap producerDefaultProperties = ImmutableMap.of( - ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, - bootstrapServers, - ProducerConfig.CLIENT_ID_CONFIG, - UUID.randomUUID().toString() - ); - Properties producerProperties = new Properties(); - producerProperties.putAll(producerDefaultProperties); - - if (authenticated) { - adminClientProperties.putAll(this.properties); - consumerProperties.putAll(this.properties); - producerProperties.putAll(this.properties); - } - try ( - AdminClient adminClient = AdminClient.create(adminClientProperties); - KafkaProducer producer = new KafkaProducer<>( - producerProperties, - new StringSerializer(), - new StringSerializer() - ); - KafkaConsumer consumer = new KafkaConsumer<>( - consumerProperties, - new StringDeserializer(), - new StringDeserializer() - ); - ) { - String topicName = "messages-" + UUID.randomUUID(); - - Collection topics = Collections.singletonList(new NewTopic(topicName, partitions, (short) rf)); - adminClient.createTopics(topics).all().get(30, TimeUnit.SECONDS); - - consumer.subscribe(Collections.singletonList(topicName)); - - producer.send(new ProducerRecord<>(topicName, "testcontainers", "rulezzz")).get(); - - Unreliables.retryUntilTrue( - 10, - TimeUnit.SECONDS, - () -> { - ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); - - if (records.isEmpty()) { - return false; - } - - assertThat(records) - .hasSize(1) - .extracting(ConsumerRecord::topic, ConsumerRecord::key, ConsumerRecord::value) - .containsExactly(tuple(topicName, "testcontainers", "rulezzz")); - - return true; - } - ); - - consumer.unsubscribe(); - } - } } diff --git a/modules/kafka/src/test/java/org/testcontainers/kafka/KafkaContainerTest.java b/modules/kafka/src/test/java/org/testcontainers/kafka/KafkaContainerTest.java new file mode 100644 index 00000000000..d520cf33f7c --- /dev/null +++ b/modules/kafka/src/test/java/org/testcontainers/kafka/KafkaContainerTest.java @@ -0,0 +1,15 @@ +package org.testcontainers.kafka; + +import org.junit.Test; +import org.testcontainers.AbstractKafka; + +public class KafkaContainerTest extends AbstractKafka { + + @Test + public void testUsage() throws Exception { + try (KafkaContainer kafka = new KafkaContainer("apache/kafka:3.7.0")) { + kafka.start(); + testKafkaFunctionality(kafka.getBootstrapServers()); + } + } +} From 9d6e7655a929abcc4db735e16642e4eb40e12155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez?= Date: Thu, 4 Apr 2024 10:02:11 -0600 Subject: [PATCH 0076/1430] Cleanup japicmp excludes --- modules/elasticsearch/build.gradle | 6 ------ modules/mongodb/build.gradle | 6 ------ 2 files changed, 12 deletions(-) diff --git a/modules/elasticsearch/build.gradle b/modules/elasticsearch/build.gradle index 550e9a9b23a..56399a509d9 100644 --- a/modules/elasticsearch/build.gradle +++ b/modules/elasticsearch/build.gradle @@ -6,9 +6,3 @@ dependencies { testImplementation "org.elasticsearch.client:transport:7.17.17" testImplementation 'org.assertj:assertj-core:3.25.2' } - -tasks.japicmp { - methodExcludes = [ - "org.testcontainers.elasticsearch.ElasticsearchContainer#containerIsStarted(com.github.dockerjava.api.command.InspectContainerResponse)", - ] -} diff --git a/modules/mongodb/build.gradle b/modules/mongodb/build.gradle index c1b1f21b235..02e5cc6e71e 100644 --- a/modules/mongodb/build.gradle +++ b/modules/mongodb/build.gradle @@ -6,9 +6,3 @@ dependencies { testImplementation("org.mongodb:mongodb-driver-sync:4.11.1") testImplementation 'org.assertj:assertj-core:3.25.1' } - -tasks.japicmp { - methodExcludes = [ - "org.testcontainers.containers.MongoDBContainer#configure()" - ] -} From 5969b0f393b724c9ed2147272d87a24c8d9efe1c Mon Sep 17 00:00:00 2001 From: Thomas Vitale Date: Fri, 5 Apr 2024 07:53:50 +0200 Subject: [PATCH 0077/1430] Weaviate: Support new container registry (#8512) Fixes gh-8511 Signed-off-by: Thomas Vitale --- .../org/testcontainers/weaviate/WeaviateContainer.java | 10 +++++++--- .../testcontainers/weaviate/WeaviateContainerTest.java | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/weaviate/src/main/java/org/testcontainers/weaviate/WeaviateContainer.java b/modules/weaviate/src/main/java/org/testcontainers/weaviate/WeaviateContainer.java index c8920a4cfb9..6225c79dd4a 100644 --- a/modules/weaviate/src/main/java/org/testcontainers/weaviate/WeaviateContainer.java +++ b/modules/weaviate/src/main/java/org/testcontainers/weaviate/WeaviateContainer.java @@ -6,7 +6,7 @@ /** * Testcontainers implementation of Weaviate. *

- * Supported image: {@code semitechnologies/weaviate} + * Supported images: {@code cr.weaviate.io/semitechnologies/weaviate}, {@code semitechnologies/weaviate} *

* Exposed ports: *