arakelian/docker-junit-rule

Question

davidgoate opened this issue · 8 comments

I appreciate this probably isn't strictly related to this project and might be more of a question about using the spotify docker client, however, I'm hoping you might be able to help me:

I am trying to bind two ports in the container to two ports on the host, I tried this:

 private static Map<String, List<PortBinding>> getPortBindings(final PortBinding binding1, final PortBinding binding2) {
        final Map<String, List<PortBinding>> bindings = new HashMap<>(2, 1f);
        bindings.put(8080, singletonList(binding1));
        bindings.put(8081, singletonList(binding2));
        return bindings;
    }


  super(ImmutableDockerConfig.builder()
.addHostConfigurer(host -> host.portBindings(getPortBindings(x,y)))

where the first binding is 172.29.1.18:5474->8080 and the second is 172.29.1.18:5474->8081

when I run the code I get:

CONTAINER ID        IMAGE                                COMMAND                  CREATED                  STATUS              PORTS                                  NAMES
c21a3eb43778        rodolpheche/wiremock:2.14.0-alpine   "/docker-entrypoint.…"   Less than a second ago   Up 1 second         8081/tcp, 172.29.1.18:5474->8080/tcp   wire-mock-test-5474

and port 8081 is not mapped as expected.

Am I creating the mappings incorrectly? Thanks in advance.

To be honest, I haven't done this myself via Spotify's API. I don't mind trying this myself but off the top of my head I can't think of a particular image that would be good for testing this. What Docker image are you using (assuming it's public)? If you can point me in the right direction, I don't mind creating a unit test to verify that it works.

Thanks for getting back to me, I am using rodolpheche/wiremock:2.14.0-alpine which exposes both 8080 and 8081. dockerfile here: https://github.com/rodolpheche/wiremock-docker/blob/master/Dockerfile#L29

public class WireMockDockerRule extends DockerRule {

    private static final String DOCKER_IMAGE = "rodolpheche/wiremock:2.14.0-alpine";
    private static final String WIRE_MOCK_HTTP_PORT_IN_CONTAINER = "8080";
    private static final String WIRE_MOCK_HTTPS_PORT_IN_CONTAINER = "8081";
    private static final String CONTAINER_NAME_PREFIX = "wire-mock-test-";

    public WireMockDockerRule(final PortBinding binding) {
        super(ImmutableDockerConfig.builder()
                .name(CONTAINER_NAME_PREFIX + binding.hostPort())
                .image(DOCKER_IMAGE)
                .ports(WIRE_MOCK_HTTP_PORT_IN_CONTAINER, WIRE_MOCK_HTTP_PORT_IN_CONTAINER)
                .addContainerConfigurer(c -> c.cmd("-verbose", "--print-all-network-traffic"))
                .alwaysRemoveContainer(true)
                .addHostConfigurer(bindPorts(getPortBindings(binding)))
                .addStartedListener(waitForContainerToBeReady(WIRE_MOCK_HTTP_PORT_IN_CONTAINER))
                .build());
    }

    private static Map<String, List<PortBinding>> getPortBindings(final PortBinding binding) {
        final Map<String, List<PortBinding>> bindings = new HashMap<>(2, 1f);
        final PortBinding httpsPortBinding = DockerRuleUtils.getRandomPort(binding.hostIp());
        bindings.put(WIRE_MOCK_HTTP_PORT_IN_CONTAINER, singletonList(binding));
        bindings.put(WIRE_MOCK_HTTPS_PORT_IN_CONTAINER, singletonList(httpsPortBinding));
        return bindings;
    }
}

public static String getLocalHostAddress() {
        try {
            final String hostAddress = InetAddress.getLocalHost().getHostAddress();
            LOGGER.info("LocalHost Address is {}.", hostAddress);
            return hostAddress;
        } catch (final UnknownHostException e) {
            throw new RuntimeException("Unable to get localhost address", e);
        }
    }

    public static PortBinding getRandomPort(final String hostIP) {
        return PortBinding.of(hostIP, RandomUtils.nextInt(3_000, 10_000));
    }

    public static HostConfigurer bindPorts(final Map<String, List<PortBinding>> bindings) {
        return host -> {
            //host.publishAllPorts(true);
            host.portBindings(bindings);
        };
    }

    public static StartedListener waitForContainerToBeReady(final String containerPortNumber) {
        return container -> container.waitForPort(containerPortNumber + TCP_SUFFIX, 15, TimeUnit.SECONDS);
    }

@davidgoate I didn't have a chance to work on this today. I'll take a look at this in the morning. Thanks!

@arakelian thanks very much, this is a cool project - very helpful! appreciate the prompt responses :)

@davidgoate This is definitely a Spotify Docker issue, e.g how to pass the "--http-port 8081" argument to the Wiremock Docker image at startup.

Using your code above, when I run "docker log "

**port:                         8080**
enable-browser-proxying:      false
no-request-journal:           false
verbose:                      true

When I start it Wiremock manually, using this line:

docker run -it --rm -p 8081:8081 -p 8080:8080 rodolpheche/wiremock:2.14.0-alpine --https-port 8081 --verbose

And then use docker log again:

port:                         8080
**https-port:                   8081**
https-keystore:               jar:file:/var/wiremock/lib/wiremock-standalone.jar!/keystore
enable-browser-proxying:      false
no-request-journal:           false
verbose:                      true            

Notice the we're missing a line like this:

https-port:                   8081

This will fix it for you:

.addContainerConfigurer(
                        c -> c.cmd("-verbose", "--print-all-network-traffic", "--https-port=8081"))

And then:

.addStartedListener(container -> {
                    container.waitForPort("8080");
                    container.waitForPort("8081");
                })

@davidgoate Upgrade to version 2.0.2 (release last night). It fixes up some issues I found with the way that I was shading spotify docker client.

Version 2.1.0 (2c2185f) adds a unit test for WireMock. Will take an hour or two before Maven Central picks it up.