Skip to content
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 @@ -16,6 +16,7 @@
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -59,36 +60,100 @@ public class ComposeContainer implements Startable {

public static final String COMPOSE_EXECUTABLE = SystemUtils.IS_OS_WINDOWS ? "docker.exe" : "docker";

private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("docker:24.0.2");
private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("docker");

private final ComposeDelegate composeDelegate;

private String project;

private List<String> filesInDirectory = new ArrayList<>();

/**
* Creates a new ComposeContainer using the specified Docker image and compose files.
*
* @param image The Docker image to use for the container
* @param composeFiles One or more Docker Compose configuration files
*/
public ComposeContainer(DockerImageName image, File... composeFiles) {
this(image, Arrays.asList(composeFiles));
}

/**
* Creates a new ComposeContainer using the specified Docker image and compose files.
*
* @param image The Docker image to use for the container
* @param composeFiles A list of Docker Compose configuration files
*/
public ComposeContainer(DockerImageName image, List<File> composeFiles) {
this(image, Base58.randomString(6).toLowerCase(), composeFiles);
}

/**
* Creates a new ComposeContainer with the specified Docker image, identifier, and compose files.
*
* @param image The Docker image to use for the container
* @param identifier A unique identifier for this compose environment
* @param composeFiles One or more Docker Compose configuration files
*/
public ComposeContainer(DockerImageName image, String identifier, File... composeFiles) {
this(image, identifier, Arrays.asList(composeFiles));
}

/**
* Creates a new ComposeContainer with the specified Docker image, identifier, and a single compose file.
*
* @param image The Docker image to use for the container
* @param identifier A unique identifier for this compose environment
* @param composeFile A Docker Compose configuration file
*/
public ComposeContainer(DockerImageName image, String identifier, File composeFile) {
this(image, identifier, Collections.singletonList(composeFile));
}

/**
* Creates a new ComposeContainer with the specified Docker image, identifier, and compose files.
*
* @param image The Docker image to use for the container
* @param identifier A unique identifier for this compose environment
* @param composeFiles A list of Docker Compose configuration files
*/
public ComposeContainer(DockerImageName image, String identifier, List<File> composeFiles) {
image.assertCompatibleWith(DEFAULT_IMAGE_NAME);
this.composeDelegate =
new ComposeDelegate(ComposeDelegate.ComposeVersion.V2, composeFiles, identifier, COMPOSE_EXECUTABLE, image);
this.project = this.composeDelegate.getProject();
}

/**
* Use the new constructor {@link #ComposeContainer(DockerImageName image, File... composeFiles)}
*/
public ComposeContainer(File... composeFiles) {
this(Arrays.asList(composeFiles));
this(DEFAULT_IMAGE_NAME, Arrays.asList(composeFiles));
this.localCompose = true;
}

/**
* Use the new constructor {@link #ComposeContainer(DockerImageName image, List composeFiles)}
*/
public ComposeContainer(List<File> composeFiles) {
this(Base58.randomString(6).toLowerCase(), composeFiles);
this(DEFAULT_IMAGE_NAME, composeFiles);
this.localCompose = true;
}

/**
* Use the new constructor {@link #ComposeContainer(DockerImageName image, String identifier, File... composeFile)}
*/
public ComposeContainer(String identifier, File... composeFiles) {
this(identifier, Arrays.asList(composeFiles));
this(DEFAULT_IMAGE_NAME, identifier, Arrays.asList(composeFiles));
this.localCompose = true;
}

/**
* Use the new constructor {@link #ComposeContainer(DockerImageName image, String identifier, List composeFiles)}
*/
public ComposeContainer(String identifier, List<File> composeFiles) {
this.composeDelegate =
new ComposeDelegate(
ComposeDelegate.ComposeVersion.V2,
composeFiles,
identifier,
COMPOSE_EXECUTABLE,
DEFAULT_IMAGE_NAME
);
this.project = this.composeDelegate.getProject();
this(DEFAULT_IMAGE_NAME, identifier, composeFiles);
this.localCompose = true;
}

@Override
Expand Down Expand Up @@ -234,16 +299,6 @@ public ComposeContainer withEnv(Map<String, String> env) {
return this;
}

/**
* Use a local Docker Compose binary instead of a container.
*
* @return this instance, for chaining
*/
public ComposeContainer withLocalCompose(boolean localCompose) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this setter, localCompose is always true and could be inlined.

this.localCompose = localCompose;
return this;
}

/**
* Whether to pull images first.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -58,41 +59,114 @@ public class DockerComposeContainer<SELF extends DockerComposeContainer<SELF>> i

public static final String COMPOSE_EXECUTABLE = SystemUtils.IS_OS_WINDOWS ? "docker-compose.exe" : "docker-compose";

private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("docker/compose:1.29.2");

private final ComposeDelegate composeDelegate;

private String project;

private List<String> filesInDirectory = new ArrayList<>();

@Deprecated
/**
* Creates a new DockerComposeContainer using the specified Docker image and compose files.
*
* @param image The Docker image to use for the container
* @param composeFiles One or more Docker Compose configuration files
*/
public DockerComposeContainer(DockerImageName image, File... composeFiles) {
this(image, Arrays.asList(composeFiles));
}

