From e0e79357f2ef4aafba1d26ed2a328151125f6495 Mon Sep 17 00:00:00 2001 From: Josef Cacek Date: Wed, 14 Dec 2022 15:27:18 +0100 Subject: [PATCH 1/5] Don't use stale mapped-ports info in the ContainerState --- .../containers/ContainerState.java | 2 +- .../containers/GenericContainerTest.java | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/containers/ContainerState.java b/core/src/main/java/org/testcontainers/containers/ContainerState.java index b82b5448d2f..760e9bf7d49 100644 --- a/core/src/main/java/org/testcontainers/containers/ContainerState.java +++ b/core/src/main/java/org/testcontainers/containers/ContainerState.java @@ -152,7 +152,7 @@ default Integer getMappedPort(int originalPort) { ); Ports.Binding[] binding = new Ports.Binding[0]; - final InspectContainerResponse containerInfo = this.getContainerInfo(); + final InspectContainerResponse containerInfo = this.getCurrentContainerInfo(); if (containerInfo != null) { binding = containerInfo.getNetworkSettings().getPorts().getBindings().get(new ExposedPort(originalPort)); } diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index 12f5810bc27..e7af4a94eab 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -6,6 +6,8 @@ import com.github.dockerjava.api.model.ExposedPort; import com.github.dockerjava.api.model.Info; import com.github.dockerjava.api.model.Ports; + +import lombok.Cleanup; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; @@ -22,6 +24,11 @@ import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.MountableFile; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -169,6 +176,45 @@ public void shouldWaitUntilExposedPortIsMapped() { } } + @Test + public void mappedPortShouldWorkAfterReconnect() throws IOException { + try ( + Network network = Network.newNetwork(); + GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) + .withNetwork(network) + .withNetworkAliases("foo") + .withExposedPorts(8080) + .withCommand( + "/bin/sh", + "-c", + "while true ; do printf 'HTTP/1.1 200 OK\\n\\nyay' | nc -l -p 8080; done" + ) + ) { + container.start(); + assertYayHttpResponseFrom(container.getHost(), container.getMappedPort(8080)); + + // disconnect container from the network + container.getDockerClient().disconnectFromNetworkCmd() + .withContainerId(container.getContainerId()) + .withNetworkId(network.getId()) + .exec(); + // reconnect container to the network + container.getDockerClient().connectToNetworkCmd() + .withContainerId(container.getContainerId()) + .withNetworkId(network.getId()) + .exec(); + assertYayHttpResponseFrom(container.getHost(), container.getMappedPort(8080)); + } + } + + private static void assertYayHttpResponseFrom(String host, Integer port) throws IOException { + URLConnection urlConnection = new java.net.URL("http", host, port, "/").openConnection(); + @Cleanup + BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); + String response = reader.readLine(); + assertThat(response).as("received response").isEqualTo("yay"); + } + static class NoopStartupCheckStrategy extends StartupCheckStrategy { @Override From 726fe3f655fe700ba4f102acac8935d95aa90ca7 Mon Sep 17 00:00:00 2001 From: Josef Cacek Date: Wed, 14 Dec 2022 16:00:05 +0100 Subject: [PATCH 2/5] Formatting fix --- .../containers/GenericContainerTest.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index e7af4a94eab..6af083d1f52 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -6,7 +6,6 @@ import com.github.dockerjava.api.model.ExposedPort; import com.github.dockerjava.api.model.Info; import com.github.dockerjava.api.model.Ports; - import lombok.Cleanup; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; @@ -27,7 +26,6 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; -import java.net.URL; import java.net.URLConnection; import java.util.Arrays; import java.util.List; @@ -184,22 +182,22 @@ public void mappedPortShouldWorkAfterReconnect() throws IOException { .withNetwork(network) .withNetworkAliases("foo") .withExposedPorts(8080) - .withCommand( - "/bin/sh", - "-c", - "while true ; do printf 'HTTP/1.1 200 OK\\n\\nyay' | nc -l -p 8080; done" - ) + .withCommand("/bin/sh", "-c", "while true ; do printf 'HTTP/1.1 200 OK\\n\\nyay' | nc -l -p 8080; done") ) { container.start(); assertYayHttpResponseFrom(container.getHost(), container.getMappedPort(8080)); // disconnect container from the network - container.getDockerClient().disconnectFromNetworkCmd() + container + .getDockerClient() + .disconnectFromNetworkCmd() .withContainerId(container.getContainerId()) .withNetworkId(network.getId()) .exec(); // reconnect container to the network - container.getDockerClient().connectToNetworkCmd() + container + .getDockerClient() + .connectToNetworkCmd() .withContainerId(container.getContainerId()) .withNetworkId(network.getId()) .exec(); From 549159060696e0179b1d882eb5c46d718d7c84c5 Mon Sep 17 00:00:00 2001 From: Josef Cacek Date: Thu, 15 Dec 2022 10:18:19 +0100 Subject: [PATCH 3/5] Revert ContainerState change, add JavaDoc, and update test to verify the recommended approach --- .../containers/ContainerState.java | 19 +++++++++++++++++-- .../containers/GenericContainerTest.java | 9 +++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/ContainerState.java b/core/src/main/java/org/testcontainers/containers/ContainerState.java index 760e9bf7d49..f355bf445fb 100644 --- a/core/src/main/java/org/testcontainers/containers/ContainerState.java +++ b/core/src/main/java/org/testcontainers/containers/ContainerState.java @@ -119,6 +119,12 @@ default boolean isHealthy() { } } + /** + * Inspects the container and returns up-to-date inspection response. + * + * @return up-to-date container inspect response + * @see #getContainerInfo() + */ default InspectContainerResponse getCurrentContainerInfo() { return getDockerClient().inspectContainerCmd(getContainerId()).exec(); } @@ -140,10 +146,16 @@ default Integer getFirstMappedPort() { /** * Get the actual mapped port for a given port exposed by the container. - * Should be used in conjunction with {@link #getHost()}. + * It should be used in conjunction with {@link #getHost()}. + *

