-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support for WaitStrategy on DockerComposeContainer - alternative appr…
…oach (#600) * Support for WaitStrategy on DockerComposeContainer As discussed in #174 * CI code quality fixes * CI code quality fixes * Another attempt at adding WaitStrategy support for docker-compose * Another attempt at adding WaitStrategy support for docker-compose fixed some tests and added some files missed from previous commit * Changes after code review comments Added new WaitStrategyTarget interface, plus moved some methods into new LogFollower and CommandExecutor interfaces * Changes after code review comments Removed CommandExecutor and LogFollower interfaces. Added ExecInContainerPattern utility class. Changed existing WaitStrategy implementations to inherit from new ones * CI code quality fixes * Changes from code review. Moved getMappedPort to default implementation in ContainerState. Using proxyContainer in ComposeStrategyWaitServiceTarget to get ip. Removed unnecessary null checks. Using lazy getter for containerInfo in ComposeStrategyWaitServiceTarget. * Changes from code review. Removed getLogger() method. Removed getContainerName from Container and ContainerState. Removed getExposedPortNumbers from ContainerState. Added waitingFor method to DockerComposeContainer. Removed StartupTimeout interface.
- Loading branch information
1 parent
c2116ca
commit 8558203
Showing
33 changed files
with
1,203 additions
and
472 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
68 changes: 68 additions & 0 deletions
68
core/src/main/java/org/testcontainers/containers/ComposeServiceWaitStrategyTarget.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package org.testcontainers.containers; | ||
|
||
import com.github.dockerjava.api.command.InspectContainerResponse; | ||
import com.github.dockerjava.api.model.Container; | ||
import lombok.EqualsAndHashCode; | ||
import lombok.Getter; | ||
import lombok.NonNull; | ||
import org.testcontainers.DockerClientFactory; | ||
import org.testcontainers.containers.wait.strategy.WaitStrategyTarget; | ||
|
||
import java.util.ArrayList; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
|
||
/** | ||
* Class to provide a wait strategy target for services started through docker-compose | ||
*/ | ||
@EqualsAndHashCode | ||
class ComposeServiceWaitStrategyTarget implements WaitStrategyTarget { | ||
|
||
private final Container container; | ||
private final GenericContainer proxyContainer; | ||
@NonNull | ||
private Map<Integer, Integer> mappedPorts; | ||
@Getter(lazy=true) | ||
private final InspectContainerResponse containerInfo = DockerClientFactory.instance().client().inspectContainerCmd(getContainerId()).exec(); | ||
|
||
ComposeServiceWaitStrategyTarget(Container container, GenericContainer proxyContainer, | ||
@NonNull Map<Integer, Integer> mappedPorts) { | ||
this.container = container; | ||
this.proxyContainer = proxyContainer; | ||
this.mappedPorts = new HashMap<>(mappedPorts); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public List<Integer> getExposedPorts() { | ||
return new ArrayList<>(this.mappedPorts.keySet()); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public Integer getMappedPort(int originalPort) { | ||
return this.proxyContainer.getMappedPort(this.mappedPorts.get(originalPort)); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public String getContainerIpAddress() { | ||
return proxyContainer.getContainerIpAddress(); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public String getContainerId() { | ||
return this.container.getId(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
114 changes: 114 additions & 0 deletions
114
core/src/main/java/org/testcontainers/containers/ContainerState.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package org.testcontainers.containers; | ||
|
||
import com.github.dockerjava.api.command.InspectContainerResponse; | ||
import com.github.dockerjava.api.exception.DockerException; | ||
import com.github.dockerjava.api.model.ExposedPort; | ||
import com.github.dockerjava.api.model.PortBinding; | ||
import com.github.dockerjava.api.model.Ports; | ||
import com.google.common.base.Preconditions; | ||
import org.testcontainers.DockerClientFactory; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.stream.Collectors; | ||
|
||
public interface ContainerState { | ||
|
||
/** | ||
* Get the IP address that this container may be reached on (may not be the local machine). | ||
* | ||
* @return an IP address | ||
*/ | ||
default String getContainerIpAddress() { | ||
return DockerClientFactory.instance().dockerHostIpAddress(); | ||
} | ||
|
||
/** | ||
* @return is the container currently running? | ||
*/ | ||
default Boolean isRunning() { | ||
try { | ||
return getContainerId() != null && DockerClientFactory.instance().client().inspectContainerCmd(getContainerId()).exec().getState().getRunning(); | ||
} catch (DockerException e) { | ||
return false; | ||
} | ||
} | ||
|
||
/** | ||
* Get the actual mapped port for a first port exposed by the container. | ||
* | ||
* @return the port that the exposed port is mapped to | ||
* @throws IllegalStateException if there are no exposed ports | ||
*/ | ||
default Integer getFirstMappedPort() { | ||
return getExposedPorts() | ||
.stream() | ||
.findFirst() | ||
.map(this::getMappedPort) | ||
.orElseThrow(() -> new IllegalStateException("Container doesn't expose any ports")); | ||
} | ||
|
||
/** | ||
* Get the actual mapped port for a given port exposed by the container. | ||
* | ||
* @param originalPort the original TCP port that is exposed | ||
* @return the port that the exposed port is mapped to, or null if it is not exposed | ||
*/ | ||
default Integer getMappedPort(int originalPort) { | ||
Preconditions.checkState(this.getContainerId() != null, "Mapped port can only be obtained after the container is started"); | ||
|
||
Ports.Binding[] binding = new Ports.Binding[0]; | ||
final InspectContainerResponse containerInfo = this.getContainerInfo(); | ||
if (containerInfo != null) { | ||
binding = containerInfo.getNetworkSettings().getPorts().getBindings().get(new ExposedPort(originalPort)); | ||
} | ||
|
||
if (binding != null && binding.length > 0 && binding[0] != null) { | ||
return Integer.valueOf(binding[0].getHostPortSpec()); | ||
} else { | ||
throw new IllegalArgumentException("Requested port (" + originalPort + ") is not mapped"); | ||
} | ||
} | ||
|
||
/** | ||
* @return the exposed ports | ||
*/ | ||
List<Integer> getExposedPorts(); | ||
|
||
/** | ||
* @return the port bindings | ||
*/ | ||
default List<String> getPortBindings() { | ||
List<String> portBindings = new ArrayList<>(); | ||
final Ports hostPortBindings = this.getContainerInfo().getHostConfig().getPortBindings(); | ||
for (Map.Entry<ExposedPort, Ports.Binding[]> binding : hostPortBindings.getBindings().entrySet()) { | ||
for (Ports.Binding portBinding : binding.getValue()) { | ||
portBindings.add(String.format("%s:%s", portBinding.toString(), binding.getKey())); | ||
} | ||
} | ||
return portBindings; | ||
} | ||
|
||
/** | ||
* @return the bound port numbers | ||
*/ | ||
default List<Integer> getBoundPortNumbers() { | ||
return getPortBindings().stream() | ||
.map(PortBinding::parse) | ||
.map(PortBinding::getBinding) | ||
.map(Ports.Binding::getHostPortSpec) | ||
.map(Integer::valueOf) | ||
.collect(Collectors.toList()); | ||
} | ||
|
||
/** | ||
* @return the id of the container | ||
*/ | ||
String getContainerId(); | ||
|
||
/** | ||
* @return the container info | ||
*/ | ||
InspectContainerResponse getContainerInfo(); | ||
} |
Oops, something went wrong.