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

Allow testcontainers to have custom labels #725

Merged
merged 6 commits into from
Jun 4, 2018
Merged
Show file tree
Hide file tree
Changes from 5 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
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,15 @@ 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> createCommandLabels = createCommand.getLabels();
createCommandLabels = new HashMap<>(createCommandLabels != null ? createCommandLabels : Collections.emptyMap());

Map<String, String> combinedLabels = new HashMap<>();
combinedLabels.putAll(labels);
combinedLabels.putAll(DockerClientFactory.DEFAULT_LABELS);
combinedLabels.putAll(createCommandLabels);
Copy link
Member

Choose a reason for hiding this comment

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

DEFAULT_LABELS must always override :)

Copy link
Member

Choose a reason for hiding this comment

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

Also, I would change to:

if (createCommand.getLabels() != null) {
    combinedLabels.putAll(createCommand.getLabels());
}

to avoid a variable

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So the order should be user defined labels < createCommandLabels < DEFAULT_LABELS?

Copy link
Member

Choose a reason for hiding this comment

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

Yes :) Sorry if I confused you about it before!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No worries ;)


createCommand.withLabels(combinedLabels);
}

private Set<Link> findLinksFromThisContainer(String alias, LinkableContainer linkableContainer) {
Expand Down Expand Up @@ -700,6 +708,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