Skip to content

Commit

Permalink
chore(citrus-testcontainers): Support generic container
Browse files Browse the repository at this point in the history
  • Loading branch information
christophd committed Nov 15, 2024
1 parent 2f9ed2d commit bc4f2aa
Show file tree
Hide file tree
Showing 9 changed files with 400 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.citrusframework.context.TestContext;
import org.citrusframework.spi.Resource;
import org.citrusframework.spi.Resources;
import org.citrusframework.testcontainers.TestContainersSettings;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.utility.MountableFile;

import static org.citrusframework.testcontainers.TestcontainersHelper.getEnvVarName;
import static org.citrusframework.testcontainers.actions.TestcontainersActionBuilder.testcontainers;
Expand Down Expand Up @@ -77,11 +82,17 @@ protected void exposeConnectionSettings(C container, TestContext context) {
dockerContainerName = dockerContainerName.substring(1);
}

String containerType = containerName.toUpperCase().replaceAll("-", "_").replaceAll("\\.", "_");
context.setVariable(getEnvVarName(containerType, "HOST"), container.getHost());
context.setVariable(getEnvVarName(containerType, "CONTAINER_IP"), container.getHost());
context.setVariable(getEnvVarName(containerType, "CONTAINER_ID"), dockerContainerId);
context.setVariable(getEnvVarName(containerType, "CONTAINER_NAME"), dockerContainerName);
if (containerName != null) {
String containerType = containerName.toUpperCase().replaceAll("-", "_").replaceAll("\\.", "_");
context.setVariable(getEnvVarName(containerType, "HOST"), container.getHost());
context.setVariable(getEnvVarName(containerType, "CONTAINER_IP"), container.getHost());
context.setVariable(getEnvVarName(containerType, "CONTAINER_ID"), dockerContainerId);
context.setVariable(getEnvVarName(containerType, "CONTAINER_NAME"), dockerContainerName);

if (!container.getExposedPorts().isEmpty()) {
context.setVariable(getEnvVarName(containerType, "PORT"), container.getFirstMappedPort());
}
}
}
}

Expand Down Expand Up @@ -110,6 +121,12 @@ public static abstract class AbstractBuilder<C extends GenericContainer<?>, T ex
protected C container;
protected Network network;
protected Duration startupTimeout = Duration.ofSeconds(TestContainersSettings.getStartupTimeout());

protected final Set<Integer> exposedPorts = new HashSet<>();
protected final List<String> portBindings = new ArrayList<>();

protected final Map<MountableFile, String> volumeMounts = new HashMap<>();

private boolean autoRemoveResources = TestContainersSettings.isAutoRemoveResources();