/**
* Creates a new DockerComposeContainer using the specified Docker image and compose files.
*
* @param image The Docker image to use for the container
* @param composeFiles A list of Docker Compose configuration files
*/
public DockerComposeContainer(DockerImageName image, List<File> composeFiles) {
this(image, Base58.randomString(6).toLowerCase(), composeFiles);
}

/**
* Creates a new DockerComposeContainer with the specified Docker image, identifier, and compose files.
*
* @param image The Docker image to use for the container
* @param identifier A unique identifier for this compose environment
* @param composeFiles One or more Docker Compose configuration files
*/
public DockerComposeContainer(DockerImageName image, String identifier, File... composeFiles) {
this(image, identifier, Arrays.asList(composeFiles));
}

/**
* Creates a new DockerComposeContainer with the specified Docker image, identifier, and a single compose file.
*
* @param image The Docker image to use for the container
* @param identifier A unique identifier for this compose environment
* @param composeFile A Docker Compose configuration file
*/
public DockerComposeContainer(DockerImageName image, String identifier, File composeFile) {
this(image, identifier, Collections.singletonList(composeFile));
}

/**
* Creates a new DockerComposeContainer with the specified Docker image, identifier, and compose files.
*
* @param image The Docker image to use for the container
* @param identifier A unique identifier for this compose environment
* @param composeFiles A list of Docker Compose configuration files
*/
public DockerComposeContainer(DockerImageName image, String identifier, List<File> composeFiles) {
this.composeDelegate =
new ComposeDelegate(ComposeDelegate.ComposeVersion.V1, composeFiles, identifier, COMPOSE_EXECUTABLE, image);
this.project = this.composeDelegate.getProject();
}

/**
* Use the new constructor {@link #DockerComposeContainer(DockerImageName image, String identifier, File composeFile)}
*/
public DockerComposeContainer(File composeFile, String identifier) {
this(identifier, composeFile);
this.localCompose = true;
}

/**
* Use the new constructor {@link #DockerComposeContainer(DockerImageName image, List composeFiles)}
*/
public DockerComposeContainer(File... composeFiles) {
this(Arrays.asList(composeFiles));
this.localCompose = true;
}

/**
* Use the new constructor {@link #DockerComposeContainer(DockerImageName image, List composeFiles)}
*/
@Deprecated
public DockerComposeContainer(List<File> composeFiles) {
this(Base58.randomString(6).toLowerCase(), composeFiles);
this.localCompose = true;
}

/**
* Use the new constructor {@link #DockerComposeContainer(DockerImageName image, String identifier, File... composeFiles)}
*/
public DockerComposeContainer(String identifier, File... composeFiles) {
this(identifier, Arrays.asList(composeFiles));
this.localCompose = true;
}

/**
* Use the new constructor {@link #DockerComposeContainer(DockerImageName image, String identifier, List composeFiles)}
*/
public DockerComposeContainer(String identifier, List<File> composeFiles) {
this.composeDelegate =
new ComposeDelegate(
ComposeDelegate.ComposeVersion.V1,
composeFiles,
identifier,
COMPOSE_EXECUTABLE,
DEFAULT_IMAGE_NAME
DockerImageName.parse("docker/compose:1.29.2")
);
this.project = this.composeDelegate.getProject();
this.localCompose = true;
}

@Override
Expand Down Expand Up @@ -234,16 +308,6 @@ public SELF withEnv(Map<String, String> env) {
return self();
}

/**
* Use a local Docker Compose binary instead of a container.
*
* @return this instance, for chaining
*/
public SELF withLocalCompose(boolean localCompose) {
this.localCompose = localCompose;
return self();
}

/**
* Whether to pull images first.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.testcontainers.containers;

import org.junit.jupiter.api.Test;
import org.testcontainers.utility.DockerImageName;

import java.io.File;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;

class ComposeContainerTest {

public static final String DOCKER_IMAGE = "docker:25.0.2";

private static final String COMPOSE_FILE_PATH = "src/test/resources/v2-compose-test.yml";

@Test
void testWithCustomDockerImage() {
ComposeContainer composeContainer = new ComposeContainer(
DockerImageName.parse(DOCKER_IMAGE),
new File(COMPOSE_FILE_PATH)
);
composeContainer.start();
verifyContainerCreation(composeContainer);
composeContainer.stop();
}

@Test
void testWithCustomDockerImageAndIdentifier() {
ComposeContainer composeContainer = new ComposeContainer(
DockerImageName.parse(DOCKER_IMAGE),
"myidentifier",
new File(COMPOSE_FILE_PATH)
);
composeContainer.start();
verifyContainerCreation(composeContainer);
composeContainer.stop();
}

private void verifyContainerCreation(ComposeContainer composeContainer) {
Optional<ContainerState> redis = composeContainer.getContainerByServiceName("redis");
assertThat(redis)
.hasValueSatisfying(container -> {
assertThat(container.isRunning()).isTrue();
assertThat(container.getContainerInfo().getConfig().getLabels())
.containsEntry("com.docker.compose.version", "2.24.5");
});
}
}
Loading
Loading