+ * Note: The returned port number might be outdated (for instance, after disconnecting from a network and reconnecting + * again). If you always need up-to-date value, override the {@link #getContainerInfo()} to return the + * {@link #getCurrentContainerInfo()}. * * @param originalPort the original TCP port that is exposed * @return the port that the exposed port is mapped to, or null if it is not exposed + * @see #getContainerInfo() + * @see #getCurrentContainerInfo() */ default Integer getMappedPort(int originalPort) { Preconditions.checkState( @@ -152,7 +164,7 @@ default Integer getMappedPort(int originalPort) { ); Ports.Binding[] binding = new Ports.Binding[0]; - final InspectContainerResponse containerInfo = this.getCurrentContainerInfo(); + final InspectContainerResponse containerInfo = this.getContainerInfo(); if (containerInfo != null) { binding = containerInfo.getNetworkSettings().getPorts().getBindings().get(new ExposedPort(originalPort)); } @@ -222,7 +234,10 @@ default String getContainerId() { } /** + * Returns the container inspect response. The response might be cached/outdated. + * * @return the container info + * @see #getCurrentContainerInfo() */ InspectContainerResponse getContainerInfo(); diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index 6af083d1f52..fa083df74f6 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -175,10 +175,15 @@ public void shouldWaitUntilExposedPortIsMapped() { } @Test - public void mappedPortShouldWorkAfterReconnect() throws IOException { + public void mappedPortCanBeUpdatedAfterReconnect() throws IOException { try ( Network network = Network.newNetwork(); - GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) + GenericContainer container = new GenericContainer(TestImages.TINY_IMAGE) { + @Override + public InspectContainerResponse getContainerInfo() { + return getCurrentContainerInfo(); + } + } .withNetwork(network) .withNetworkAliases("foo") .withExposedPorts(8080) From d7fa5ffcdde05a15ed35ade9fd0fa541727c27ff Mon Sep 17 00:00:00 2001 From: Josef Cacek Date: Tue, 24 Jan 2023 13:56:21 +0700 Subject: [PATCH 4/5] Update core/src/test/java/org/testcontainers/containers/GenericContainerTest.java Co-authored-by: Kevin Wittek --- .../containers/GenericContainerTest.java | 44 ------------------- 1 file changed, 44 deletions(-) diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index d437755324c..81dac8724ef 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -184,50 +184,6 @@ public void shouldWaitUntilExposedPortIsMapped() { } } - @Test - public void mappedPortCanBeUpdatedAfterReconnect() throws IOException { - try ( - Network network = Network.newNetwork(); - GenericContainer container = new GenericContainer(TestImages.TINY_IMAGE) { - @Override - public InspectContainerResponse getContainerInfo() { - return getCurrentContainerInfo(); - } - } - .withNetwork(network) - .withNetworkAliases("foo") - .withExposedPorts(8080) - .withCommand("/bin/sh", "-c", "while true ; do printf 'HTTP/1.1 200 OK\\n\\nyay' | nc -l -p 8080; done") - ) { - container.start(); - assertYayHttpResponseFrom(container.getHost(), container.getMappedPort(8080)); - - // disconnect container from the network - container - .getDockerClient() - .disconnectFromNetworkCmd() - .withContainerId(container.getContainerId()) - .withNetworkId(network.getId()) - .exec(); - // reconnect container to the network - container - .getDockerClient() - .connectToNetworkCmd() - .withContainerId(container.getContainerId()) - .withNetworkId(network.getId()) - .exec(); - assertYayHttpResponseFrom(container.getHost(), container.getMappedPort(8080)); - } - } - - private static void assertYayHttpResponseFrom(String host, Integer port) throws IOException { - URLConnection urlConnection = new java.net.URL("http", host, port, "/").openConnection(); - @Cleanup - BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); - String response = reader.readLine(); - assertThat(response).as("received response").isEqualTo("yay"); - } - static class NoopStartupCheckStrategy extends StartupCheckStrategy { @Override From 22730f974282c86919211e0c2b2842dc39aea3f6 Mon Sep 17 00:00:00 2001 From: Josef Cacek Date: Tue, 24 Jan 2023 13:59:24 +0700 Subject: [PATCH 5/5] Remove unused imports --- .../org/testcontainers/containers/GenericContainerTest.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index 81dac8724ef..538e2e3d67a 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -6,7 +6,6 @@ import com.github.dockerjava.api.model.ExposedPort; import com.github.dockerjava.api.model.Info; import com.github.dockerjava.api.model.Ports; -import lombok.Cleanup; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; @@ -23,10 +22,6 @@ import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.MountableFile; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.URLConnection; import java.util.Arrays; import java.util.List; import java.util.Map;