package org.testcontainers.junit; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import com.google.common.util.concurrent.Uninterruptibles; import org.junit.Test; import org.rnorth.ducttape.unreliables.Unreliables; import org.testcontainers.containers.FixedHostPortGenericContainer; import org.testcontainers.containers.GenericContainer; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; import java.util.concurrent.TimeUnit; /** * Test of {@link FixedHostPortGenericContainer}. Note that this is not an example of typical use (usually, a container * should be a field on the test class annotated with @Rule or @TestRule). Instead, here, the lifecycle of the container * is managed completely within the test method to allow a free port to be found and assigned before the container * is started. */ public class FixedHostPortContainerTest { private static final String TEST_IMAGE = "alpine:3.2"; /** * Default http server port (just something different from default) */ private static final int TEST_PORT = 5678; /** * test response */ private static final String TEST_RESPONSE = "test-response"; /** * *nix pipe to fire test response on test port */ private static final String HTTP_ECHO_CMD = String.format("while true; do echo \"%s\" | nc -l -p %d; done", TEST_RESPONSE, TEST_PORT); @Test public void testFixedHostPortMapping() throws IOException { // first find a free port on the docker host that will work for testing final Integer unusedHostPort; try ( final GenericContainer echoServer = new GenericContainer<>(TEST_IMAGE) .withExposedPorts(TEST_PORT) .withCommand("/bin/sh", "-c", HTTP_ECHO_CMD) ) { echoServer.start(); unusedHostPort = echoServer.getMappedPort(TEST_PORT); } // now starting echo server container mapped to known-as-free host port try ( final GenericContainer echoServer = new FixedHostPortGenericContainer(TEST_IMAGE) // using workaround for port bind+expose .withFixedExposedPort(unusedHostPort, TEST_PORT) .withExposedPorts(TEST_PORT) .withCommand("/bin/sh", "-c", HTTP_ECHO_CMD) ) { echoServer.start(); assertThat("Port mapping does not seem to match given fixed port", echoServer.getMappedPort(TEST_PORT), equalTo(unusedHostPort)); final String content = this.readResponse(echoServer, unusedHostPort); assertThat("Returned echo from fixed port does not match expected", content, equalTo(TEST_RESPONSE)); } } /** * Simple socket content reader from given container:port * * @param container to query * @param port to send request to * @return socket reader content * @throws IOException if any */ private String readResponse(GenericContainer container, Integer port) throws IOException { try ( final BufferedReader reader = Unreliables.retryUntilSuccess(10, TimeUnit.SECONDS, () -> { Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS); final Socket socket = new Socket(container.getHost(), port); return new BufferedReader(new InputStreamReader(socket.getInputStream())); } ) ) { return reader.readLine(); } } }