diff --git a/core/src/main/java/org/testcontainers/containers/GenericContainer.java b/core/src/main/java/org/testcontainers/containers/GenericContainer.java index 24c3415b6f2..aef42a82120 100644 --- a/core/src/main/java/org/testcontainers/containers/GenericContainer.java +++ b/core/src/main/java/org/testcontainers/containers/GenericContainer.java @@ -817,7 +817,7 @@ public ExecResult execInContainer(Charset outputCharset, String... command) .execCreateCmd(this.containerId) .withCmd(command); - logger().info("Running \"exec\" command: " + String.join(" ", command)); + logger().debug("Running \"exec\" command: " + String.join(" ", command)); final ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(this.containerId) .withAttachStdout(true).withAttachStderr(true).withCmd(command).exec(); diff --git a/core/src/main/java/org/testcontainers/containers/wait/HostPortWaitStrategy.java b/core/src/main/java/org/testcontainers/containers/wait/HostPortWaitStrategy.java index d13d8ebf3ed..743432eaeda 100644 --- a/core/src/main/java/org/testcontainers/containers/wait/HostPortWaitStrategy.java +++ b/core/src/main/java/org/testcontainers/containers/wait/HostPortWaitStrategy.java @@ -1,13 +1,16 @@ package org.testcontainers.containers.wait; +import lombok.extern.slf4j.Slf4j; import org.rnorth.ducttape.TimeoutException; import org.rnorth.ducttape.unreliables.Unreliables; import org.testcontainers.DockerClientFactory; import org.testcontainers.containers.ContainerLaunchException; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.dockerclient.ProxiedUnixSocketClientProviderStrategy; -import java.io.IOException; import java.net.Socket; +import java.util.List; +import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; /** @@ -15,30 +18,76 @@ * * @author richardnorth */ +@Slf4j public class HostPortWaitStrategy extends GenericContainer.AbstractWaitStrategy { + + private static final String SUCCESS_MARKER = "TESTCONTAINERS_SUCCESS"; @Override protected void waitUntilReady() { final Integer port = getLivenessCheckPort(); if (null == port) { + log.debug("Liveness check port of {} is empty. Not waiting.", container.getContainerName()); return; } - final String ipAddress = container.getContainerIpAddress(); + Callable checkStrategy; + + // Special case for Docker for Mac, see #160 + if (DockerClientFactory.instance().isUsing(ProxiedUnixSocketClientProviderStrategy.class)) { + List exposedPorts = container.getExposedPorts(); + + Integer exposedPort = exposedPorts.stream() + .filter(it -> port.equals(container.getMappedPort(it))) + .findFirst() + .orElse(null); + + if (null == exposedPort) { + log.warn("Liveness check port of {} is set to {}, but it's not listed in exposed ports.", + container.getContainerName(), port); + return; + } + + String[][] commands = { + { "/bin/sh", "-c", "nc -vz -w 1 localhost " + exposedPort + " && echo " + SUCCESS_MARKER }, + { "/bin/bash", "-c", " { + for (String[] command : commands) { + try { + if (container.execInContainer(command).getStdout().contains(SUCCESS_MARKER)) { + return true; + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } catch (Exception e) { + continue; + } + } + + return false; + }; + } else { + checkStrategy = () -> { + new Socket(container.getContainerIpAddress(), port).close(); + return true; + }; + } + try { - Unreliables.retryUntilSuccess((int) startupTimeout.getSeconds(), TimeUnit.SECONDS, () -> { - getRateLimiter().doWhenReady(() -> { + Unreliables.retryUntilTrue((int) startupTimeout.getSeconds(), TimeUnit.SECONDS, () -> { + return getRateLimiter().getWhenReady(() -> { try { - new Socket(ipAddress, port).close(); - } catch (IOException e) { + return checkStrategy.call(); + } catch (Exception e) { throw new RuntimeException(e); } }); - return true; }); } catch (TimeoutException e) { throw new ContainerLaunchException("Timed out waiting for container port to open (" + - ipAddress + ":" + port + " should be listening)"); + container.getContainerIpAddress() + ":" + port + " should be listening)"); } } }