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
    }
}

@@ -322,16 +322,43 @@
 ables;%0A%0A
+import java.time.Duration;%0A
 import j
@@ -387,16 +387,16 @@
 meUnit;%0A
-
 %0Aimport 
@@ -819,24 +819,293 @@
  .build();%0A%0A
+    private Duration timeout = Duration.ofSeconds(CONTAINER_RUNNING_TIMEOUT_SEC);%0A%0A    @SuppressWarnings(%22unchecked%22)%0A    public %3CSELF extends StartupCheckStrategy%3E SELF withTimeout(Duration timeout) %7B%0A        this.timeout = timeout;%0A        return (SELF) this;%0A    %7D%0A%0A
     public b
@@ -1270,37 +1270,32 @@
 rue(
-CONTAINER_RUNNING_TIMEOUT_SEC
+(int) timeout.toMillis()
 , Ti
@@ -1297,24 +1297,29 @@
 ), TimeUnit.
+MILLI
 SECONDS, () 

Make StartupCheckStrategy timeout value configurable (#1308)