Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
5065cc9
Initial ContainerDef
eddumelendez Jun 29, 2023
ab7f48a
Move PortForwardingContainer to use ContainerDef
eddumelendez Oct 23, 2023
6c6dfd2
Add mutate method
eddumelendez Oct 23, 2023
0f39f54
Move ContainerDef and polish code
eddumelendez Oct 23, 2023
00a53a6
Apply ContainerDef to MongoDBContainer
eddumelendez Oct 24, 2023
251c9d5
Fix test
eddumelendez Oct 24, 2023
745da74
Add createContainerDef and getContainerDef
eddumelendez Oct 24, 2023
af6e835
Fix test
eddumelendez Oct 24, 2023
7bf4e12
Polish
eddumelendez Oct 24, 2023
f9bca0d
Add waitStrategy to ContainerDef
eddumelendez Oct 25, 2023
7ccb450
Fix waitStrategy
eddumelendez Oct 25, 2023
402be60
configure
eddumelendez Oct 25, 2023
f226712
Exclude removed configure method
eddumelendez Oct 25, 2023
0f4f6ef
Add missing methods to avoid breaking compatibility
eddumelendez Oct 25, 2023
9ade249
Revert "Fix waitStrategy"
eddumelendez Oct 25, 2023
268c9ca
Revert "configure"
eddumelendez Oct 25, 2023
f4d7228
Restore waitStrategy to avoid breaking compatibility
eddumelendez Oct 25, 2023
d434594
Add default network alias to BrowserWebDriverContainer
eddumelendez Oct 25, 2023
93d5292
Restore default network alias
eddumelendez Oct 25, 2023
266b08f
Fix checkstyle
eddumelendez Oct 25, 2023
602fe12
Fix assertion
eddumelendez Oct 25, 2023
de23c6a
Merge branch 'main' into new-container-def-api
eddumelendez Oct 26, 2023
98517c0
Fix comments
eddumelendez Oct 26, 2023
f6501ab
Fix comment
eddumelendez Oct 26, 2023
f3d78c2
Use @Getter where is needed but not for collections
eddumelendez Oct 26, 2023
643ad4e
Given defense copy in collections, set bindings
eddumelendez Oct 26, 2023
4e38df9
Fix comments
eddumelendez Oct 27, 2023
7b6a8fb
Fix waitStrategy
eddumelendez Oct 27, 2023
e6559eb
Merge branch 'main' into new-container-def-api
eddumelendez Oct 27, 2023
92e41c7
Add missing methods
eddumelendez Oct 27, 2023
235e823
Polish MongoDBContainer
eddumelendez Oct 29, 2023
62f22ae
Fix comment
eddumelendez Oct 29, 2023
eb7ed91
Rollback change in neo4j test
eddumelendez Oct 31, 2023
273f950
rename method
eddumelendez Oct 31, 2023
8f55e1d
Switch networkAliases to LinkedHashSet
eddumelendez Oct 31, 2023
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
304 changes: 304 additions & 0 deletions core/src/main/java/org/testcontainers/containers/ContainerDef.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
package org.testcontainers.containers;

import com.github.dockerjava.api.command.CreateContainerCmd;
import com.github.dockerjava.api.model.Bind;
import com.github.dockerjava.api.model.ExposedPort;
import com.github.dockerjava.api.model.HostConfig;
import com.github.dockerjava.api.model.InternetProtocol;
import com.github.dockerjava.api.model.PortBinding;
import com.github.dockerjava.api.model.Ports;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.testcontainers.DockerClientFactory;
import org.testcontainers.UnstableAPI;
import org.testcontainers.containers.wait.strategy.WaitStrategy;
import org.testcontainers.images.RemoteDockerImage;
import org.testcontainers.utility.DockerImageName;
import org.testcontainers.utility.TestcontainersConfiguration;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

