From 7938cc21d234caab824d76c8cab778c2296dc59e Mon Sep 17 00:00:00 2001 From: "emanuel.trandafir" Date: Fri, 25 Oct 2024 16:09:22 +0200 Subject: [PATCH 1/8] updated docker compose redme --- core/docker-compose-test.yml | 7 + .../containers/ComposeContainerDocTest.java | 115 +++++++++++ .../test/resources/v2-compose-test-doc.env | 3 + .../test/resources/v2-compose-test-doc.yml | 11 ++ docs/modules/docker_compose.md | 178 +++++++----------- 5 files changed, 203 insertions(+), 111 deletions(-) create mode 100644 core/docker-compose-test.yml create mode 100644 core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java create mode 100644 core/src/test/resources/v2-compose-test-doc.env create mode 100644 core/src/test/resources/v2-compose-test-doc.yml diff --git a/core/docker-compose-test.yml b/core/docker-compose-test.yml new file mode 100644 index 00000000000..41d2bac8bc6 --- /dev/null +++ b/core/docker-compose-test.yml @@ -0,0 +1,7 @@ +version: '2.2' +services: + http: + build: . + image: python:latest + ports: + - 8080:8080 \ No newline at end of file diff --git a/core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java b/core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java new file mode 100644 index 00000000000..0ca560b3792 --- /dev/null +++ b/core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java @@ -0,0 +1,115 @@ +package org.testcontainers.containers; + +import org.junit.Ignore; +import org.junit.Test; +import org.testcontainers.containers.wait.strategy.Wait; + +import java.io.File; +import java.time.Duration; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + +public class ComposeContainerDocTest { + + private static final int REDIS_PORT = 6379; + private static final int POSTGRES_PORT = 5432; + private static final String DOCKER_COMPOSE_FILE_PATH = "src/test/resources/v2-compose-test-doc.yml"; + public static final String ENV_FILE_NAME = "v2-compose-test-doc.env"; + + @Test + public void testComposeContainerConstructor() { + try ( + // composeContainerConstructor { + ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) + .withExposedService("redis-1", REDIS_PORT) + .withExposedService("postgres-1", POSTGRES_PORT) + // } + ) { + compose.start(); + + // getServiceHostAndPort { + String redisUrl = String.format("%s:%s", + compose.getServiceHost("redis-1", REDIS_PORT), + compose.getServicePort("redis-1", REDIS_PORT) + ); + // } + assertThat(redisUrl).isNotBlank(); + + containsStartedServices(compose, "redis-1", "postgres-1"); + } + } + + @Test + public void testComposeContainerWithCombinedWaitStrategies() { + try ( + // composeContainerWithCombinedWaitStrategies { + ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) + .withExposedService("redis-1", REDIS_PORT, + Wait.forSuccessfulCommand("redis-cli ping")) + .withExposedService("postgres-1", POSTGRES_PORT, + Wait.forLogMessage(".*database system is ready to accept connections.*\\n", 1)) + // } + ){ + compose.start(); + containsStartedServices(compose, "redis-1", "postgres-1"); + } + } + + @Test + public void testComposeContainerWaitForPortWithTimeout() { + try ( + // composeContainerWaitForPortWithTimeout { + ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) + .withExposedService("redis-1", REDIS_PORT, + Wait.forListeningPort().withStartupTimeout(Duration.ofSeconds(30))) + // } + ){ + compose.start(); + containsStartedServices(compose, "redis-1"); + } + } + + @Test + public void testComposeContainerWithLocalCompose() { + try ( + // composeContainerWithLocalCompose { + ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) + .withExposedService("redis-1", REDIS_PORT) + .withLocalCompose(true) + // } + ){ + compose.start(); + containsStartedServices(compose, "redis-1"); + } + } + + @Test + public void test() { + try ( + // composeContainerWithCopyFiles { + ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) + .withExposedService("postgres-1", POSTGRES_PORT) + .withCopyFilesInContainer(ENV_FILE_NAME) + // } + ){ + compose.start(); + containsStartedServices(compose, "postgres-1"); + } + } + + private void containsStartedServices(ComposeContainer compose, String... expectedServices) { + final List containerNames = compose.listChildContainers() + .stream() + .flatMap(it -> Stream.of(it.getNames())) + .collect(Collectors.toList()); + + for (String service: expectedServices) { + assertThat(containerNames) + .anyMatch(it -> it.endsWith(service)); + } + } +} diff --git a/core/src/test/resources/v2-compose-test-doc.env b/core/src/test/resources/v2-compose-test-doc.env new file mode 100644 index 00000000000..418a240fa16 --- /dev/null +++ b/core/src/test/resources/v2-compose-test-doc.env @@ -0,0 +1,3 @@ +POSTGRES_USER=postgres +POSTGRES_PASSWORD=postgres +POSTGRES_DB=postgres \ No newline at end of file diff --git a/core/src/test/resources/v2-compose-test-doc.yml b/core/src/test/resources/v2-compose-test-doc.yml new file mode 100644 index 00000000000..2c17541157e --- /dev/null +++ b/core/src/test/resources/v2-compose-test-doc.yml @@ -0,0 +1,11 @@ +version: '3.8' + +services: + redis: + image: redis:7 + postgres: + image: postgres:17-alpine + environment: + POSTGRES_USER: myuser + POSTGRES_PASSWORD: mypassword + POSTGRES_DB: mydatabase diff --git a/docs/modules/docker_compose.md b/docs/modules/docker_compose.md index 9032e7c6ee2..b470431b8f7 100644 --- a/docs/modules/docker_compose.md +++ b/docs/modules/docker_compose.md @@ -2,158 +2,114 @@ ## Benefits -Similar to generic containers support, it's also possible to run a bespoke set of services -specified in a `docker-compose.yml` file. +Similar to generic container support, it's also possible to run a bespoke set of services specified in a `docker-compose.yml` file. -This is intended to be useful on projects where Docker Compose is already used in dev or other environments to define -services that an application may be dependent upon. +This is especially useful for projects where Docker Compose is already used in development or other environments to define services that an application may be dependent upon. -Behind the scenes, Testcontainers actually launches a temporary Docker Compose client - in a container, of course, so -it's not necessary to have it installed on all developer/test machines. +The [`ComposeContainer`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/ComposeContainer.html) leverages [Compose V2](https://www.docker.com/blog/announcing-compose-v2-general-availability/), making it easy to use the same dependencies from the development environment within tests. ## Example -A single class rule, pointing to a `docker-compose.yml` file, should be sufficient to launch any number of services -required by your tests: -```java -@ClassRule -public static DockerComposeContainer environment = - new DockerComposeContainer(new File("src/test/resources/compose-test.yml")) - .withExposedService("redis_1", REDIS_PORT) - .withExposedService("elasticsearch_1", ELASTICSEARCH_PORT); -``` +A single class `ComposeContainer`, defined based on a `docker-compose.yml` file, should be sufficient to launch any number of services required by our tests: + + +[Create a ComposeContainer](../../core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java) inside_block:composeContainerConstructor + + +!!! note + Make sure the service names use a `-` rather than `_` as separator. -In this example, `compose-test.yml` should have content such as: +In this example, Docker Compose file should have content such as: ```yaml -redis: - image: redis -elasticsearch: - image: elasticsearch +version: '3.8' + +services: + redis: + image: redis:7 + postgres: + image: postgres:17-alpine + environment: + POSTGRES_USER: postgres ``` -Note that it is not necessary to define ports to be exposed in the YAML file; this would inhibit reuse/inclusion of the -file in other contexts. +Note that it is not necessary to define ports to be exposed in the YAML file, as this would inhibit the reuse/inclusion of the file in other contexts. + +Instead, Testcontainers will spin up a small 'ambassador' container, which will proxy between the Compose-managed containers and ports that are accessible to our tests. This is done using a separate, minimal container that runs socat as a TCP proxy. + +## ComposeContainer vs DockerComposeContainer -Instead, Testcontainers will spin up a small 'ambassador' container, which will proxy -between the Compose-managed containers and ports that are accessible to your tests. This is done using a separate, minimal -container that runs socat as a TCP proxy. +So far, we discussed [`ComposeContainer`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/ComposeContainer.html), which is the equivalent of docker compose [version 2](https://www.docker.com/blog/announcing-compose-v2-general-availability/). -## Accessing a container from tests +On the other hand, [`DockerComposeContainer`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/DockerComposeContainer.html) utilizes Compose V1, which has been marked deprecated by Docker. -The rule provides methods for discovering how your tests can interact with the containers: +The two APIs are quite similar, and most examples provided on this page can be applied to both of them. + +## Accessing a Container + +ComposeContainer provides methods for discovering how your tests can interact with the containers: * `getServiceHost(serviceName, servicePort)` returns the IP address where the container is listening (via an ambassador container) * `getServicePort(serviceName, servicePort)` returns the Docker mapped port for a port that has been exposed (via an ambassador container) -For example, with the Redis example above, the following will allow your tests to access the Redis service: -```java -String redisUrl = environment.getServiceHost("redis_1", REDIS_PORT) - + ":" + - environment.getServicePort("redis_1", REDIS_PORT); -``` +Let's use this API to create the URL that will enable our tests to access the Redis service: + +[Access a Service's host and port](../../core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java) inside_block:getServiceHostAndPort + -## Startup timeout +## Wait Strategies and Startup Timeouts Ordinarily Testcontainers will wait for up to 60 seconds for each exposed container's first mapped network port to start listening. This simple measure provides a basic check whether a container is ready for use. -There are overloaded `withExposedService` methods that take a `WaitStrategy` so you can specify a timeout strategy per container. +There are overloaded `withExposedService` methods that take a [`WaitStrategy`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/wait/strategy/WaitStrategy.html) where we can specify a timeout strategy per container. We can either use the fluent API to crate a custom strategy or use one of the already existing ones, accessible via the static factory methods from of the [`Wait`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/wait/strategy/Wait.html) class. -### Waiting for startup examples +For instance, we can wait for exposed port and set a custom timeout: + +[Wait for the exposed port and use a custom timeout](../../core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java) inside_block:composeContainerWaitForPortWithTimeout + -Waiting for exposed port to start listening: -```java -@ClassRule -public static DockerComposeContainer environment = - new DockerComposeContainer(new File("src/test/resources/compose-test.yml")) - .withExposedService("redis_1", REDIS_PORT, - Wait.forListeningPort().withStartupTimeout(Duration.ofSeconds(30))); -``` +Needless to say, we can define different strategies for each service in our Docker Compose setup. -Wait for arbitrary status codes on an HTTPS endpoint: -```java -@ClassRule -public static DockerComposeContainer environment = - new DockerComposeContainer(new File("src/test/resources/compose-test.yml")) - .withExposedService("elasticsearch_1", ELASTICSEARCH_PORT, - Wait.forHttp("/all") - .forStatusCode(200) - .forStatusCode(401) - .usingTls()); -``` +For example, our Redis container can wait for a successful redis-cli command, while Postgres waits for a specific log message: -Separate wait strategies for each container: -```java -@ClassRule -public static DockerComposeContainer environment = - new DockerComposeContainer(new File("src/test/resources/compose-test.yml")) - .withExposedService("redis_1", REDIS_PORT, Wait.forListeningPort()) - .withExposedService("elasticsearch_1", ELASTICSEARCH_PORT, - Wait.forHttp("/all") - .forStatusCode(200) - .forStatusCode(401) - .usingTls()); -``` - -Alternatively, you can use `waitingFor(serviceName, waitStrategy)`, -for example if you need to wait on a log message from a service, but don't need to expose a port. + +[Wait for a custom command and a log message](../../core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java) inside_block:composeContainerWithCombinedWaitStrategies + -```java -@ClassRule -public static DockerComposeContainer environment = - new DockerComposeContainer(new File("src/test/resources/compose-test.yml")) - .withExposedService("redis_1", REDIS_PORT, Wait.forListeningPort()) - .waitingFor("db_1", Wait.forLogMessage("started", 1)); -``` +!!! More on Wait Strategies -## 'Local compose' mode - -You can override Testcontainers' default behaviour and make it use a `docker-compose` binary installed on the local machine. -This will generally yield an experience that is closer to running docker-compose locally, with the caveat that Docker Compose needs to be present on dev and CI machines. -```java -public static DockerComposeContainer environment = - new DockerComposeContainer(new File("src/test/resources/compose-test.yml")) - .withExposedService("redis_1", REDIS_PORT, Wait.forListeningPort()) - .waitingFor("db_1", Wait.forLogMessage("started", 1)) - .withLocalCompose(true); -``` + Refer to the documentation to learn how to use the API to create tailor-made strategies for [waiting until containers are fully started and ready](../features/startup_and_waits.md). -## Compose V2 +## The 'Local Compose' Mode -[Compose V2 is GA](https://www.docker.com/blog/announcing-compose-v2-general-availability/) and it relies on the `docker` command itself instead of `docker-compose`. -Testcontainers provides `ComposeContainer` if you want to use Compose V2. +We can override Testcontainers' default behaviour and make it use a `docker-compose` binary installed on the local machine. -```java -public static ComposeContainer environment = - new ComposeContainer(new File("src/test/resources/compose-test.yml")) - .withExposedService("redis-1", REDIS_PORT, Wait.forListeningPort()) - .waitingFor("db-1", Wait.forLogMessage("started", 1)); -``` +This will generally yield an experience that is closer to running _docker compose_ locally, with the caveat that Docker Compose needs to be present on dev and CI machines. -!!! note - Make sure the service name use a `-` instead of `_` as separator using `ComposeContainer`. + +[Use ComposeContainer in 'Local Compose' mode](../../core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java) inside_block:composeContainerWithLocalCompose + -## Build working directory +## Build Working Directory -You can select what files should be copied only via `withCopyFilesInContainer`: +We can select what files should be copied only via `withCopyFilesInContainer`: -```java -public static ComposeContainer environment = - new ComposeContainer(new File("compose.yml")) - .withCopyFilesInContainer(".env"); -``` + +[Use ComposeContainer in 'Local Compose' mode](../../core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java) inside_block:composeContainerWithCopyFiles + -In this example, only `compose.yml` and `.env` are copied over into the container that will run the Docker Compose file. +In this example, only docker compose and env files are copied over into the container that will run the Docker Compose file. By default, all files in the same directory as the compose file are copied over. -This can be used with `DockerComposeContainer` and `ComposeContainer`. -You can use file and directory references. -They are always resolved relative to the directory where the compose file resides. +We can use file and directory references. They are always resolved relative to the directory where the compose file resides. + +This can be used with [`DockerComposeContainer`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/DockerComposeContainer.html) and [`ComposeContainer`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/ComposeContainer.html). !!! note - This only work with containarized Compose, not with `Local Compose` mode. + + This can be used with [`DockerComposeContainer`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/DockerComposeContainer.html) and [`ComposeContainer`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/ComposeContainer.html) - but **only in the containerized Compose (not with `Local Compose` mode)**. ## Using private repositories in Docker compose When Docker Compose is used in container mode (not local), it's needs to be made aware of Docker settings for private repositories. From 39c56a4984c214075f6a14118d77c1eb215f97d7 Mon Sep 17 00:00:00 2001 From: "emanuel.trandafir" Date: Fri, 25 Oct 2024 16:18:43 +0200 Subject: [PATCH 2/8] formatting --- .../containers/ComposeContainerDocTest.java | 184 +++++++++--------- 1 file changed, 94 insertions(+), 90 deletions(-) diff --git a/core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java b/core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java index 0ca560b3792..b8f68a0a177 100644 --- a/core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java +++ b/core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java @@ -1,6 +1,5 @@ package org.testcontainers.containers; -import org.junit.Ignore; import org.junit.Test; import org.testcontainers.containers.wait.strategy.Wait; @@ -11,105 +10,110 @@ import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.catchThrowable; public class ComposeContainerDocTest { - private static final int REDIS_PORT = 6379; - private static final int POSTGRES_PORT = 5432; - private static final String DOCKER_COMPOSE_FILE_PATH = "src/test/resources/v2-compose-test-doc.yml"; - public static final String ENV_FILE_NAME = "v2-compose-test-doc.env"; + private static final int REDIS_PORT = 6379; + private static final int POSTGRES_PORT = 5432; + private static final String DOCKER_COMPOSE_FILE_PATH = "src/test/resources/v2-compose-test-doc.yml"; + public static final String ENV_FILE_NAME = "v2-compose-test-doc.env"; - @Test - public void testComposeContainerConstructor() { - try ( - // composeContainerConstructor { - ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) - .withExposedService("redis-1", REDIS_PORT) - .withExposedService("postgres-1", POSTGRES_PORT) - // } - ) { - compose.start(); + @Test + public void testComposeContainerConstructor() { + try ( + // composeContainerConstructor { + ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) + .withExposedService("redis-1", REDIS_PORT) + .withExposedService("postgres-1", POSTGRES_PORT) + // } + ) { + compose.start(); - // getServiceHostAndPort { - String redisUrl = String.format("%s:%s", - compose.getServiceHost("redis-1", REDIS_PORT), - compose.getServicePort("redis-1", REDIS_PORT) - ); - // } - assertThat(redisUrl).isNotBlank(); + // getServiceHostAndPort { + String redisUrl = String.format( + "%s:%s", + compose.getServiceHost("redis-1", REDIS_PORT), + compose.getServicePort("redis-1", REDIS_PORT) + ); + // } + assertThat(redisUrl).isNotBlank(); - containsStartedServices(compose, "redis-1", "postgres-1"); - } - } + containsStartedServices(compose, "redis-1", "postgres-1"); + } + } - @Test - public void testComposeContainerWithCombinedWaitStrategies() { - try ( - // composeContainerWithCombinedWaitStrategies { - ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) - .withExposedService("redis-1", REDIS_PORT, - Wait.forSuccessfulCommand("redis-cli ping")) - .withExposedService("postgres-1", POSTGRES_PORT, - Wait.forLogMessage(".*database system is ready to accept connections.*\\n", 1)) - // } - ){ - compose.start(); - containsStartedServices(compose, "redis-1", "postgres-1"); - } - } + @Test + public void testComposeContainerWithCombinedWaitStrategies() { + try ( + // composeContainerWithCombinedWaitStrategies { + ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) + .withExposedService("redis-1", REDIS_PORT, Wait.forSuccessfulCommand("redis-cli ping")) + .withExposedService( + "postgres-1", + POSTGRES_PORT, + Wait.forLogMessage(".*database system is ready to accept connections.*\\n", 1) + ) + // } + ) { + compose.start(); + containsStartedServices(compose, "redis-1", "postgres-1"); + } + } - @Test - public void testComposeContainerWaitForPortWithTimeout() { - try ( - // composeContainerWaitForPortWithTimeout { - ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) - .withExposedService("redis-1", REDIS_PORT, - Wait.forListeningPort().withStartupTimeout(Duration.ofSeconds(30))) - // } - ){ - compose.start(); - containsStartedServices(compose, "redis-1"); - } - } + @Test + public void testComposeContainerWaitForPortWithTimeout() { + try ( + // composeContainerWaitForPortWithTimeout { + ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) + .withExposedService( + "redis-1", + REDIS_PORT, + Wait.forListeningPort().withStartupTimeout(Duration.ofSeconds(30)) + ) + // } + ) { + compose.start(); + containsStartedServices(compose, "redis-1"); + } + } - @Test - public void testComposeContainerWithLocalCompose() { - try ( - // composeContainerWithLocalCompose { - ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) - .withExposedService("redis-1", REDIS_PORT) - .withLocalCompose(true) - // } - ){ - compose.start(); - containsStartedServices(compose, "redis-1"); - } - } + @Test + public void testComposeContainerWithLocalCompose() { + try ( + // composeContainerWithLocalCompose { + ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) + .withExposedService("redis-1", REDIS_PORT) + .withLocalCompose(true) + // } + ) { + compose.start(); + containsStartedServices(compose, "redis-1"); + } + } - @Test - public void test() { - try ( - // composeContainerWithCopyFiles { - ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) - .withExposedService("postgres-1", POSTGRES_PORT) - .withCopyFilesInContainer(ENV_FILE_NAME) - // } - ){ - compose.start(); - containsStartedServices(compose, "postgres-1"); - } - } + @Test + public void test() { + try ( + // composeContainerWithCopyFiles { + ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) + .withExposedService("postgres-1", POSTGRES_PORT) + .withCopyFilesInContainer(ENV_FILE_NAME) + // } + ) { + compose.start(); + containsStartedServices(compose, "postgres-1"); + } + } - private void containsStartedServices(ComposeContainer compose, String... expectedServices) { - final List containerNames = compose.listChildContainers() - .stream() - .flatMap(it -> Stream.of(it.getNames())) - .collect(Collectors.toList()); + private void containsStartedServices(ComposeContainer compose, String... expectedServices) { + final List containerNames = compose + .listChildContainers() + .stream() + .flatMap(it -> Stream.of(it.getNames())) + .collect(Collectors.toList()); - for (String service: expectedServices) { - assertThat(containerNames) - .anyMatch(it -> it.endsWith(service)); - } - } + for (String service : expectedServices) { + assertThat(containerNames).anyMatch(it -> it.endsWith(service)); + } + } } From 048a59463068a60901e5070cc8d353f8ccf898f6 Mon Sep 17 00:00:00 2001 From: "emanuel.trandafir" Date: Fri, 25 Oct 2024 17:06:43 +0200 Subject: [PATCH 3/8] fix checkstyle rule --- .../org/testcontainers/containers/ComposeContainerDocTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java b/core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java index b8f68a0a177..312edc2f9f3 100644 --- a/core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java +++ b/core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java @@ -14,8 +14,11 @@ public class ComposeContainerDocTest { private static final int REDIS_PORT = 6379; + private static final int POSTGRES_PORT = 5432; + private static final String DOCKER_COMPOSE_FILE_PATH = "src/test/resources/v2-compose-test-doc.yml"; + public static final String ENV_FILE_NAME = "v2-compose-test-doc.env"; @Test From d0f360ec4a20fae3ddf0934a2307fad6ba6e772f Mon Sep 17 00:00:00 2001 From: "emanuel.trandafir" Date: Mon, 28 Oct 2024 12:05:15 +0100 Subject: [PATCH 4/8] reuse existing tests wherever possible --- .../containers/ComposeContainerDocTest.java | 122 ------------------ .../containers/ComposeProfilesOptionTest.java | 4 +- .../junit/ComposeContainerTest.java | 11 +- .../ComposeContainerWithCopyFilesTest.java | 2 + .../ComposeContainerWithWaitStrategies.java | 54 ++++++++ .../test/resources/v2-compose-test-doc.env | 3 - .../test/resources/v2-compose-test-doc.yml | 11 -- docs/modules/docker_compose.md | 29 +++-- 8 files changed, 84 insertions(+), 152 deletions(-) delete mode 100644 core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java create mode 100644 core/src/test/java/org/testcontainers/junit/ComposeContainerWithWaitStrategies.java delete mode 100644 core/src/test/resources/v2-compose-test-doc.env delete mode 100644 core/src/test/resources/v2-compose-test-doc.yml diff --git a/core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java b/core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java deleted file mode 100644 index 312edc2f9f3..00000000000 --- a/core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java +++ /dev/null @@ -1,122 +0,0 @@ -package org.testcontainers.containers; - -import org.junit.Test; -import org.testcontainers.containers.wait.strategy.Wait; - -import java.io.File; -import java.time.Duration; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.assertj.core.api.Assertions.assertThat; - -public class ComposeContainerDocTest { - - private static final int REDIS_PORT = 6379; - - private static final int POSTGRES_PORT = 5432; - - private static final String DOCKER_COMPOSE_FILE_PATH = "src/test/resources/v2-compose-test-doc.yml"; - - public static final String ENV_FILE_NAME = "v2-compose-test-doc.env"; - - @Test - public void testComposeContainerConstructor() { - try ( - // composeContainerConstructor { - ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) - .withExposedService("redis-1", REDIS_PORT) - .withExposedService("postgres-1", POSTGRES_PORT) - // } - ) { - compose.start(); - - // getServiceHostAndPort { - String redisUrl = String.format( - "%s:%s", - compose.getServiceHost("redis-1", REDIS_PORT), - compose.getServicePort("redis-1", REDIS_PORT) - ); - // } - assertThat(redisUrl).isNotBlank(); - - containsStartedServices(compose, "redis-1", "postgres-1"); - } - } - - @Test - public void testComposeContainerWithCombinedWaitStrategies() { - try ( - // composeContainerWithCombinedWaitStrategies { - ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) - .withExposedService("redis-1", REDIS_PORT, Wait.forSuccessfulCommand("redis-cli ping")) - .withExposedService( - "postgres-1", - POSTGRES_PORT, - Wait.forLogMessage(".*database system is ready to accept connections.*\\n", 1) - ) - // } - ) { - compose.start(); - containsStartedServices(compose, "redis-1", "postgres-1"); - } - } - - @Test - public void testComposeContainerWaitForPortWithTimeout() { - try ( - // composeContainerWaitForPortWithTimeout { - ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) - .withExposedService( - "redis-1", - REDIS_PORT, - Wait.forListeningPort().withStartupTimeout(Duration.ofSeconds(30)) - ) - // } - ) { - compose.start(); - containsStartedServices(compose, "redis-1"); - } - } - - @Test - public void testComposeContainerWithLocalCompose() { - try ( - // composeContainerWithLocalCompose { - ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) - .withExposedService("redis-1", REDIS_PORT) - .withLocalCompose(true) - // } - ) { - compose.start(); - containsStartedServices(compose, "redis-1"); - } - } - - @Test - public void test() { - try ( - // composeContainerWithCopyFiles { - ComposeContainer compose = new ComposeContainer(new File(DOCKER_COMPOSE_FILE_PATH)) - .withExposedService("postgres-1", POSTGRES_PORT) - .withCopyFilesInContainer(ENV_FILE_NAME) - // } - ) { - compose.start(); - containsStartedServices(compose, "postgres-1"); - } - } - - private void containsStartedServices(ComposeContainer compose, String... expectedServices) { - final List containerNames = compose - .listChildContainers() - .stream() - .flatMap(it -> Stream.of(it.getNames())) - .collect(Collectors.toList()); - - for (String service : expectedServices) { - assertThat(containerNames).anyMatch(it -> it.endsWith(service)); - } - } -} diff --git a/core/src/test/java/org/testcontainers/containers/ComposeProfilesOptionTest.java b/core/src/test/java/org/testcontainers/containers/ComposeProfilesOptionTest.java index 71aba726dda..8fc662a118e 100644 --- a/core/src/test/java/org/testcontainers/containers/ComposeProfilesOptionTest.java +++ b/core/src/test/java/org/testcontainers/containers/ComposeProfilesOptionTest.java @@ -37,9 +37,11 @@ public void setUp() { @Test public void testProfileOption() { try ( + // composeContainerWithLocalCompose { ComposeContainer compose = new ComposeContainer(COMPOSE_FILE) - .withOptions("--profile=cache") .withLocalCompose(true) + // } + .withOptions("--profile=cache") ) { compose.start(); assertThat(compose.listChildContainers()).hasSize(1); diff --git a/core/src/test/java/org/testcontainers/junit/ComposeContainerTest.java b/core/src/test/java/org/testcontainers/junit/ComposeContainerTest.java index c101da6b6b3..39c7ff2baf5 100644 --- a/core/src/test/java/org/testcontainers/junit/ComposeContainerTest.java +++ b/core/src/test/java/org/testcontainers/junit/ComposeContainerTest.java @@ -18,21 +18,30 @@ public class ComposeContainerTest extends BaseComposeTest { @Rule + // composeContainerConstructor { public ComposeContainer environment = new ComposeContainer( new File("src/test/resources/composev2/compose-test.yml") ) .withExposedService("redis-1", REDIS_PORT) .withExposedService("db-1", 3306); + // } + @Override protected ComposeContainer getEnvironment() { return environment; } @Test - public void testGetServicePort() { + public void testGetServiceHostAndPort() { + // getServiceHostAndPort { + String serviceHost = environment.getServiceHost("redis-1", REDIS_PORT); int serviceWithInstancePort = environment.getServicePort("redis-1", REDIS_PORT); + // } + + assertThat(serviceHost).as("Service host is not blank").isNotBlank(); assertThat(serviceWithInstancePort).as("Port is set for service with instance number").isNotNull(); + int serviceWithoutInstancePort = environment.getServicePort("redis", REDIS_PORT); assertThat(serviceWithoutInstancePort).as("Port is set for service with instance number").isNotNull(); assertThat(serviceWithoutInstancePort).as("Service ports are the same").isEqualTo(serviceWithInstancePort); diff --git a/core/src/test/java/org/testcontainers/junit/ComposeContainerWithCopyFilesTest.java b/core/src/test/java/org/testcontainers/junit/ComposeContainerWithCopyFilesTest.java index 390ddd505fb..2b1e2cd4081 100644 --- a/core/src/test/java/org/testcontainers/junit/ComposeContainerWithCopyFilesTest.java +++ b/core/src/test/java/org/testcontainers/junit/ComposeContainerWithCopyFilesTest.java @@ -49,11 +49,13 @@ public void testWithFileCopyInclusionUsingFilePath() throws IOException { @Test public void testWithFileCopyInclusionUsingDirectoryPath() throws IOException { try ( + // composeContainerWithCopyFiles { ComposeContainer environment = new ComposeContainer( new File("src/test/resources/compose-file-copy-inclusions/compose-test-only.yml") ) .withExposedService("app", 8080) .withCopyFilesInContainer("Dockerfile", "EnvVariableRestEndpoint.java", "test") + // } ) { environment.start(); diff --git a/core/src/test/java/org/testcontainers/junit/ComposeContainerWithWaitStrategies.java b/core/src/test/java/org/testcontainers/junit/ComposeContainerWithWaitStrategies.java new file mode 100644 index 00000000000..1304413dce5 --- /dev/null +++ b/core/src/test/java/org/testcontainers/junit/ComposeContainerWithWaitStrategies.java @@ -0,0 +1,54 @@ +package org.testcontainers.junit; + +import org.junit.Test; +import org.testcontainers.containers.ComposeContainer; +import org.testcontainers.containers.wait.strategy.Wait; + +import java.io.File; +import java.time.Duration; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ComposeContainerWithWaitStrategies { + + private static final int REDIS_PORT = 6379; + + @Test + public void testComposeContainerConstructor() { + try ( + // composeContainerWithCombinedWaitStrategies { + ComposeContainer compose = new ComposeContainer(new File("src/test/resources/composev2/compose-test.yml")) + .withExposedService("redis-1", REDIS_PORT, Wait.forSuccessfulCommand("redis-cli ping")) + .withExposedService("db-1", 3306, Wait.forLogMessage(".*ready for connections.*\\n", 1)) + // } + ) { + compose.start(); + containsStartedServices(compose, "redis-1", "db-1"); + } + } + + @Test + public void testComposeContainerWaitForPortWithTimeout() { + try ( + // composeContainerWaitForPortWithTimeout { + ComposeContainer compose = new ComposeContainer(new File("src/test/resources/composev2/compose-test.yml")) + .withExposedService( + "redis-1", + REDIS_PORT, + Wait.forListeningPort().withStartupTimeout(Duration.ofSeconds(30)) + ) + // } + ) { + compose.start(); + containsStartedServices(compose, "redis-1"); + } + } + + private void containsStartedServices(ComposeContainer compose, String... expectedServices) { + for (String serviceName : expectedServices) { + assertThat(compose.getContainerByServiceName(serviceName)) + .as("Container should be found by service name %s", serviceName) + .isPresent(); + } + } +} diff --git a/core/src/test/resources/v2-compose-test-doc.env b/core/src/test/resources/v2-compose-test-doc.env deleted file mode 100644 index 418a240fa16..00000000000 --- a/core/src/test/resources/v2-compose-test-doc.env +++ /dev/null @@ -1,3 +0,0 @@ -POSTGRES_USER=postgres -POSTGRES_PASSWORD=postgres -POSTGRES_DB=postgres \ No newline at end of file diff --git a/core/src/test/resources/v2-compose-test-doc.yml b/core/src/test/resources/v2-compose-test-doc.yml deleted file mode 100644 index 2c17541157e..00000000000 --- a/core/src/test/resources/v2-compose-test-doc.yml +++ /dev/null @@ -1,11 +0,0 @@ -version: '3.8' - -services: - redis: - image: redis:7 - postgres: - image: postgres:17-alpine - environment: - POSTGRES_USER: myuser - POSTGRES_PASSWORD: mypassword - POSTGRES_DB: mydatabase diff --git a/docs/modules/docker_compose.md b/docs/modules/docker_compose.md index b470431b8f7..a4b7e057e2d 100644 --- a/docs/modules/docker_compose.md +++ b/docs/modules/docker_compose.md @@ -13,23 +13,24 @@ The [`ComposeContainer`](http://static.javadoc.io/org.testcontainers/testcontain A single class `ComposeContainer`, defined based on a `docker-compose.yml` file, should be sufficient to launch any number of services required by our tests: -[Create a ComposeContainer](../../core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java) inside_block:composeContainerConstructor +[Create a ComposeContainer](../../core/src/test/java/org/testcontainers/junit/ComposeContainerTest.java) inside_block:composeContainerConstructor !!! note Make sure the service names use a `-` rather than `_` as separator. -In this example, Docker Compose file should have content such as: + ```yaml -version: '3.8' +!include ../../core/src/test/resources/composev2/compose-test.yml +``` +In this example, Docker Compose file should have content such as: +```yaml services: redis: - image: redis:7 - postgres: - image: postgres:17-alpine - environment: - POSTGRES_USER: postgres + image: redis + db: + image: mysql:8.0.36 ``` Note that it is not necessary to define ports to be exposed in the YAML file, as this would inhibit the reuse/inclusion of the file in other contexts. @@ -55,7 +56,7 @@ ComposeContainer provides methods for discovering how your tests can interact wi Let's use this API to create the URL that will enable our tests to access the Redis service: -[Access a Service's host and port](../../core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java) inside_block:getServiceHostAndPort +[Access a Service's host and port](../../core/src/test/java/org/testcontainers/junit/ComposeContainerTest.java) inside_block:getServiceHostAndPort ## Wait Strategies and Startup Timeouts @@ -67,15 +68,15 @@ There are overloaded `withExposedService` methods that take a [`WaitStrategy`](h For instance, we can wait for exposed port and set a custom timeout: -[Wait for the exposed port and use a custom timeout](../../core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java) inside_block:composeContainerWaitForPortWithTimeout +[Wait for the exposed port and use a custom timeout](../../core/src/test/java/org/testcontainers/junit/ComposeContainerWithWaitStrategies.java) inside_block:composeContainerWaitForPortWithTimeout Needless to say, we can define different strategies for each service in our Docker Compose setup. -For example, our Redis container can wait for a successful redis-cli command, while Postgres waits for a specific log message: +For example, our Redis container can wait for a successful redis-cli command, while our db service waits for a specific log message: -[Wait for a custom command and a log message](../../core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java) inside_block:composeContainerWithCombinedWaitStrategies +[Wait for a custom command and a log message](../../core/src/test/java/org/testcontainers/junit/ComposeContainerWithWaitStrategies.java) inside_block:composeContainerWithCombinedWaitStrategies !!! More on Wait Strategies @@ -89,7 +90,7 @@ We can override Testcontainers' default behaviour and make it use a `docker-comp This will generally yield an experience that is closer to running _docker compose_ locally, with the caveat that Docker Compose needs to be present on dev and CI machines. -[Use ComposeContainer in 'Local Compose' mode](../../core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java) inside_block:composeContainerWithLocalCompose +[Use ComposeContainer in 'Local Compose' mode](../../core/src/test/java/org/testcontainers/containers/ComposeProfilesOptionTest.java) inside_block:composeContainerWithLocalCompose ## Build Working Directory @@ -97,7 +98,7 @@ This will generally yield an experience that is closer to running _docker compos We can select what files should be copied only via `withCopyFilesInContainer`: -[Use ComposeContainer in 'Local Compose' mode](../../core/src/test/java/org/testcontainers/containers/ComposeContainerDocTest.java) inside_block:composeContainerWithCopyFiles +[Use ComposeContainer in 'Local Compose' mode](../../core/src/test/java/org/testcontainers/junit/ComposeContainerWithCopyFilesTest.java) inside_block:composeContainerWithCopyFiles In this example, only docker compose and env files are copied over into the container that will run the Docker Compose file. From deec12da5558939cf537ee0ea5ecf118385154ba Mon Sep 17 00:00:00 2001 From: "emanuel.trandafir" Date: Mon, 28 Oct 2024 12:15:21 +0100 Subject: [PATCH 5/8] minor fixes --- core/docker-compose-test.yml | 7 ------- docs/modules/docker_compose.md | 5 ----- 2 files changed, 12 deletions(-) delete mode 100644 core/docker-compose-test.yml diff --git a/core/docker-compose-test.yml b/core/docker-compose-test.yml deleted file mode 100644 index 41d2bac8bc6..00000000000 --- a/core/docker-compose-test.yml +++ /dev/null @@ -1,7 +0,0 @@ -version: '2.2' -services: - http: - build: . - image: python:latest - ports: - - 8080:8080 \ No newline at end of file diff --git a/docs/modules/docker_compose.md b/docs/modules/docker_compose.md index a4b7e057e2d..fd54c1c4529 100644 --- a/docs/modules/docker_compose.md +++ b/docs/modules/docker_compose.md @@ -19,11 +19,6 @@ A single class `ComposeContainer`, defined based on a `docker-compose.yml` file, !!! note Make sure the service names use a `-` rather than `_` as separator. - -```yaml -!include ../../core/src/test/resources/composev2/compose-test.yml -``` - In this example, Docker Compose file should have content such as: ```yaml services: From 25727427bf30d0d440b78edd2a07649c45964dbd Mon Sep 17 00:00:00 2001 From: "emanuel.trandafir" Date: Tue, 29 Oct 2024 08:32:22 +0100 Subject: [PATCH 6/8] use sembr, remove javadoc links, minor changes --- docs/modules/docker_compose.md | 42 +++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/docs/modules/docker_compose.md b/docs/modules/docker_compose.md index fd54c1c4529..f8ede59a6c7 100644 --- a/docs/modules/docker_compose.md +++ b/docs/modules/docker_compose.md @@ -4,13 +4,16 @@ Similar to generic container support, it's also possible to run a bespoke set of services specified in a `docker-compose.yml` file. -This is especially useful for projects where Docker Compose is already used in development or other environments to define services that an application may be dependent upon. +This is especially useful for projects where Docker Compose is already used in development +or other environments to define services that an application may be dependent upon. -The [`ComposeContainer`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/ComposeContainer.html) leverages [Compose V2](https://www.docker.com/blog/announcing-compose-v2-general-availability/), making it easy to use the same dependencies from the development environment within tests. +The `ComposeContainer` leverages [Compose V2](https://www.docker.com/blog/announcing-compose-v2-general-availability/), +making it easy to use the same dependencies from the development environment within tests. ## Example -A single class `ComposeContainer`, defined based on a `docker-compose.yml` file, should be sufficient to launch any number of services required by our tests: +A single class `ComposeContainer`, defined based on a `docker-compose.yml` file, +should be sufficient to launch any number of services required by our tests: [Create a ComposeContainer](../../core/src/test/java/org/testcontainers/junit/ComposeContainerTest.java) inside_block:composeContainerConstructor @@ -28,15 +31,17 @@ services: image: mysql:8.0.36 ``` -Note that it is not necessary to define ports to be exposed in the YAML file, as this would inhibit the reuse/inclusion of the file in other contexts. +Note that it is not necessary to define ports to be exposed in the YAML file, +as this would inhibit the reuse/inclusion of the file in other contexts. -Instead, Testcontainers will spin up a small 'ambassador' container, which will proxy between the Compose-managed containers and ports that are accessible to our tests. This is done using a separate, minimal container that runs socat as a TCP proxy. +Instead, Testcontainers will spin up a small 'ambassador' container, +which will proxy between the Compose-managed containers and ports that are accessible to our tests. ## ComposeContainer vs DockerComposeContainer -So far, we discussed [`ComposeContainer`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/ComposeContainer.html), which is the equivalent of docker compose [version 2](https://www.docker.com/blog/announcing-compose-v2-general-availability/). +So far, we discussed `ComposeContainer`, which is the equivalent of docker compose [version 2](https://www.docker.com/blog/announcing-compose-v2-general-availability/). -On the other hand, [`DockerComposeContainer`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/DockerComposeContainer.html) utilizes Compose V1, which has been marked deprecated by Docker. +On the other hand, `DockerComposeContainer` utilizes Compose V1, which has been marked deprecated by Docker. The two APIs are quite similar, and most examples provided on this page can be applied to both of them. @@ -56,10 +61,13 @@ Let's use this API to create the URL that will enable our tests to access the Re ## Wait Strategies and Startup Timeouts Ordinarily Testcontainers will wait for up to 60 seconds for each exposed container's first mapped network port to start listening. - This simple measure provides a basic check whether a container is ready for use. -There are overloaded `withExposedService` methods that take a [`WaitStrategy`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/wait/strategy/WaitStrategy.html) where we can specify a timeout strategy per container. We can either use the fluent API to crate a custom strategy or use one of the already existing ones, accessible via the static factory methods from of the [`Wait`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/wait/strategy/Wait.html) class. +There are overloaded `withExposedService` methods that take a `WaitStrategy` +where we can specify a timeout strategy per container. + +We can either use the fluent API to crate a [custom strategy](../features/startup_and_waits.md) or use one of the already existing ones, +accessible via the static factory methods from of the `Wait` class. For instance, we can wait for exposed port and set a custom timeout: @@ -68,7 +76,8 @@ For instance, we can wait for exposed port and set a custom timeout: Needless to say, we can define different strategies for each service in our Docker Compose setup. -For example, our Redis container can wait for a successful redis-cli command, while our db service waits for a specific log message: +For example, our Redis container can wait for a successful redis-cli command, +while our db service waits for a specific log message: [Wait for a custom command and a log message](../../core/src/test/java/org/testcontainers/junit/ComposeContainerWithWaitStrategies.java) inside_block:composeContainerWithCombinedWaitStrategies @@ -82,7 +91,8 @@ For example, our Redis container can wait for a successful redis-cli command, wh We can override Testcontainers' default behaviour and make it use a `docker-compose` binary installed on the local machine. -This will generally yield an experience that is closer to running _docker compose_ locally, with the caveat that Docker Compose needs to be present on dev and CI machines. +This will generally yield an experience that is closer to running _docker compose_ locally, +with the caveat that Docker Compose needs to be present on dev and CI machines. [Use ComposeContainer in 'Local Compose' mode](../../core/src/test/java/org/testcontainers/containers/ComposeProfilesOptionTest.java) inside_block:composeContainerWithLocalCompose @@ -99,16 +109,16 @@ We can select what files should be copied only via `withCopyFilesInContainer`: In this example, only docker compose and env files are copied over into the container that will run the Docker Compose file. By default, all files in the same directory as the compose file are copied over. -We can use file and directory references. They are always resolved relative to the directory where the compose file resides. - -This can be used with [`DockerComposeContainer`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/DockerComposeContainer.html) and [`ComposeContainer`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/ComposeContainer.html). +We can use file and directory references. +They are always resolved relative to the directory where the compose file resides. !!! note - This can be used with [`DockerComposeContainer`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/DockerComposeContainer.html) and [`ComposeContainer`](http://static.javadoc.io/org.testcontainers/testcontainers/{{ latest_version }}/org/testcontainers/containers/ComposeContainer.html) - but **only in the containerized Compose (not with `Local Compose` mode)**. + This can be used with `DockerComposeContainer` and `ComposeContainer`, but **only in the containerized Compose (not with `Local Compose` mode)**. ## Using private repositories in Docker compose -When Docker Compose is used in container mode (not local), it's needs to be made aware of Docker settings for private repositories. +When Docker Compose is used in container mode (not local), +it needs to be made aware of Docker settings for private repositories. By default, those setting are located in `$HOME/.docker/config.json`. There are 3 ways to specify location of the `config.json` for Docker Compose: From 2037dfa9c42d115543d3bcdffc99de419a04133e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 26 Nov 2024 14:03:10 -0500 Subject: [PATCH 7/8] Apply suggestions from code review --- docs/modules/docker_compose.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/docs/modules/docker_compose.md b/docs/modules/docker_compose.md index f8ede59a6c7..1297e031e0f 100644 --- a/docs/modules/docker_compose.md +++ b/docs/modules/docker_compose.md @@ -2,7 +2,8 @@ ## Benefits -Similar to generic container support, it's also possible to run a bespoke set of services specified in a `docker-compose.yml` file. +Similar to generic container support, it's also possible to run a bespoke set of services specified in a +`docker-compose.yml` file. This is especially useful for projects where Docker Compose is already used in development or other environments to define services that an application may be dependent upon. @@ -34,12 +35,12 @@ services: Note that it is not necessary to define ports to be exposed in the YAML file, as this would inhibit the reuse/inclusion of the file in other contexts. -Instead, Testcontainers will spin up a small 'ambassador' container, +Instead, Testcontainers will spin up a small `ambassador` container, which will proxy between the Compose-managed containers and ports that are accessible to our tests. ## ComposeContainer vs DockerComposeContainer -So far, we discussed `ComposeContainer`, which is the equivalent of docker compose [version 2](https://www.docker.com/blog/announcing-compose-v2-general-availability/). +So far, we discussed `ComposeContainer`, which supports docker compose [version 2](https://www.docker.com/blog/announcing-compose-v2-general-availability/). On the other hand, `DockerComposeContainer` utilizes Compose V1, which has been marked deprecated by Docker. @@ -83,9 +84,7 @@ while our db service waits for a specific log message: [Wait for a custom command and a log message](../../core/src/test/java/org/testcontainers/junit/ComposeContainerWithWaitStrategies.java) inside_block:composeContainerWithCombinedWaitStrategies -!!! More on Wait Strategies - Refer to the documentation to learn how to use the API to create tailor-made strategies for [waiting until containers are fully started and ready](../features/startup_and_waits.md). ## The 'Local Compose' Mode @@ -113,12 +112,11 @@ We can use file and directory references. They are always resolved relative to the directory where the compose file resides. !!! note - This can be used with `DockerComposeContainer` and `ComposeContainer`, but **only in the containerized Compose (not with `Local Compose` mode)**. ## Using private repositories in Docker compose -When Docker Compose is used in container mode (not local), -it needs to be made aware of Docker settings for private repositories. +When Docker Compose is used in container mode (not local), it needs to be made aware of Docker +settings for private repositories. By default, those setting are located in `$HOME/.docker/config.json`. There are 3 ways to specify location of the `config.json` for Docker Compose: From e4bc2a4199146e463db83ce8f07c59665e997380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edd=C3=BA=20Mel=C3=A9ndez=20Gonzales?= Date: Tue, 26 Nov 2024 14:07:47 -0500 Subject: [PATCH 8/8] Update docs/modules/docker_compose.md --- docs/modules/docker_compose.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/docker_compose.md b/docs/modules/docker_compose.md index 1297e031e0f..2ac45912479 100644 --- a/docs/modules/docker_compose.md +++ b/docs/modules/docker_compose.md @@ -48,7 +48,7 @@ The two APIs are quite similar, and most examples provided on this page can be a ## Accessing a Container -ComposeContainer provides methods for discovering how your tests can interact with the containers: +`ComposeContainer` provides methods for discovering how your tests can interact with the containers: * `getServiceHost(serviceName, servicePort)` returns the IP address where the container is listening (via an ambassador container)