org.testcontainers.utility.DockerStatus Maven / Gradle / Ivy
Show all versions of testcontainers Show documentation
package org.testcontainers.utility;
import com.github.dockerjava.api.command.InspectContainerResponse;
import java.time.Duration;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
/**
* Utility functions for dealing with docker status based on the information available to us, and trying to be
* defensive.
*
*
In docker-java version 2.2.0, which we're using, only these
* fields are available in the container state returned from Docker Inspect: "isRunning", "isPaused", "startedAt", and
* "finishedAt". There are states that can occur (including "created", "OOMkilled" and "dead") that aren't directly
* shown through this result.
*
*
Docker also doesn't seem to use null values for timestamps; see DOCKER_TIMESTAMP_ZERO, below.
*/
public class DockerStatus {
/**
* When the docker client has an "empty" timestamp, it returns this special value, rather than
* null or an empty string.
*/
static final String DOCKER_TIMESTAMP_ZERO = "0001-01-01T00:00:00Z";
/**
* Based on this status, is this container running, and has it been doing so for the specified amount of time?
*
* @param state the state provided by InspectContainer
* @param minimumRunningDuration minimum duration to consider this as "solidly" running, or null
* @param now the time to consider as the current time
* @return true if we can conclude that the container is running, false otherwise
*/
public static boolean isContainerRunning(InspectContainerResponse.ContainerState state,
Duration minimumRunningDuration,
Instant now) {
if (state.getRunning()) {
if (minimumRunningDuration == null) {
return true;
}
Instant startedAt = DateTimeFormatter.ISO_INSTANT.parse(
state.getStartedAt(), Instant::from);
if (startedAt.isBefore(now.minus(minimumRunningDuration))) {
return true;
}
}
return false;
}
/**
* Based on this status, has the container halted?
*
* @param state the state provided by InspectContainer
* @return true if we can conclude that the container has started but is now stopped, false otherwise.
*/
public static boolean isContainerStopped(InspectContainerResponse.ContainerState state) {
// get some preconditions out of the way
if (state.getRunning() || state.getPaused()) {
return false;
}
// if the finished timestamp is non-empty, that means the container started and finished.
boolean hasStarted = isDockerTimestampNonEmpty(state.getStartedAt());
boolean hasFinished = isDockerTimestampNonEmpty(state.getFinishedAt());
return hasStarted && hasFinished;
}
public static boolean isDockerTimestampNonEmpty(String dockerTimestamp) {
// This is a defensive approach. Current versions of Docker use the DOCKER_TIMESTAMP_ZERO value, but
// that could change.
return dockerTimestamp != null
&& !dockerTimestamp.isEmpty()
&& !dockerTimestamp.equals(DOCKER_TIMESTAMP_ZERO)
&& DateTimeFormatter.ISO_INSTANT.parse(dockerTimestamp, Instant::from).getEpochSecond() >= 0L;
}
public static boolean isContainerExitCodeSuccess(InspectContainerResponse.ContainerState state) {
int exitCode = state.getExitCode();
// 0 is the only exit code we can consider as success
return exitCode == 0;
}
}