public B containerName(String name) {
Expand Down Expand Up @@ -193,6 +210,60 @@ public B autoRemove(boolean enabled) {
return self;
}

public B addExposedPort(int port) {
this.exposedPorts.add(port);
return self;
}

public B addExposedPorts(int... ports) {
for (int port : ports) {
addExposedPort(port);
}
return self;
}

public B addExposedPorts(List<Integer> ports) {
exposedPorts.addAll(ports);
return self;
}

public B addPortBinding(String binding) {
this.portBindings.add(binding);
return self;
}

public B addPortBindings(String... bindings) {
for (String binding : bindings) {
addPortBinding(binding);
}
return self;
}

public B addPortBindings(List<String> bindings) {
portBindings.addAll(bindings);
return self;
}

public B withVolumeMount(MountableFile mountableFile, String containerPath) {
this.volumeMounts.put(mountableFile, containerPath);
return self;
}

public B withVolumeMount(String mountableFile, String mountPath) {
return withVolumeMount(Resources.create(mountableFile), mountPath);
}

public B withVolumeMount(Resource mountableFile, String mountPath) {
if (mountableFile instanceof Resources.ClasspathResource) {
this.volumeMounts.put(MountableFile.forClasspathResource(mountableFile.getLocation()), mountPath);
} else if (mountableFile instanceof Resources.FileSystemResource) {
this.volumeMounts.put(MountableFile.forHostPath(mountableFile.getFile().getAbsolutePath()), mountPath);
} else {
this.volumeMounts.put(MountableFile.forHostPath(mountableFile.getLocation()), mountPath);
}
return self;
}

protected void prepareBuild() {
}

Expand All @@ -205,7 +276,11 @@ public T build() {

if (network != null) {
container.withNetwork(network);
container.withNetworkAliases(containerName);
if (serviceName != null) {
container.withNetworkAliases(serviceName);
} else if (containerName != null) {
container.withNetworkAliases(containerName);
}
}

container.withStartupTimeout(startupTimeout);
Expand All @@ -214,10 +289,24 @@ public T build() {
container.withLabels(labels);
container.withEnv(env);

exposedPorts.forEach(container::addExposedPort);
container.setPortBindings(portBindings);

volumeMounts.forEach((mountableFile, containerPath) ->
container.withCopyFileToContainer(mountableFile, containerPath));

if (!commandLine.isEmpty()) {
container.withCommand(commandLine.toArray(String[]::new));
}

if (containerName == null && image != null) {
if (image.contains(":")) {
containerName = image.split(":")[0];
} else {
containerName = image;
}
}

return doBuild();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ public static TestcontainersActionBuilder testcontainers() {
return new TestcontainersActionBuilder();
}

/**
* Manage generic testcontainers.
* @return
*/
public GenericContainerActionBuilder container() {
return new GenericContainerActionBuilder();
}

/**
* Manage LocalStack testcontainers.
* @return
Expand Down Expand Up @@ -100,6 +108,26 @@ public StopTestcontainersAction.Builder stop() {
return builder;
}

public class GenericContainerActionBuilder {
/**
* Start generic testcontainers instance.
*/
public StartTestcontainersAction.Builder<?> start() {
StartTestcontainersAction.Builder<?> builder = new StartTestcontainersAction.Builder<>();
delegate = builder;
return builder;
}

/**
* Stop generic testcontainers instance.
*/
public StopTestcontainersAction.Builder stop() {
StopTestcontainersAction.Builder builder = new StopTestcontainersAction.Builder();
delegate = builder;
return builder;
}
}

public class LocalStackActionBuilder {
/**
* Start LocalStack testcontainers instance.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,22 +187,34 @@ private void configureStartActionBuilder(StartTestcontainersAction.AbstractBuild
}

if (container.getEnvironmentVariables() != null) {
container.getEnvironmentVariables().getVariables().forEach(variable -> {
builder.withEnv(variable.getName(), variable.getValue());
});
container.getEnvironmentVariables().getVariables().forEach(variable -> builder.withEnv(variable.getName(), variable.getValue()));
}

if (container.getLabels() != null) {
container.getLabels().getLabels().forEach(label -> {
builder.withLabel(label.getName(), label.getValue());
});
container.getLabels().getLabels().forEach(label -> builder.withLabel(label.getName(), label.getValue()));
}

if (container.getExposedPorts() != null) {
container.getExposedPorts().getPorts().forEach(builder::addExposedPort);
}

if (container.getPortBindings() != null) {
container.getPortBindings().getBindings().forEach(builder::addPortBinding);
}

if (container.getVolumeMounts() != null) {
container.getVolumeMounts().getMounts().forEach(mount ->
builder.withVolumeMount(mount.getFile(), mount.getMountPath()));
}
}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"labels",
"environmentVariables",
"exposedPorts",
"portBindings",
"volumeMounts"
})
public static class Container {

Expand Down Expand Up @@ -230,6 +242,15 @@ public static class Container {
@XmlElement
protected Labels labels;

@XmlElement(name = "exposed-ports")
protected ExposedPorts exposedPorts;

@XmlElement(name = "port-bindings")
protected PortBindings portBindings;

@XmlElement(name = "volume-mounts")
protected VolumeMounts volumeMounts;

public String getName() {
return name;
}
Expand Down Expand Up @@ -293,6 +314,119 @@ public Labels getLabels() {
public void setLabels(Labels labels) {
this.labels = labels;
}

public ExposedPorts getExposedPorts() {
return exposedPorts;
}

public void setExposedPorts(ExposedPorts exposedPorts) {
this.exposedPorts = exposedPorts;
}

public PortBindings getPortBindings() {
return portBindings;
}

public void setPortBindings(PortBindings portBindings) {
this.portBindings = portBindings;
}

public VolumeMounts getVolumeMounts() {
return volumeMounts;
}

public void setVolumeMounts(VolumeMounts volumeMounts) {
this.volumeMounts = volumeMounts;
}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"mounts"
})
public static class VolumeMounts {

@XmlElement(name = "mount")
private List<Mount> mounts;

public List<Mount> getMounts() {
if (mounts == null) {
mounts = new ArrayList<>();
}
return mounts;
}

public void setMounts(List<Mount> mounts) {
this.mounts = mounts;
}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
public static class Mount {

@XmlAttribute(name = "file", required = true)
protected String file;
@XmlAttribute(name = "mount-path", required = true)
protected String mountPath;

public String getFile() {
return file;
}

public void setFile(String file) {
this.file = file;
}

public String getMountPath() {
return mountPath;
}

public void setMountPath(String mountPath) {
this.mountPath = mountPath;
}
}
}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"ports"
})
public static class ExposedPorts {

@XmlElement(name = "port")
private List<Integer> ports;

public List<Integer> getPorts() {
if (ports == null) {
ports = new ArrayList<>();
}
return ports;
}

public void setPorts(List<Integer> ports) {
this.ports = ports;
}
}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"bindings"
})
public static class PortBindings {

@XmlElement(name = "binding")
private List<String> bindings;

public List<String> getBindings() {
if (bindings == null) {
bindings = new ArrayList<>();
}
return bindings;
}

public void setBindings(List<String> bindings) {
this.bindings = bindings;
}
}
}

@XmlAccessorType(XmlAccessType.FIELD)
Expand Down
Loading

0 comments on commit bc4f2aa

Please sign in to comment.