Skip to content

Commit

Permalink
Add support for container labels (#725)
Browse files Browse the repository at this point in the history
Adds additional builder methods for defining container labels.
  • Loading branch information
mgansler authored and kiview committed Jun 4, 2018
1 parent db02d79 commit a2c0981
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 6 deletions.
16 changes: 16 additions & 0 deletions core/src/main/java/org/testcontainers/containers/Container.java
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,22 @@ default SELF withEnv(String key, Function<Optional<String>, String> mapper) {
*/
SELF withEnv(Map<String, String> env);

/**
* Add a label to the container.
*
* @param key label key
* @param value label value
* @return this
*/
SELF withLabel(String key, String value);

/**
* Add labels to the container.
* @param labels map of labels
* @return this
*/
SELF withLabels(Map<String, String> labels);

/**
* Set the command that should be run in the container
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ public class GenericContainer<SELF extends GenericContainer<SELF>>
@NonNull
private Map<String, String> env = new HashMap<>();

@NonNull
private Map<String, String> labels = new HashMap<>();

@NonNull
private String[] commandParts = new String[0];

Expand Down Expand Up @@ -470,10 +473,14 @@ private void applyConfiguration(CreateContainerCmd createCommand) {

createContainerCmdModifiers.forEach(hook -> hook.accept(createCommand));

Map<String, String> labels = createCommand.getLabels();
labels = new HashMap<>(labels != null ? labels : Collections.emptyMap());
labels.putAll(DockerClientFactory.DEFAULT_LABELS);
createCommand.withLabels(labels);
Map<String, String> combinedLabels = new HashMap<>();
combinedLabels.putAll(labels);
if (createCommand.getLabels() != null) {
combinedLabels.putAll(createCommand.getLabels());
}
combinedLabels.putAll(DockerClientFactory.DEFAULT_LABELS);

createCommand.withLabels(combinedLabels);
}

private Set<Link> findLinksFromThisContainer(String alias, LinkableContainer linkableContainer) {
Expand Down Expand Up @@ -700,6 +707,27 @@ public SELF withEnv(Map<String, String> env) {
return self();
}

/**
* {@inheritDoc}
*/
@Override
public SELF withLabel(String key, String value) {
if (key.startsWith("org.testcontainers")) {
throw new IllegalArgumentException("The org.testcontainers namespace is reserved for interal use");
}
labels.put(key, value);
return self();
}

/**
* {@inheritDoc}
*/
@Override
public SELF withLabels(Map<String, String> labels) {
labels.forEach(this::withLabel);
return self();
}

/**
* {@inheritDoc}
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.net.Socket;
import java.time.Duration;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher;
Expand Down Expand Up @@ -220,6 +221,32 @@ public void environmentFromMapTest() throws IOException {
assertEquals("Environment variables can be passed into a command from a map", "42 and 50", line);
}

@Test
public void customLabelTest() {
try (final GenericContainer alpineCustomLabel = new GenericContainer("alpine:3.2")
.withLabel("our.custom", "label")
.withCommand("top")) {

alpineCustomLabel.start();

Map<String, String> labels = alpineCustomLabel.getCurrentContainerInfo().getConfig().getLabels();
assertTrue("org.testcontainers label is present", labels.containsKey("org.testcontainers"));
assertTrue("our.custom label is present", labels.containsKey("our.custom"));
assertEquals("our.custom label value is label", labels.get("our.custom"), "label");
}
}

@Test
public void exceptionThrownWhenTryingToOverrideTestcontainersLabels() {
assertThrows("When trying to overwrite an 'org.testcontainers' label, withLabel() throws an exception",
IllegalArgumentException.class,
() -> {
new GenericContainer("alpine:3.2")
.withLabel("org.testcontainers.foo", "false");
}
);
}

@Test
public void customClasspathResourceMappingTest() throws IOException {
// Note: This functionality doesn't work if you are running your build inside a Docker container;
Expand Down Expand Up @@ -341,7 +368,7 @@ public void copyToContainerTest() throws Exception {

try (final GenericContainer alpineCopyToContainer = new GenericContainer("alpine:3.2")
.withCommand("top")){

alpineCopyToContainer.start();
final MountableFile mountableFile = MountableFile.forClasspathResource("test_copy_to_container.txt");
alpineCopyToContainer.copyFileToContainer(mountableFile, "/home/");
Expand Down
2 changes: 1 addition & 1 deletion docs/usage/generic_containers.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,4 @@ The class rule provides methods for discovering how your tests can interact with
For example, with the Redis example above, the following will allow your tests to access the Redis service:
```java
String redisUrl = redis.getContainerIpAddress() + ":" + redis.getMappedPort(6379);
```
```
8 changes: 8 additions & 0 deletions docs/usage/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ new GenericContainer(...)
.withEnv("API_TOKEN", "foo")
```

### Labels

To add a custom label to the container, use `withLabel`:
```java
new GenericContainer(...)
.withLabel("your.custom", "label")
```

### Command

By default the container will execute whatever command is specified in the image's Dockerfile. To override this, and specify a different command, use `withCommand`:
Expand Down

0 comments on commit a2c0981

Please sign in to comment.