From 404a91d0912a582a35db83ddc265b72974c56481 Mon Sep 17 00:00:00 2001 From: Soumajit Ghosh Date: Thu, 18 Jun 2026 09:32:55 +0530 Subject: [PATCH] Refresh mapped ports after network attach --- .../containers/ContainerState.java | 9 +-- .../containers/ContainerStateTest.java | 66 +++++++++++++++++++ 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/testcontainers/containers/ContainerState.java b/core/src/main/java/org/testcontainers/containers/ContainerState.java index e19f7a85310..e82bf640fbf 100644 --- a/core/src/main/java/org/testcontainers/containers/ContainerState.java +++ b/core/src/main/java/org/testcontainers/containers/ContainerState.java @@ -148,13 +148,8 @@ default Integer getFirstMappedPort() { * Get the actual mapped port for a given port exposed by the container. * 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) { @@ -164,7 +159,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)); } @@ -186,7 +181,7 @@ default Integer getMappedPort(int originalPort) { */ default List getPortBindings() { List portBindings = new ArrayList<>(); - final Ports hostPortBindings = this.getContainerInfo().getHostConfig().getPortBindings(); + final Ports hostPortBindings = this.getCurrentContainerInfo().getHostConfig().getPortBindings(); for (Map.Entry binding : hostPortBindings.getBindings().entrySet()) { for (Ports.Binding portBinding : binding.getValue()) { portBindings.add(String.format("%s:%s", portBinding.toString(), binding.getKey())); diff --git a/core/src/test/java/org/testcontainers/containers/ContainerStateTest.java b/core/src/test/java/org/testcontainers/containers/ContainerStateTest.java index 7b37bc1926f..0da3a4049b2 100644 --- a/core/src/test/java/org/testcontainers/containers/ContainerStateTest.java +++ b/core/src/test/java/org/testcontainers/containers/ContainerStateTest.java @@ -1,5 +1,11 @@ package org.testcontainers.containers; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.model.ExposedPort; +import com.github.dockerjava.api.model.HostConfig; +import com.github.dockerjava.api.model.NetworkSettings; +import com.github.dockerjava.api.model.Ports; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -35,4 +41,64 @@ void test(String name, String testSet, List expectedResult) { List result = containerState.getBoundPortNumbers(); assertThat(result).hasSameElementsAs(expectedResult); } + + @Test + void getMappedPortUsesCurrentContainerInfo() { + ContainerState containerState = mock(ContainerState.class); + doCallRealMethod().when(containerState).getMappedPort(8080); + InspectContainerResponse cachedInfo = inspectResponse(8080, 18080); + InspectContainerResponse currentInfo = inspectResponse(8080, 28080); + + when(containerState.getContainerId()).thenReturn("container-id"); + when(containerState.getContainerInfo()).thenReturn(cachedInfo); + when(containerState.getCurrentContainerInfo()).thenReturn(currentInfo); + + assertThat(containerState.getMappedPort(8080)).isEqualTo(28080); + } + + @Test + void getFirstMappedPortUsesCurrentContainerInfo() { + ContainerState containerState = mock(ContainerState.class); + doCallRealMethod().when(containerState).getMappedPort(8080); + doCallRealMethod().when(containerState).getFirstMappedPort(); + InspectContainerResponse cachedInfo = inspectResponse(8080, 18080); + InspectContainerResponse currentInfo = inspectResponse(8080, 28080); + + when(containerState.getContainerId()).thenReturn("container-id"); + when(containerState.getExposedPorts()).thenReturn(Collections.singletonList(8080)); + when(containerState.getContainerInfo()).thenReturn(cachedInfo); + when(containerState.getCurrentContainerInfo()).thenReturn(currentInfo); + + assertThat(containerState.getFirstMappedPort()).isEqualTo(28080); + } + + @Test + void getPortBindingsUsesCurrentContainerInfo() { + ContainerState containerState = mock(ContainerState.class); + doCallRealMethod().when(containerState).getPortBindings(); + InspectContainerResponse cachedInfo = inspectResponse(8080, 18080); + InspectContainerResponse currentInfo = inspectResponse(8080, 28080); + + when(containerState.getContainerInfo()).thenReturn(cachedInfo); + when(containerState.getCurrentContainerInfo()).thenReturn(currentInfo); + + assertThat(containerState.getPortBindings()).containsExactly("28080:8080/tcp"); + } + + private static InspectContainerResponse inspectResponse(int containerPort, int hostPort) { + InspectContainerResponse response = mock(InspectContainerResponse.class); + NetworkSettings networkSettings = mock(NetworkSettings.class); + HostConfig hostConfig = mock(HostConfig.class); + Ports ports = new Ports(); + ExposedPort exposedPort = new ExposedPort(containerPort); + Ports.Binding binding = Ports.Binding.bindPort(hostPort); + ports.bind(exposedPort, binding); + + when(response.getNetworkSettings()).thenReturn(networkSettings); + when(networkSettings.getPorts()).thenReturn(ports); + when(response.getHostConfig()).thenReturn(hostConfig); + when(hostConfig.getPortBindings()).thenReturn(ports); + + return response; + } }