All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pl.domzal.junit.docker.rule.WaitFor Maven / Gradle / Ivy

There is a newer version: 0.6.0
Show newest version
package pl.domzal.junit.docker.rule;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.spotify.docker.client.shaded.com.google.common.collect.Lists;
import com.spotify.docker.client.shaded.com.google.common.primitives.Ints;

import pl.domzal.junit.docker.rule.wait.HttpPingChecker;
import pl.domzal.junit.docker.rule.wait.LogChecker;
import pl.domzal.junit.docker.rule.wait.LogSequenceChecker;
import pl.domzal.junit.docker.rule.wait.TcpPortChecker;
import pl.domzal.junit.docker.rule.wait.StartConditionCheck;
import pl.domzal.junit.docker.rule.wait.StartCondition;

/**
 * Predefined set of handy {@link StartConditionCheck} builders.
 */
public class WaitFor {

    private static final Logger log = LoggerFactory.getLogger(WaitFor.class);

    /**
     * Wait for specified text in log on container start.
     * Whole log content (from container start) is checked so this condition
     * will work independent of any other wait conditions.
     * Rule startup will fail when message will not be found.
     *
     * @param logMessage Message to wait for.
     */
    public static StartCondition logMessage(final String logMessage) {
        return new StartCondition() {
            @Override
            public StartConditionCheck build(DockerRule currentRule) {
                log.debug("new wait for condition - message: '{}'", logMessage);
                return new LogChecker(currentRule, logMessage);
            }
        };
    }

    /**
     * Wait for message sequence in log container start.
     *
     * @param message
     */
    public static StartCondition logMessageSequence(String... message) {
        return logMessageSequence(Lists.newArrayList(message));
    }

    public static StartCondition logMessageSequence(final List messageSequence) {
        return new StartCondition() {
            @Override
            public StartConditionCheck build(DockerRule currentRule) {
                log.debug("new wait for condition - message sequence: '{}'", messageSequence);
                return new LogSequenceChecker(messageSequence);
            }
        };
    }

    /**
     * Wait for TCP port listening under given internal container port.
     * Given port MUST be exposed (with {@link DockerRuleBuilder#expose(String, String)} or
     * {@link DockerRuleBuilder#publishAllPorts(boolean)}) (reachable from the test
     * code point of view).
     * 

* Side note: * Internal port is required for convenience - rule will find matching external port * or, report error at startup when given internal port was not exposed. *

* Side note 2: * TCP port check depends of docker internal port-forwarding feature and docker server setup. * In short: won't work if docker engine forwards port using docker-proxy (aka userland proxy) * - will report port opening almost instantly and NOT wait for underlying port opening. * To make things worst - this is default configuration on some platforms so it is better to not * rely on this method at all. *

* Additional userland proxy info:

* * @param internalTcpPorts TCP port (or ports) to scan (internal, MUST be exposed for wait to work). */ public static StartCondition tcpPort(final int... internalTcpPorts) { return tcpPort(Ints.asList(internalTcpPorts)); } private static StartCondition tcpPort(final List internalPorts) { return new StartCondition() { @Override public StartConditionCheck build(DockerRule currentRule) { List externalPorts = Lists.newArrayList(); for (Integer intPort : internalPorts) { externalPorts.add(currentRule.findExternalPort(intPort)); } log.debug("new wait for condition - tcp port(s) open: {} (external port(s): {})", internalPorts, externalPorts); return new TcpPortChecker(currentRule.getDockerHost(), externalPorts); } }; } /** * Wait for http endpoint availability under given internal container port. * Given port MUST be exposed (with {@link DockerRuleBuilder#expose(String, String)} or * {@link DockerRuleBuilder#publishAllPorts(boolean)}) (reachable from the test * code point of view). *

* Side note: Internal port is required for convenience - rule will find matching * external port or, report error at startup when given internal port was not exposed. * * @param internalHttpPort Http port to scan for availability. Port is scanned with HTTP HEAD method * until response with error code 2xx or 3xx is returned or until timeout. * Port MUST be exposed for wait to work and given port number must * be internal (as seen on container, not as on host) port number. */ public static StartCondition httpPing(final int internalHttpPort) { return new StartCondition() { @Override public StartConditionCheck build(DockerRule currentRule) { String exposedPort = currentRule.getExposedContainerPort(Integer.toString(internalHttpPort)); String pingUrl = String.format("http://%s:%s/", currentRule.getDockerHost(), exposedPort); log.debug("new wait for condition - http ping port: {}, url: '{}'", internalHttpPort, pingUrl); return new HttpPingChecker(pingUrl, null, null); } }; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy