Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for https://docs.docker.com/compose/extends/ Next Try #227

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -42,7 +41,7 @@ public class DockerComposeContainer<SELF extends DockerComposeContainer<SELF>> e
*/
private final String identifier;
private final Map<String, AmbassadorContainer> ambassadorContainers = new HashMap<>();
private final File composeFile;
private final List<File> composeFiles;
private Set<String> spawnedContainerIds;
private Map<String, Integer> scalingPreferences = new HashMap<>();
private DockerClient dockerClient;
Expand All @@ -59,13 +58,26 @@ public class DockerComposeContainer<SELF extends DockerComposeContainer<SELF>> 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<File> composeFiles) {
this(Base58.randomString(6).toLowerCase(), composeFiles);
}

public DockerComposeContainer(String identifier, File... composeFiles) {
this(identifier, Arrays.asList(composeFiles));
}

public DockerComposeContainer(String identifier, List<File> composeFiles) {

this.composeFiles = composeFiles;

// Use a unique identifier so that containers created for this compose environment can be identified
this.identifier = identifier;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -282,20 +294,31 @@ private SELF self() {
}

class DockerCompose extends GenericContainer<DockerCompose> {
public DockerCompose(File composeFile, String identifier) {
public DockerCompose(List<File> 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<String> absoluteDockerComposeFiles = composeFiles.stream().map(
file -> containerPwd + "/" + file.getAbsoluteFile().getName()).collect(Collectors.toList());
String composeFileEnvVariableValue = Joiner.on(File.pathSeparator).join(absoluteDockerComposeFiles);
logger().debug("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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
});

}
}
Original file line number Diff line number Diff line change
@@ -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;
});

}
}
6 changes: 6 additions & 0 deletions core/src/test/resources/docker-compose-base.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: '2'
services:
alpine:
build: compose-dockerfile
environment:
bar: base
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
version: '2'
services:
alpine:
environment:
bar: overwritten