Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Testcontainers - Cannot connect to exposed port

I implemented a POP3 server and client using javax.mail just to try doing integration testing with Docker. So I created two Docker images based on the openjdk:8-jre image and copied my jars to them and started it. Based on my configuration (see below) it is working. They are talking to each other.

But as want to have multiple integration tests it is going to be tedious to build an image for each one and starting them. Also I don't know how to automate the results. But then I stumbled across TestContainers and it seems that this would be big help when implementing those tests.

So I started to port those tests to TestContainers using my POP3 Server image as a GenericContainer and starting my POP3 Client classes in the JUnit test method. I exposed the port 24999 which my POP3 Server is listening to. But when I try to connect to the server I get the following error:

com.sun.mail.util.MailConnectException: Couldn't connect to host, port: localhost, 32782; timeout -1;
  nested exception is:
    java.net.ConnectException: Connection refused
...

There is probably some setting I am missing in TestContainers. Could you please help me.

Here is the code I am using:

public class DockerPop3AutocryptKeyProvidingAndReceivingTest {
    @Test
    public void test() throws InterruptedException {
        GenericContainer container = new GenericContainer<>("immerfroehlich/emailfilter:latest")
                .withExposedPorts(24999);
        
        container.start();
        
        String host = container.getContainerIpAddress();
        String port = container.getFirstMappedPort().toString();

        //The following is simplified, but copied from the working jar used in the Docker Client image/container
        MyPOP3Client client = new MyPOP3Client(host, port);
        client.connect();
        
        container.stop();
    }
}

This is how I create my Docker image:

FROM openjdk:8-jre

ADD build/distributions/MyPOP3Server.tar . #This is where I have packed all the needed files to. It gets unpacked by Docker.
#EXPOSE 24999 #I tried both with and without this expose
WORKDIR /MyPOP3Server/bin
ENTRYPOINT ["sh","MyPOP3Server"] #Executes the shell script which runs java with my jar

This is a simplified version of the code that is running inside the Server Jar:

MyPOP3Server server = new MyPOP3Server();
server.listenToPort(24999);

Please tell me what am I missing. What is wrong here?

Thanks and kind regards.

like image 792
NoradX Avatar asked Jul 20 '26 13:07

NoradX


2 Answers

There's some good advice in other answers; I'll augment these with a couple of other tips:

As already suggested:

  • absolutely do add the LogConsumer so that you can see the container's log output - maybe something useful will appear there, now or in the future. It's always good to have.

  • set a breakpoint after the container is started, just before you start your client.

Additionally, I'd hope the following things make the difference. While paused at the breakpoint:

  • run docker ps -a in the terminal
  • firstly, check that your container is running and hasn't exited. If it has exited, have a look at the logs for the container from the terminal.
  • secondly, check the port mapping in the docker ps output. You should see something like 0.0.0.0:32768->24999/tcp (first port number is random, though).
  • evaluate container.getFirstMappedPort() in your IDE and check that the port number you get back is the same as the randomised exposed port. Unless you have a very unusual Docker installation on your local machine, this container should be reachable at localhost: + this port.
  • if you've got this far then it's likely that there's something wrong with either the container or the client code. You could try connecting a different client to the running container - even something like nc could help if you don't have another POP3 client handy.

Another thing to try is to run the container manually, just to reduce the amount of indirection taking place. The Testcontainers code snippet you've given is equivalent to:

docker run -p 24999 immerfroehlich/emailfilter:latest

You might find that this helps you divide up the problem space into smaller pieces.

like image 141
Richard North Avatar answered Jul 23 '26 03:07

Richard North


Thanks for all of your help. This led me towards the solution. It has been a combination of the missing WaitStrategy and problems with the port mapping.

Here is what I did: 1) In the MyPop3Server.listenToPort(String port) method I added a System.out.println:

public class MyPop3Server {
  public void listenToPort(String port) {
     //simplified: do initialization and listenToPort
     System.out.println("Awaiting Connection...");
  }
}

In my test I added a LogMessageWaitStrategy that listens for "Awaiting Connection"

GenericContainer container = new GenericContainer<>("immerfroehlich/emailfilter:latest")
   .waitingFor(Wait.forLogMessage("Awaiting Connection.*", 1))
   .withExposedPorts(24999);

2) I switched from container.getFirstMappedPort() to

container.getMappedPort(24999);

Here is the whole changed and working test code:

public class DockerPop3AutocryptKeyProvidingAndReceivingTest {
    @Test
    public void test() throws InterruptedException {
        GenericContainer container = new GenericContainer<>("immerfroehlich/emailfilter:latest")
                .waitingFor(Wait.forLogMessage("Awaiting Connection.*", 1))
                .withExposedPorts(24999);

        container.start();

        String host = container.getContainerIpAddress();
        String port = container.getMappedPort(24999).toString();

        //The following is simplified, but copied from the working jar used in the Docker Client image/container
        MyPOP3Client client = new MyPOP3Client(host, port);
        client.connect();

        container.stop();
    }
}

Thank you everyone.

like image 38
NoradX Avatar answered Jul 23 '26 03:07

NoradX



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!