From 31d1c558d6892dae5d227a9ff19173873c5b327d Mon Sep 17 00:00:00 2001 From: Christian Schilling Date: Thu, 22 Sep 2016 23:26:29 +0200 Subject: [PATCH 1/2] feat:add support to pass multiple docker compose files to the DockerComposeContainer --- .../containers/DockerComposeContainer.java | 57 +++++++++++----- .../junit/DockerComposeDoNotOverrideTest.java | 67 +++++++++++++++++++ .../junit/DockerComposeOverrideTest.java | 64 ++++++++++++++++++ .../test/resources/docker-compose-base.yml | 6 ++ .../docker-compose-non-default-override.yml | 5 ++ 5 files changed, 182 insertions(+), 17 deletions(-) create mode 100644 core/src/test/java/org/testcontainers/junit/DockerComposeDoNotOverrideTest.java create mode 100644 core/src/test/java/org/testcontainers/junit/DockerComposeOverrideTest.java create mode 100644 core/src/test/resources/docker-compose-base.yml create mode 100644 core/src/test/resources/docker-compose-non-default-override.yml diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index b01aaa70b79..b48628a2de3 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -22,13 +22,12 @@ import org.testcontainers.utility.ResourceReaper; import java.io.File; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; import static org.testcontainers.containers.BindMode.READ_ONLY; import static org.testcontainers.containers.BindMode.READ_WRITE; @@ -42,7 +41,7 @@ public class DockerComposeContainer> e */ private final String identifier; private final Map ambassadorContainers = new HashMap<>(); - private final File composeFile; + private final List composeFiles; private Set spawnedContainerIds; private Map scalingPreferences = new HashMap<>(); private DockerClient dockerClient; @@ -59,13 +58,26 @@ public class DockerComposeContainer> e .withConstantThroughput() .build(); - public DockerComposeContainer(File composeFile) { - this(composeFile, Base58.randomString(6).toLowerCase()); + @Deprecated + public DockerComposeContainer(File composeFile, String identifier) { + this(identifier, composeFile); } - @SuppressWarnings("WeakerAccess") - public DockerComposeContainer(File composeFile, String identifier) { - this.composeFile = composeFile; + public DockerComposeContainer(File... composeFiles) { + this(Arrays.asList(composeFiles)); + } + + public DockerComposeContainer(List composeFiles) { + this(Base58.randomString(6).toLowerCase(), composeFiles); + } + + public DockerComposeContainer(String identifier, File... composeFiles) { + this(identifier, Arrays.asList(composeFiles)); + } + + public DockerComposeContainer(String identifier, List composeFiles) { + + this.composeFiles = composeFiles; // Use a unique identifier so that containers created for this compose environment can be identified this.identifier = identifier; @@ -100,7 +112,7 @@ private void createServices() { } private DockerCompose getDockerCompose(String cmd) { - return new DockerCompose(composeFile, identifier) + return new DockerCompose(composeFiles, identifier) .withCommand(cmd) .withEnv(env); } @@ -282,20 +294,31 @@ private SELF self() { } class DockerCompose extends GenericContainer { - public DockerCompose(File composeFile, String identifier) { + public DockerCompose(List composeFiles, String identifier) { super("docker/compose:1.8.0"); + checkNotNull(composeFiles); + checkArgument(!composeFiles.isEmpty(), "No docker compose file have been provided"); + addEnv("COMPOSE_PROJECT_NAME", identifier); - // Map the docker compose file into the container - String pwd = composeFile.getAbsoluteFile().getParentFile().getAbsolutePath(); - String containerPwd = pwd; + // Map the docker compose file into the container + File dockerComposeBaseFile = composeFiles.get(0); + final String pwd = dockerComposeBaseFile.getAbsoluteFile().getParentFile().getAbsolutePath(); + final String containerPwd; if (SystemUtils.IS_OS_WINDOWS) { - containerPwd = PathUtils.createMinGWPath(containerPwd).substring(1); + containerPwd = PathUtils.createMinGWPath(pwd).substring(1); + } else { + containerPwd = pwd; } - addEnv("COMPOSE_FILE", containerPwd + "/" + composeFile.getAbsoluteFile().getName()); + List absoluteDockerComposeFiles = composeFiles.stream().map( + file -> containerPwd + "/" + file.getAbsoluteFile().getName()).collect(Collectors.toList()); + String composeFileEnvVariableValue = Joiner.on(File.pathSeparator).join(absoluteDockerComposeFiles); + logger().info("Set env COMPOSE_FILE={}", composeFileEnvVariableValue); + addEnv("COMPOSE_FILE", composeFileEnvVariableValue); addFileSystemBind(pwd, containerPwd, READ_ONLY); + // Ensure that compose can access docker. Since the container is assumed to be running on the same machine // as the docker daemon, just mapping the docker control socket is OK. // As there seems to be a problem with mapping to the /var/run directory in certain environments (e.g. CircleCI) diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeDoNotOverrideTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeDoNotOverrideTest.java new file mode 100644 index 00000000000..0037f48b6d6 --- /dev/null +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeDoNotOverrideTest.java @@ -0,0 +1,67 @@ +package org.testcontainers.junit; + +import com.google.common.util.concurrent.Uninterruptibles; +import org.junit.Assume; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.rnorth.ducttape.unreliables.Unreliables; +import org.testcontainers.containers.DockerComposeContainer; +import org.testcontainers.utility.TestEnvironment; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.Socket; +import java.util.concurrent.TimeUnit; + +import static org.rnorth.visibleassertions.VisibleAssertions.info; +import static org.rnorth.visibleassertions.VisibleAssertions.pass; + +/** + * Created by rnorth on 11/06/2016. + */ +public class DockerComposeDoNotOverrideTest { + + static final String DOCKER_COMPOSE_OVERRIDE_TEST_BASE_YML = "src/test/resources/docker-compose-base.yml"; + static final String DOCKER_COMPOSE_OVERRIDE_TEST_BASE_ENV = "bar=base"; + + static final String DOCKER_COMPOSE_OVERRIDE_TEST_OVERRIDE_YML = "src/test/resources/docker-compose-non-default-override.yml"; + static final String DOCKER_COMPOSE_OVERRIDE_TEST_OVERRIDE_ENV = "bar=overwritten"; + + @Rule + public DockerComposeContainer compose = + new DockerComposeContainer(new File(DOCKER_COMPOSE_OVERRIDE_TEST_BASE_YML)) + .withExposedService("alpine_1", 3000); + + @BeforeClass + public static void checkVersion() { + Assume.assumeTrue(TestEnvironment.dockerApiAtLeast("1.22")); + } + + + @Test(timeout = 30_000) + public void testEnvVar() throws IOException { + BufferedReader br = Unreliables.retryUntilSuccess(10, TimeUnit.SECONDS, () -> { + Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS); + + Socket socket = new Socket(compose.getServiceHost("alpine_1", 3000), compose.getServicePort("alpine_1", 3000)); + return new BufferedReader(new InputStreamReader(socket.getInputStream())); + }); + + Unreliables.retryUntilTrue(10, TimeUnit.SECONDS, () -> { + while (br.ready()) { + String line = br.readLine(); + if (line.contains(DOCKER_COMPOSE_OVERRIDE_TEST_BASE_ENV)) { + pass("Mapped environment variable was found"); + return true; + } + } + info("Mapped environment variable was not found yet - process probably not ready"); + Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS); + return false; + }); + + } +} diff --git a/core/src/test/java/org/testcontainers/junit/DockerComposeOverrideTest.java b/core/src/test/java/org/testcontainers/junit/DockerComposeOverrideTest.java new file mode 100644 index 00000000000..8d72d8d2533 --- /dev/null +++ b/core/src/test/java/org/testcontainers/junit/DockerComposeOverrideTest.java @@ -0,0 +1,64 @@ +package org.testcontainers.junit; + +import com.google.common.util.concurrent.Uninterruptibles; +import org.junit.Assume; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.rnorth.ducttape.unreliables.Unreliables; +import org.testcontainers.containers.DockerComposeContainer; +import org.testcontainers.utility.TestEnvironment; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.Socket; +import java.util.concurrent.TimeUnit; + +import static org.rnorth.visibleassertions.VisibleAssertions.info; +import static org.rnorth.visibleassertions.VisibleAssertions.pass; +import static org.testcontainers.junit.DockerComposeDoNotOverrideTest.*; + +/** + * Created by rnorth on 11/06/2016. + */ +public class DockerComposeOverrideTest { + + @Rule + public DockerComposeContainer compose = + new DockerComposeContainer( + new File(DOCKER_COMPOSE_OVERRIDE_TEST_BASE_YML), + new File(DOCKER_COMPOSE_OVERRIDE_TEST_OVERRIDE_YML)) + .withExposedService("alpine_1", 3000); + + @BeforeClass + public static void checkVersion() { + Assume.assumeTrue(TestEnvironment.dockerApiAtLeast("1.22")); + } + + + @Test(timeout = 30_000) + public void testEnvVar() throws IOException { + BufferedReader br = Unreliables.retryUntilSuccess(10, TimeUnit.SECONDS, () -> { + Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS); + + Socket socket = new Socket(compose.getServiceHost("alpine_1", 3000), compose.getServicePort("alpine_1", 3000)); + return new BufferedReader(new InputStreamReader(socket.getInputStream())); + }); + + Unreliables.retryUntilTrue(10, TimeUnit.SECONDS, () -> { + while (br.ready()) { + String line = br.readLine(); + if (line.contains(DOCKER_COMPOSE_OVERRIDE_TEST_OVERRIDE_ENV)) { + pass("Mapped environment variable was found"); + return true; + } + } + info("Mapped environment variable was not found yet - process probably not ready"); + Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS); + return false; + }); + + } +} diff --git a/core/src/test/resources/docker-compose-base.yml b/core/src/test/resources/docker-compose-base.yml new file mode 100644 index 00000000000..c2dda256277 --- /dev/null +++ b/core/src/test/resources/docker-compose-base.yml @@ -0,0 +1,6 @@ +version: '2' +services: + alpine: + build: compose-dockerfile + environment: + bar: base \ No newline at end of file diff --git a/core/src/test/resources/docker-compose-non-default-override.yml b/core/src/test/resources/docker-compose-non-default-override.yml new file mode 100644 index 00000000000..fa7acb70dfd --- /dev/null +++ b/core/src/test/resources/docker-compose-non-default-override.yml @@ -0,0 +1,5 @@ +version: '2' +services: + alpine: + environment: + bar: overwritten \ No newline at end of file From 5c91a714062091050d8ccefdfe17478df64009b6 Mon Sep 17 00:00:00 2001 From: Christian Schilling Date: Sat, 24 Sep 2016 11:45:30 +0200 Subject: [PATCH 2/2] refactor:switch from info to debug level for COMPOSE_FILE debug message --- .../org/testcontainers/containers/DockerComposeContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java index b48628a2de3..7ac8dd7d2be 100644 --- a/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java +++ b/core/src/main/java/org/testcontainers/containers/DockerComposeContainer.java @@ -315,7 +315,7 @@ public DockerCompose(List composeFiles, String identifier) { List absoluteDockerComposeFiles = composeFiles.stream().map( file -> containerPwd + "/" + file.getAbsoluteFile().getName()).collect(Collectors.toList()); String composeFileEnvVariableValue = Joiner.on(File.pathSeparator).join(absoluteDockerComposeFiles); - logger().info("Set env COMPOSE_FILE={}", composeFileEnvVariableValue); + logger().debug("Set env COMPOSE_FILE={}", composeFileEnvVariableValue); addEnv("COMPOSE_FILE", composeFileEnvVariableValue); addFileSystemBind(pwd, containerPwd, READ_ONLY);