package org.testcontainers.containers.startupcheck; import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.InspectContainerResponse; import org.rnorth.ducttape.ratelimits.RateLimiter; import org.rnorth.ducttape.ratelimits.RateLimiterBuilder; import org.rnorth.ducttape.unreliables.Unreliables; import java.util.concurrent.TimeUnit; import static org.testcontainers.containers.GenericContainer.CONTAINER_RUNNING_TIMEOUT_SEC; /** * Approach to determine whether a container has 'started up' correctly. */ public abstract class StartupCheckStrategy { private static final RateLimiter DOCKER_CLIENT_RATE_LIMITER = RateLimiterBuilder .newBuilder() .withRate(1, TimeUnit.SECONDS) .withConstantThroughput() .build(); public boolean waitUntilStartupSuccessful(DockerClient dockerClient, String containerId) { final Boolean[] startedOK = {null}; Unreliables.retryUntilTrue(CONTAINER_RUNNING_TIMEOUT_SEC, TimeUnit.SECONDS, () -> { //noinspection CodeBlock2Expr return DOCKER_CLIENT_RATE_LIMITER.getWhenReady(() -> { StartupStatus state = checkStartupState(dockerClient, containerId); switch (state) { case SUCCESSFUL: startedOK[0] = true; return true; case FAILED: startedOK[0] = false; return true; default: return false; } }); }); return startedOK[0]; } public abstract StartupStatus checkStartupState(DockerClient dockerClient, String containerId); protected InspectContainerResponse.ContainerState getCurrentState(DockerClient dockerClient, String containerId) { return dockerClient.inspectContainerCmd(containerId).exec().getState(); } public enum StartupStatus { NOT_YET_KNOWN, SUCCESSFUL, FAILED } }