@UnstableAPI
@Slf4j
class ContainerDef {

@Getter
private RemoteDockerImage image;

Set<ExposedPort> exposedPorts = new HashSet<>();

Set<PortBinding> portBindings = new HashSet<>();

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

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

private String[] entrypoint;

private String[] command = new String[0];

@Getter
private Network network;

Set<String> networkAliases = new LinkedHashSet<>();

@Getter
private String networkMode;

List<Bind> binds = new ArrayList<>();

@Getter
private boolean privilegedMode;

@Getter
private WaitStrategy waitStrategy = GenericContainer.DEFAULT_WAIT_STRATEGY;

public ContainerDef() {}

protected void applyTo(CreateContainerCmd createCommand) {
HostConfig hostConfig = createCommand.getHostConfig();
if (hostConfig == null) {
hostConfig = new HostConfig();
createCommand.withHostConfig(hostConfig);
}
// PortBindings must contain:
// * all exposed ports with a randomized host port (equivalent to -p CONTAINER_PORT)
// * all exposed ports with a fixed host port (equivalent to -p HOST_PORT:CONTAINER_PORT)
Map<ExposedPort, PortBinding> allPortBindings = new HashMap<>();
// First, collect all the randomized host ports from our 'exposedPorts' field
for (ExposedPort exposedPort : this.exposedPorts) {
allPortBindings.put(exposedPort, new PortBinding(Ports.Binding.empty(), exposedPort));
}
// Next, collect all the fixed host ports from our 'portBindings' field, overwriting any randomized ports so that
// we don't create two bindings for the same container port.
for (PortBinding portBinding : this.portBindings) {
allPortBindings.put(portBinding.getExposedPort(), portBinding);
}
hostConfig.withPortBindings(new ArrayList<>(allPortBindings.values()));

// Next, ExposedPorts must be set up to publish all of the above ports, both randomized and fixed.
createCommand.withExposedPorts(new ArrayList<>(allPortBindings.keySet()));

createCommand.withEnv(
this.envVars.entrySet()
.stream()
.filter(it -> it.getValue() != null)
.map(it -> it.getKey() + "=" + it.getValue())
.toArray(String[]::new)
);

if (this.entrypoint != null) {
createCommand.withEntrypoint(this.entrypoint);
}

if (this.command != null) {
createCommand.withCmd(this.command);
}

if (this.network != null) {
hostConfig.withNetworkMode(this.network.getId());
createCommand.withAliases(this.networkAliases.toArray(new String[0]));
} else {
if (this.networkMode != null) {
createCommand.getHostConfig().withNetworkMode(this.networkMode);
}
}

boolean shouldCheckFileMountingSupport =
this.binds.size() > 0 && !TestcontainersConfiguration.getInstance().isDisableChecks();
if (shouldCheckFileMountingSupport) {
if (!DockerClientFactory.instance().isFileMountingSupported()) {
log.warn(
"Unable to mount a file from test host into a running container. " +
"This may be a misconfiguration or limitation of your Docker environment. " +
"Some features might not work."
);
}
}

hostConfig.withBinds(this.binds.toArray(new Bind[0]));

if (this.privilegedMode) {
createCommand.getHostConfig().withPrivileged(this.privilegedMode);
}

Map<String, String> combinedLabels = new HashMap<>(this.labels);
if (createCommand.getLabels() != null) {
combinedLabels.putAll(createCommand.getLabels());
}

createCommand.withLabels(combinedLabels);
}

protected void setImage(RemoteDockerImage image) {
this.image = image;
}

protected void setImage(String image) {
setImage(DockerImageName.parse(image));
}

protected void setImage(DockerImageName image) {
setImage(new RemoteDockerImage(image));
}

public Set<ExposedPort> getExposedPorts() {
return new HashSet<>(this.exposedPorts);
}

protected void setExposedPorts(Set<ExposedPort> exposedPorts) {
this.exposedPorts.clear();
this.exposedPorts.addAll(exposedPorts);
}

protected void addExposedPorts(ExposedPort... exposedPorts) {
this.exposedPorts.addAll(Arrays.asList(exposedPorts));
}

protected void addExposedPort(ExposedPort exposedPort) {
this.exposedPorts.add(exposedPort);
}

protected void setExposedTcpPorts(Set<Integer> ports) {
this.exposedPorts.clear();
ports.forEach(port -> this.exposedPorts.add(ExposedPort.tcp(port)));
}

protected void addExposedTcpPorts(int... ports) {
for (int port : ports) {
this.exposedPorts.add(ExposedPort.tcp(port));
}
}

protected void addExposedTcpPort(int port) {
this.exposedPorts.add(ExposedPort.tcp(port));
}

protected void addExposedPort(int port, InternetProtocol protocol) {
this.exposedPorts.add(new ExposedPort(port, protocol));
}

public Set<PortBinding> getPortBindings() {
return new HashSet<>(this.portBindings);
}

protected void setPortBindings(Set<PortBinding> portBindings) {
this.portBindings.clear();
this.portBindings.addAll(portBindings);
}

protected void addPortBindings(PortBinding... portBindings) {
this.portBindings.addAll(Arrays.asList(portBindings));
}

protected void addPortBinding(PortBinding portBinding) {
this.portBindings.add(portBinding);
}

public Map<String, String> getLabels() {
return new HashMap<>(this.labels);
}

protected void setLabels(Map<String, String> labels) {
this.labels.clear();
this.labels.putAll(labels);
}

protected void addLabels(Map<String, String> labels) {
this.labels.putAll(labels);
}

protected void addLabel(String key, String value) {
this.labels.put(key, value);
}

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

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

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

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

public String[] getEntrypoint() {
return Arrays.copyOf(this.entrypoint, this.entrypoint.length);
}

protected void setEntrypoint(String... entrypoint) {
this.entrypoint = entrypoint;
}

public String[] getCommand() {
return Arrays.copyOf(this.command, this.command.length);
}

protected void setCommand(String... command) {
this.command = command;
}

protected void setNetwork(Network network) {
this.network = network;
}

public Set<String> getNetworkAliases() {
return new LinkedHashSet<>(this.networkAliases);
}

protected void setNetworkAliases(Set<String> aliases) {
this.networkAliases.clear();
this.networkAliases.addAll(aliases);
}

protected void addNetworkAliases(String... aliases) {
this.networkAliases.addAll(Arrays.asList(aliases));
}

protected void addNetworkAlias(String alias) {
this.networkAliases.add(alias);
}

protected void setNetworkMode(String networkMode) {
this.networkMode = networkMode;
}

protected void setPrivilegedMode(boolean privilegedMode) {
this.privilegedMode = privilegedMode;
}

public List<Bind> getBinds() {
return new ArrayList<>(this.binds);
}

protected void setBinds(List<Bind> binds) {
this.binds.clear();
this.binds.addAll(binds);
}

protected void addBinds(Bind... binds) {
this.binds.addAll(Arrays.asList(binds));
}

protected void addBind(Bind bind) {
this.binds.add(bind);
}

protected void setWaitStrategy(WaitStrategy waitStrategy) {
this.waitStrategy = waitStrategy;
}
}
Loading