Home > Back-end >  Use PostgreSQLContainer with image on-the-fly in testcontainers
Use PostgreSQLContainer with image on-the-fly in testcontainers

Time:08-01

Goal

I want to use customized PostgreSQL image with locale support with test containers.

On postgres side

I prepared Dockerfile as described in postgres image documentation:

You can extend the Debian-based images with a simple Dockerfile to set a different locale. The following example will set the default locale to de_DE.utf8:

FROM postgres:14.3

RUN localedef -i de_DE -c -f UTF-8 -A /usr/share/locale/locale.alias de_DE.UTF-8

ENV LANG de_DE.utf8

So essentially nothing changes in the way this image works, but has some more capabilities in terms of locale support.

On testcontainers side

I wanted to use it as described in testcontainers documentation:

Simply pass a configured instance of ImageFromDockerfile as a constructor parameter to GenericContainer. Testcontainers will docker build a temporary container image, and will use it when creating the container.

public GenericContainer dslContainer = new GenericContainer(
new ImageFromDockerfile()
        .withFileFromString("folder/someFile.txt", "hello")
        .withFileFromClasspath("test.txt", "mappable-resource/test-resource.txt")
        .withFileFromClasspath("Dockerfile", "mappable-dockerfile/Dockerfile"))

Problem

In examples above testcontainers uses GenericContainer. GenericContainer exposes constructor public GenericContainer(final Future<String> image), what allows it to be used with ImageFromDockerfile. Sadly PostgreSQLContainer does not provide such constructor but I still want to use this class because it has several internal setups to support postgres well. There are two constructors in PostgreSQLContainer but they only accept image name.

Only solution I could think of was to essentially make a local copy of original PostgreSQLContainer and add missing constructor. That seems to work fine but it is a dirty hack for obvious reasons.

Question

My question is: am I missing some other way to accomplish the task with tools testcontainers provide? Or is it an area of improvement to add such public constructor in testcontainers?

CodePudding user response:

I believe the solution would be:

import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.utility.DockerImageName;

import java.net.URI;
import java.nio.file.Paths;
import java.time.Duration;

import static java.time.temporal.ChronoUnit.SECONDS;

public class Demo {

    public static void main(String[] args) throws Exception {
        // the most buggy part - need to investigate
        // how to work properly with ImageFromDockerfile
        URI path = Demo.class.getResource("/PostgreSQLde").toURI();
        ImageFromDockerfile image = new ImageFromDockerfile()
                .withDockerfile(Paths.get(path));
        DockerImageName imageName = DockerImageName.parse(image.get())
                .asCompatibleSubstituteFor(PostgreSQLContainer.IMAGE);
        new PostgreSQLContainer<>(imageName)
                .waitingFor(new LogMessageWaitStrategy()
                        // oops
                        .withRegEx(".*Datenbanksystem ist bereit, um Verbindungen anzunehmen.*\\s")
                        .withTimes(2)
                        .withStartupTimeout(Duration.of(60, SECONDS)))
                .start();
    }

}
  • Related