diff --git a/docker-compose-rule-core/src/integrationTest/java/com/palantir/docker/compose/EventsIntegrationTest.java b/docker-compose-rule-core/src/integrationTest/java/com/palantir/docker/compose/EventsIntegrationTest.java index e39f2cb23..21d5b50a8 100644 --- a/docker-compose-rule-core/src/integrationTest/java/com/palantir/docker/compose/EventsIntegrationTest.java +++ b/docker-compose-rule-core/src/integrationTest/java/com/palantir/docker/compose/EventsIntegrationTest.java @@ -17,7 +17,7 @@ package com.palantir.docker.compose; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -87,18 +87,15 @@ public void produces_events_when_a_container_healthcheck_exceeds_its_timeout() { .addEventConsumer(eventConsumer) .build(); - try { - runDockerComposeRule(dockerComposeManager); - fail("Was expecting an exception"); - } catch (Throwable t) { - // ignore the failure - } + assertThatThrownBy(() -> runDockerComposeRule(dockerComposeManager), "Was expecting an exception") + .isInstanceOf(Throwable.class); List events = getEvents(); ClusterWaitEvent clusterWait = events.stream() .map(this::isClusterWait) .filter(Optional::isPresent) + .filter(e -> e.get().getTask().getFailure().isPresent()) .map(Optional::get) .findFirst() .orElseThrow(() -> new IllegalStateException("no clusterwaits in events")); diff --git a/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/connection/Ports.java b/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/connection/Ports.java index 227f98801..695a45c52 100644 --- a/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/connection/Ports.java +++ b/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/connection/Ports.java @@ -18,11 +18,13 @@ import com.google.common.base.Preconditions; import com.google.common.base.Strings; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import java.util.stream.Stream; public final class Ports { @@ -56,7 +58,30 @@ public Stream stream() { public static Ports parseFromDockerComposePs(String psOutput, String dockerMachineIp) { Preconditions.checkArgument(!Strings.isNullOrEmpty(psOutput), "No container found"); - Matcher matcher = PORT_PATTERN.matcher(psOutput); + final String[] lines = psOutput.split("\\R"); + String cleanOutput = psOutput; + // Clean actual ps output to remove line breaks and unneeded spaces + if (lines.length > 1) { + int lineWithDashes = -1; + for (int i = 0; i < lines.length; i++) { + if (lines[i].startsWith("-------")) { + lineWithDashes = i; + break; + } + } + Preconditions.checkArgument(lineWithDashes > -1, "No container found"); + final int linesToSkip = lineWithDashes + 1; + Preconditions.checkArgument(lines.length > linesToSkip, "No container found"); + final int lastIndexOfFieldSeparator = lines[linesToSkip].lastIndexOf(" "); + Preconditions.checkArgument(lastIndexOfFieldSeparator > -1, "Invalid input"); + + cleanOutput = Arrays.stream(lines) + .skip(linesToSkip) + .map(l -> l.substring(lastIndexOfFieldSeparator + 3)) + .map(String::trim) + .collect(Collectors.joining("")); + } + Matcher matcher = PORT_PATTERN.matcher(cleanOutput); List ports = new ArrayList<>(); while (matcher.find()) { String matchedIpAddress = matcher.group(IP_ADDRESS); @@ -66,7 +91,7 @@ public static Ports parseFromDockerComposePs(String psOutput, String dockerMachi ports.add(new DockerPort(ip, externalPort, internalPort)); } - Matcher rangeMatcher = PORT_RANGE_PATTERN.matcher(psOutput); + Matcher rangeMatcher = PORT_RANGE_PATTERN.matcher(cleanOutput); while (rangeMatcher.find()) { String matchedIpAddress = rangeMatcher.group(IP_ADDRESS); String ip = matchedIpAddress.equals(NO_IP_ADDRESS) ? dockerMachineIp : matchedIpAddress; diff --git a/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/Docker.java b/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/Docker.java index e403a5e4b..471496cfe 100644 --- a/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/Docker.java +++ b/docker-compose-rule-core/src/main/java/com/palantir/docker/compose/execution/Docker.java @@ -34,7 +34,8 @@ public final class Docker { private static final Logger log = LoggerFactory.getLogger(Docker.class); // Without java escape characters: ^(\d+)\.(\d+)\.(\d+)(?:-.*)?$ - private static final Pattern VERSION_PATTERN = Pattern.compile("^Docker version (\\d+)\\.(\\d+)\\.(\\d+)(?:-.*)?$"); + private static final Pattern VERSION_PATTERN = + Pattern.compile("^Docker version (\\d+)\\.(\\d+)\\.(\\d+)(?:[,-].*)?$"); private static final String HEALTH_STATUS_FORMAT = "--format=" + "{{if not .State.Running}}DOWN" + "{{else if .State.Paused}}PAUSED" diff --git a/docker-compose-rule-core/src/test/java/com/palantir/docker/compose/connection/PortsShould.java b/docker-compose-rule-core/src/test/java/com/palantir/docker/compose/connection/PortsShould.java index a7a936504..8207c5461 100644 --- a/docker-compose-rule-core/src/test/java/com/palantir/docker/compose/connection/PortsShould.java +++ b/docker-compose-rule-core/src/test/java/com/palantir/docker/compose/connection/PortsShould.java @@ -95,6 +95,35 @@ public void parse_actual_docker_compose_output() { assertThat(ports, is(expected)); } + @Test + public void parse_docker_compose_output_on_narrow_terminal() { + String psOutput = " Name Command State Ports \n" + + "--------------------------------------------------------------------------------\n" + + "projectnamemyserv docker-entrypoint.sh Up (healthy) 4510/tcp, 4511/tcp,\n" + + "ice_localstack_1 4512/tcp, 4513/tcp,\n" + + " 4514/tcp, 4515/tcp,\n" + + " 4558/tcp, 4559/tcp,\n" + + " 0.0.0.0:49153->4566\n" + + " /tcp,:::49153->4566\n" + + " /tcp, 5678/tcp "; + Ports ports = Ports.parseFromDockerComposePs(psOutput, LOCALHOST_IP); + Ports expected = new Ports(newArrayList(new DockerPort(LOCALHOST_IP, 49153, 4566))); + assertThat(ports, is(expected)); + } + + @Test + public void parse_docker_compose_output_on_narrow_terminal_2() { + String psOutput = " Name Command State Ports \n" + + "------------------------------------------------------------\n" + + "decisiontable docker- Up (healthy) 4559/tcp, 0.0\n" + + "microservice_ entrypoint.sh .0.0:49187->4\n" + + "localstack_1 566/tcp, \n" + + " 5678/tcp "; + Ports ports = Ports.parseFromDockerComposePs(psOutput, LOCALHOST_IP); + Ports expected = new Ports(newArrayList(new DockerPort(LOCALHOST_IP, 49187, 4566))); + assertThat(ports, is(expected)); + } + @Test public void throw_illegal_state_exception_when_no_running_container_found_for_service() { exception.expect(IllegalArgumentException.class);