Skip to content
Closed
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 @@ -21,6 +21,7 @@
import java.util.concurrent.Future;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

public interface Container<SELF extends Container<SELF>> extends LinkableContainer, ContainerState {
/**
Expand Down Expand Up @@ -212,7 +213,7 @@ default SELF withFileSystemBind(String hostPath, String containerPath) {
* @return this
*/
default SELF withEnv(String key, Function<Optional<String>, String> mapper) {
Optional<String> oldValue = Optional.ofNullable(getEnvMap().get(key));
Optional<String> oldValue = Optional.ofNullable(getEnvMap().get(key).get());
return withEnv(key, mapper.apply(oldValue));
}

Expand Down Expand Up @@ -447,7 +448,7 @@ default void followOutput(Consumer<OutputFrame> consumer, OutputFrame.OutputType
@Deprecated
List<String> getEnv();

Map<String, String> getEnvMap();
Map<String, Supplier<String>> getEnvMap();

String[] getCommandParts();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;

@UnstableAPI
@Slf4j
Expand All @@ -38,7 +39,7 @@ class ContainerDef {

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

Map<String, String> envVars = new HashMap<>();
Map<String, Supplier<String>> envVars = new HashMap<>();

private String[] entrypoint;

Expand Down Expand Up @@ -89,8 +90,8 @@ protected void applyTo(CreateContainerCmd createCommand) {
createCommand.withEnv(
this.envVars.entrySet()
.stream()
.filter(it -> it.getValue() != null)
.map(it -> it.getKey() + "=" + it.getValue())
.filter(it -> it.getValue() != null && it.getValue().get() != null)
.map(it -> it.getKey() + "=" + it.getValue().get())
.toArray(String[]::new)
);

Expand Down Expand Up @@ -219,21 +220,30 @@ protected void addLabel(String key, String value) {
this.labels.put(key, value);
}

public Map<String, String> getEnvVars() {
public Map<String, Supplier<String>> getEnvVars() {
return new HashMap<>(this.envVars);
}

protected void setEnvVars(Map<String, String> envVars) {
protected void setEnvVars(Map<String, Supplier<String>> envVars) {
this.envVars.clear();
this.envVars.putAll(envVars);
}

protected void addEnvVars(Map<String, String> envVars) {
this.envVars.putAll(envVars);
this.envVars.putAll(
envVars
.entrySet()
.stream()
.collect(
HashMap::new,
(map, entry) -> map.put(entry.getKey(), () -> entry.getValue()),
HashMap::putAll
)
);
}

protected void addEnvVar(String key, String value) {
this.envVars.put(key, value);
this.envVars.put(key, () -> value);
}

public String[] getEntrypoint() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.Adler32;
Expand Down Expand Up @@ -953,7 +954,7 @@ public void setCommand(@NonNull String... commandParts) {
}

@Override
public Map<String, String> getEnvMap() {
public Map<String, Supplier<String>> getEnvMap() {
return this.containerDef.envVars;
}

Expand All @@ -965,14 +966,14 @@ public List<String> getEnv() {
return this.containerDef.getEnvVars()
.entrySet()
.stream()
.map(it -> it.getKey() + "=" + it.getValue())
.map(it -> it.getKey() + "=" + it.getValue().get())
.collect(Collectors.toList());
}

@Override
public void setEnv(List<String> env) {
this.containerDef.setEnvVars(
env.stream().map(it -> it.split("=")).collect(Collectors.toMap(it -> it[0], it -> it[1]))
env.stream().map(it -> it.split("=")).collect(Collectors.toMap(it -> it[0], it -> () -> it[1]))
);
}

Expand Down Expand Up @@ -1147,12 +1148,17 @@ protected void addFixedExposedPort(int hostPort, int containerPort, InternetProt
this.containerDef.addPortBindings(portBinding);
}

public SELF withEnv(String key, Supplier<String> value) {
getEnvMap().put(key, value);
return self();
}

/**
* {@inheritDoc}
*/
@Override
public SELF withEnv(String key, String value) {
this.addEnv(key, value);
getEnvMap().put(key, () -> value);
return self();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ public String getBrokerUrl() {
}

public String getUser() {
return getEnvMap().get("ARTEMIS_USER");
return getEnvMap().get("ARTEMIS_USER").get();
}

public String getPassword() {
return getEnvMap().get("ARTEMIS_PASSWORD");
return getEnvMap().get("ARTEMIS_PASSWORD").get();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ public InetSocketAddress getContactPoint() {
* @return The configured local Datacenter name.
*/
public String getLocalDatacenter() {
return getEnvMap().getOrDefault("CASSANDRA_DC", DEFAULT_LOCAL_DATACENTER);
return getEnvMap().getOrDefault("CASSANDRA_DC", () -> DEFAULT_LOCAL_DATACENTER).get();
}

@Deprecated
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package org.testcontainers.junit.jupiter;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer;

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

@Testcontainers
public class ThrowOnContainerDependencyReadingContainerValueBeforeContainerStart {

private static final String FIRST_DEPENDENCY_ENV_KEY = "first_dependency";

private static final String SECOND_DEPENDENCY_ENV_KEY = "second_dependency";

// @Container - not applicable in this case. Manual container management is required
private static final GenericContainer<?> FIRST_CONTAINER = new GenericContainer<>(
JUnitJupiterTestImages.HTTPD_IMAGE
)
.withExposedPorts(80);

// @Container - not applicable in this case. Manual container management is required
private static final GenericContainer<?> SECOND_CONTAINER = new GenericContainer<>(
JUnitJupiterTestImages.HTTPD_IMAGE
)
.withExposedPorts(80);

// @Container - not applicable in this case. Manual container management is required
private static final GenericContainer<?> APP_CONTAINER = new GenericContainer<>(JUnitJupiterTestImages.HTTPD_IMAGE)
.dependsOn(FIRST_CONTAINER, SECOND_CONTAINER)
// .withEnv can not use getFirstMappedPort() call here because FIRST_CONTAINER is not started yet
.withExposedPorts(80);

@BeforeAll
public static void setupWithException() {
assertThatThrownBy(() -> {
/*
* Sequence of expressions are substitute when using @Container annotation:
* @Container GenericContainer<?> FIRST_CONTAINER
* @Container GenericContainer<?> SECOND_CONTAINER
* @Container GenericContainer<?> APP_CONTAINER
* APP_CONTAINER.withEnv(FIRST_DEPENDENCY_ENV_KEY, String.valueOf(FIRST_CONTAINER.getFirstMappedPort()))
* APP_CONTAINER.withEnv(SECOND_DEPENDENCY_ENV_KEY, String.valueOf(SECOND_CONTAINER.getFirstMappedPort()))
*/
// reading values from not started containers
APP_CONTAINER
.withEnv(FIRST_DEPENDENCY_ENV_KEY, String.valueOf(FIRST_CONTAINER.getFirstMappedPort()))
.withEnv(SECOND_DEPENDENCY_ENV_KEY, String.valueOf(SECOND_CONTAINER.getFirstMappedPort()));

FIRST_CONTAINER.start();
SECOND_CONTAINER.start();
APP_CONTAINER.start();
})
.isInstanceOf(IllegalStateException.class)
.hasMessageContaining("Mapped port can only be obtained after the container is started");
}

@Test
public void throw_on_container_dependency_reading_container_value_before_container_start() {
// noop
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.testcontainers.junit.jupiter;

import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer;

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

@Testcontainers
public class WithEnvAsStringSupplierDependsOnValueFromAnotherContainer {

private static final String FIRST_DEPENDENCY_ENV_KEY = "first_dependency";

private static final String SECOND_DEPENDENCY_ENV_KEY = "second_dependency";

@Container
private static final GenericContainer<?> FIRST_CONTAINER = new GenericContainer<>(
JUnitJupiterTestImages.HTTPD_IMAGE
)
.withExposedPorts(80);

@Container
private static final GenericContainer<?> SECOND_CONTAINER = new GenericContainer<>(
JUnitJupiterTestImages.HTTPD_IMAGE
)
.withExposedPorts(80);

@Container
private static final GenericContainer<?> APP_CONTAINER = new GenericContainer<>(JUnitJupiterTestImages.HTTPD_IMAGE)
.dependsOn(FIRST_CONTAINER, SECOND_CONTAINER)
.withEnv(FIRST_DEPENDENCY_ENV_KEY, () -> String.valueOf(FIRST_CONTAINER.getFirstMappedPort()))
.withEnv(SECOND_DEPENDENCY_ENV_KEY, () -> String.valueOf(SECOND_CONTAINER.getFirstMappedPort()))
.withExposedPorts(80);

@Test
public void smokeTest() {
assertThat(FIRST_CONTAINER.isRunning()).isTrue();
assertThat(SECOND_CONTAINER.isRunning()).isTrue();
assertThat(APP_CONTAINER.isRunning()).isTrue();

assertThat(getDependencyEnvOfMappedPort(FIRST_DEPENDENCY_ENV_KEY))
.isEqualTo(String.valueOf(FIRST_CONTAINER.getFirstMappedPort()));
assertThat(getDependencyEnvOfMappedPort(SECOND_DEPENDENCY_ENV_KEY))
.isEqualTo(String.valueOf(SECOND_CONTAINER.getFirstMappedPort()));
}

private static String getDependencyEnvOfMappedPort(String dependencyEnvKey) {
return APP_CONTAINER
.getEnvMap()
.entrySet()
.stream()
.filter(e -> e.getKey().startsWith(dependencyEnvKey))
.map(e -> e.getValue().get())
.findFirst()
.orElse(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ protected String commandZookeeper() {
* <li>{@code container.getHost():container.getMappedPort(9093)}</li>
* <li>{@code container.getConfig().getHostName():9092}</li>
* </ul>
*
* @param listenerSupplier a supplier that will provide a listener
* @return this {@link KafkaContainer} instance
*/
Expand Down Expand Up @@ -275,10 +276,10 @@ private static class KafkaContainerDef extends ContainerDef {

private void resolveListeners() {
Set<String> listeners = Arrays
.stream(this.envVars.get("KAFKA_LISTENERS").split(","))
.stream(this.envVars.get("KAFKA_LISTENERS").get().split(","))
.collect(Collectors.toSet());
Set<String> listenerSecurityProtocolMap = Arrays
.stream(this.envVars.get("KAFKA_LISTENER_SECURITY_PROTOCOL_MAP").split(","))
.stream(this.envVars.get("KAFKA_LISTENER_SECURITY_PROTOCOL_MAP").get().split(","))
.collect(Collectors.toSet());

List<Supplier<String>> listenersToTransform = new ArrayList<>(this.listeners);
Expand All @@ -299,8 +300,8 @@ private void resolveListeners() {
String kafkaListeners = String.join(",", listeners);
String kafkaListenerSecurityProtocolMap = String.join(",", listenerSecurityProtocolMap);

this.envVars.put("KAFKA_LISTENERS", kafkaListeners);
this.envVars.put("KAFKA_LISTENER_SECURITY_PROTOCOL_MAP", kafkaListenerSecurityProtocolMap);
this.envVars.put("KAFKA_LISTENERS", () -> kafkaListeners);
this.envVars.put("KAFKA_LISTENER_SECURITY_PROTOCOL_MAP", () -> kafkaListenerSecurityProtocolMap);
}

void withListener(Supplier<String> listenerSupplier) {
Expand All @@ -321,7 +322,7 @@ void withClusterId(String clusterId) {
}

void withRaft() {
this.envVars.computeIfAbsent("CLUSTER_ID", key -> clusterId);
this.envVars.computeIfAbsent("CLUSTER_ID", key -> () -> clusterId);
this.envVars.computeIfAbsent("KAFKA_NODE_ID", key -> getEnvVars().get("KAFKA_BROKER_ID"));
addEnvVar("KAFKA_LISTENER_SECURITY_PROTOCOL_MAP", kafkaListenerSecurityProtocolMap());
addEnvVar("KAFKA_LISTENERS", kafkaListeners());
Expand All @@ -334,14 +335,18 @@ void withRaft() {
getEnvVars().get("KAFKA_NODE_ID"),
networkAlias
);
this.envVars.computeIfAbsent("KAFKA_CONTROLLER_QUORUM_VOTERS", key -> controllerQuorumVoters);
this.envVars.computeIfAbsent("KAFKA_CONTROLLER_QUORUM_VOTERS", key -> () -> controllerQuorumVoters);
addEnvVar("KAFKA_CONTROLLER_LISTENER_NAMES", "CONTROLLER");

setWaitStrategy(Wait.forLogMessage(".*Transitioning from RECOVERY to RUNNING.*", 1));
}

private String kafkaListenerSecurityProtocolMap() {
String kafkaListenerSecurityProtocolMapEnvVar = getEnvVars().get("KAFKA_LISTENER_SECURITY_PROTOCOL_MAP");
Supplier<String> kafkaListenerSecurityProtocolMapEnvVarSupplier = getEnvVars()
.get("KAFKA_LISTENER_SECURITY_PROTOCOL_MAP");
String kafkaListenerSecurityProtocolMapEnvVar = kafkaListenerSecurityProtocolMapEnvVarSupplier == null
? null
: kafkaListenerSecurityProtocolMapEnvVarSupplier.get();
String kafkaListenerSecurityProtocolMap = String.format(
"%s,CONTROLLER:PLAINTEXT",
kafkaListenerSecurityProtocolMapEnvVar
Expand All @@ -353,7 +358,10 @@ private String kafkaListenerSecurityProtocolMap() {
}

private String kafkaListeners() {
String kafkaListenersEnvVar = getEnvVars().get("KAFKA_LISTENERS");
Supplier<String> kafkaListenersEnvVarSupplier = getEnvVars().get("KAFKA_LISTENERS");
String kafkaListenersEnvVar = kafkaListenersEnvVarSupplier == null
? null
: kafkaListenersEnvVarSupplier.get();
String kafkaListeners = String.format("%s,CONTROLLER://0.0.0.0:9094", kafkaListenersEnvVar);
Set<String> listeners = new HashSet<>(Arrays.asList(kafkaListeners.split(",")));
return String.join(",", listeners);
Expand Down
Loading