1

I'm trying to implement a JUnit (v4.13.2) test using testcontainers (v1.16.2) to better test our DAO/JPA classes. I'm using the centos/postgresql-96-centos7 official docker image and I can run it on the cmd line just fine using: docker run -d --name postgres -e POSTGRESQL_USER=user -e POSTGRESQL_PASSWORD=pass -e POSTGRES_DATABASE=db -p 5432:5432 centos/postgresql-96-centos7. I removed the container prior to running the unit test to avoid any conflicts in my docker environment. However, when I run my test, I consistently get the following errors:

java.lang.ExceptionInInitializerError
Caused by: org.testcontainers.containers.ContainerLaunchException: Container startup failed
Caused by: org.rnorth.ducttape.RetryCountExceededException: Retry limit hit with exception
Caused by: org.testcontainers.containers.ContainerLaunchException: Could not create/start container
Caused by: java.lang.IllegalStateException: Container exited with code 2

I have tried increasing the timeout value to 5 mins and simplified to the JUnit4 testing pattern (to avoid running a mixed testing environment) to no avail. I'm only including the code for the abstract class because it is throwing the exception before calling POSTGRESQL_CONTAINER.start().

public abstract class AbstractRdbmsTest {
    private static final String DOCKER_IMAGE_NAME = "centos/postgresql-96-centos7";
    private static final String POSTGRESQL_USER = "user";
    private static final String POSTGRESQL_PASSWORD = "pass";
    private static final String POSTGRESQL_DATABASE = "db";

    protected static final PostgreSQLContainer POSTGRESQL_CONTAINER;

    static {
        DockerImageName imgName = DockerImageName.parse(DOCKER_IMAGE_NAME).asCompatibleSubstituteFor("postgres");

        POSTGRESQL_CONTAINER = (PostgreSQLContainer) new PostgreSQLContainer(imgName)
                .withDatabaseName(POSTGRESQL_DATABASE)
                .withUsername(POSTGRESQL_USER)
                .withPassword(POSTGRESQL_PASSWORD)
                .withExposedPorts(PostgreSQLContainer.POSTGRESQL_PORT);

        POSTGRESQL_CONTAINER.start();
    }
}

EDIT: Local Docker Env: Client/Server: Docker Engine - Community v20.10.7

Sean Smitz
  • 31
  • 1
  • 6
  • Do you try using the empty constructor (PostgreSQLContainer()) or DOCKER_IMAGE_NAME except imgName? – Valentyn Hruzytskyi Dec 01 '21 at 16:19
  • Both the `PostgreSQLContainer()` and `PostgreSQLContainer(String imageName)` constructors are now deprecated; so I avoided using them. Stepping through the code: it appears to find the image just fine, but for whatever reason it doesn't seem to think it is starting up correctly. – Sean Smitz Dec 01 '21 at 17:13
  • It seems that centos/postgresql-96-centos7 image is not compatible with testcontainers, if you take a look at [PostgreSQLContainer.java](https://github.com/testcontainers/testcontainers-java/blob/master/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java) you can find that PostgreSQLContainer.java sets another environment variables (POSTGRES_USER vs POSTGRESQL_USER) and expects that "database system is ready to accept connections" messages appears in the container logs twice. – Andrey B. Panfilov Dec 01 '21 at 17:52
  • Good catch. I'm going to dig further into creating an image and see if I can wrap this image and provide the correct environment. Although, I'm not sure how I can echo LOG messages... EDIT: Might be best for me to use a GenericContainer and construct the JDBC URL... PITA. – Sean Smitz Dec 01 '21 at 18:03

1 Answers1

2

So as stated above, what appears to have gotten around the problem is the following:

public abstract class AbstractRdbmsTest {
    private static final String DOCKER_IMAGE_NAME = "centos/postgresql-96-centos7";
    private static final String POSTGRESQL_USER = "user";
    private static final String POSTGRESQL_PASSWORD = "pass";
    private static final String POSTGRESQL_DATABASE = "db";

    protected static final PostgreSQLContainer CONTAINER;

    static {
        DockerImageName imgName = DockerImageName.parse(DOCKER_IMAGE_NAME).asCompatibleSubstituteFor("postgres");

        CONTAINER = (PostgreSQLContainer) new PostgreSQLContainer(imgName)
                .withDatabaseName(POSTGRESQL_DATABASE)
                .withUsername(POSTGRESQL_USER)
                .withPassword(POSTGRESQL_PASSWORD)
                .withEnv("POSTGRESQL_DATABASE", POSTGRESQL_DATABASE)
                .withEnv("POSTGRESQL_USER", POSTGRESQL_USER)
                .withEnv("POSTGRESQL_PASSWORD", POSTGRESQL_PASSWORD)
                .withExposedPorts(PostgreSQLContainer.POSTGRESQL_PORT);

        CONTAINER.setWaitStrategy(Wait.defaultWaitStrategy()
                .withStartupTimeout(Duration.of(60, SECONDS)));

        CONTAINER.start();
    }
}

Added the correct environment variables and changed the wait strategy. As a note: Apparently, the image I'm using is more non-standard than I realized. The official container may not need the change to the wait strategy.

Sean Smitz
  • 31
  • 1
  • 6