Skip to content

Commit

Permalink
Add interface to customize CreateContainerCmd via SPI
Browse files Browse the repository at this point in the history
Add `CreateContainerCmdCustomizer` interface to customize
`CreateContainerCmd`. Customization is applied after Testcontainers
configuration is set.
  • Loading branch information
eddumelendez committed Aug 17, 2023
1 parent 5e88c3d commit 31293c2
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.containers.wait.strategy.WaitStrategy;
import org.testcontainers.containers.wait.strategy.WaitStrategyTarget;
import org.testcontainers.core.CreateContainerCmdCustomizer;
import org.testcontainers.images.ImagePullPolicy;
import org.testcontainers.images.RemoteDockerImage;
import org.testcontainers.images.builder.Transferable;
Expand Down Expand Up @@ -88,6 +89,7 @@
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
Expand Down Expand Up @@ -238,6 +240,10 @@ public class GenericContainer<SELF extends GenericContainer<SELF>>

private boolean hostAccessible = false;

private final ServiceLoader<CreateContainerCmdCustomizer> createContainerCustomizers = ServiceLoader.load(
CreateContainerCmdCustomizer.class
);

public GenericContainer(@NonNull final DockerImageName dockerImageName) {
this.image = new RemoteDockerImage(dockerImageName);
}
Expand Down Expand Up @@ -377,6 +383,8 @@ private void tryStart(Instant startedAt) {
CreateContainerCmd createCommand = dockerClient.createContainerCmd(dockerImageName);
applyConfiguration(createCommand);

customizeCreateContainerCmd(createCommand);

createCommand.getLabels().putAll(DockerClientFactory.DEFAULT_LABELS);

boolean reused = false;
Expand Down Expand Up @@ -554,6 +562,10 @@ private void tryStart(Instant startedAt) {
}
}

private void customizeCreateContainerCmd(CreateContainerCmd createCommand) {
this.createContainerCustomizers.forEach(customizer -> customizer.customize(createCommand));
}

@VisibleForTesting
Checksum hashCopiedFiles() {
Checksum checksum = new Adler32();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.testcontainers.core;

import com.github.dockerjava.api.command.CreateContainerCmd;

/**
* Callback interface that can be used to customize a {@link CreateContainerCmd}.
*/
public interface CreateContainerCmdCustomizer {
/**
* Callback to customize a {@link CreateContainerCmd} instance.
* @param createContainerCmd the create command to customize
*/
void customize(CreateContainerCmd createContainerCmd);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.testcontainers.custom;

import com.github.dockerjava.api.command.CreateContainerCmd;
import org.testcontainers.core.CreateContainerCmdCustomizer;

public class TestCreateContainerCmdCustomizer implements CreateContainerCmdCustomizer {

@Override
public void customize(CreateContainerCmd createContainerCmd) {
createContainerCmd.getLabels().put("project", "testcontainers-java");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,9 @@ public void customLabelTest() {
.containsKey("org.testcontainers.version");
assertThat(labels).as("our.custom label is present").containsKey("our.custom");
assertThat(labels).as("our.custom label value is label").containsEntry("our.custom", "label");
assertThat(labels)
.as("project label value is testcontainers-java")
.containsEntry("project", "testcontainers-java");
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.testcontainers.custom.TestCreateContainerCmdCustomizer
16 changes: 16 additions & 0 deletions docs/features/advanced_options.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ It is possible to specify an Image Pull Policy to determine at runtime whether a

## Customizing the container

### Using docker-java

It is possible to use the [`docker-java`](https://github.com/docker-java/docker-java) API directly to customize containers before creation. This is useful if there is a need to use advanced Docker features that are not exposed by the Testcontainers API. Any customizations you make using `withCreateContainerCmdModifier` will be applied _on top_ of the container definition that Testcontainers creates, but before it is created.

For example, this can be used to change the container hostname:
Expand All @@ -53,6 +55,20 @@ For example, this can be used to change the container hostname:

For what is possible, consult the [`docker-java CreateContainerCmd` source code](https://github.com/docker-java/docker-java/blob/3.2.1/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateContainerCmd.java).

### Using CreateContainerCmdCustomizer

Testcontainers provides a `CreateContainerCmdCustomizer` to customize [`docker-java CreateContainerCmd`](https://github.com/docker-java/docker-java/blob/3.2.1/docker-java-api/src/main/java/com/github/dockerjava/api/command/CreateContainerCmd.java)
via Service Provider Interface (SPI) mechanism.

<!--codeinclude-->
[CreateContainerCmd example implementation](../../core/src/test/java/org/testcontainers/custom/TestCreateContainerCmdCustomizer.java)
<!--/codeinclude-->

The previous implementation should be registered in `META-INF/services/org.testcontainers.core.CreateContainerCmdCustomizer` file.

!!! warning
`CreateContainerCmdCustomizer` implementation will apply to all containers created by Testcontainers.

## Parallel Container Startup

Usually, containers are started sequentially when more than one container is used.
Expand Down

0 comments on commit 31293c2

Please sign in to comment.