Я хочу иметь автоматические тесты для тестирования команд импорта из источника данных A (оракул) в источник данных B (postgres). Оба источника данных должны быть созданы с помощью тестконтейнеров.

Базовая настройка выполнена, но проблема в следующем:

testcontainers oracleContainer запускается до изменения точки входа, определенной в Dokerfile, для завершения и создания пользователя, необходимого для тестов.

После запуска контейнера выполняется несколько сценариев sql, которые создают таблицы и заполняют их данными. Эти сценарии терпят неудачу, потому что пользователь, упомянутый в сценарии, еще не создан.

testcontainers не ожидает полной настройки.


Я настроил контейнер следующим образом:

        OracleContainer oracleContainer = new OracleContainer("webdizz/oracle-xe-11g-sa:latest")
            .withStartupTimeoutSeconds(10000)
            .withEnv("DATABASES", "xyz");

База данных определенно создана, но через довольно длительное время (протестировано путем бесконечного запуска теста и проверки базы данных с помощью docker exec)

Я попытался установить стратегию ожидания для контейнера несколькими способами, например так:

        oracleContainer.setWaitStrategy(new LogMessageWaitStrategy().withRegEx("*.Enjoy!*"));

Но это ни к чему не привело.


Проверяя журналы с:

Slf4jLogConsumer logConsumer = new Slf4jLogConsumer(LOGGER);
    oracleContainer.followOutput(logConsumer);

Я вижу, что тестконтейнеры никогда не дожидаются его завершения.

Все, что я нашел в Интернете об этой «ошибке» или «проблеме», это BugReport на github: https://github.com/testcontainers/testcontainers-java/issues/1292

И кажется, что пользователь даже использует тот же контейнер, что и я. Однако решение, упомянутое в проблеме, не сработало для меня.

2
Simon 16 Авг 2019 в 21:45

2 ответа

Лучший ответ

Я решил эту проблему, создав сценарий (фактически два, но его можно объединить в один), который проверяет, существует ли пользователь базы данных «XYZ», и возвращает 0, если он существует.

< Сильный > wait_check.sh :

#!/usr/bin/env bash
while :
do
    echo "waiting for user to exist"
    if $(/bin/bash /check_db_user.sh | grep -q XYZ); then
        echo "user XYZ exists"
        exit 0
    fi
done

И check_db_user.sh :

#!/usr/bin/env bash
sqlplus -s /nolog <<EOF
connect username/password
select username from dba_users where username = 'XYZ';
quit
EOF

И затем я запускаю wait_check.sh с помощью:

oracleContainer.copyFileToContainer(
        MountableFile.forClasspathResource("/helper/wait_check.sh"),
        "/wait_check.sh");
oracleContainer.copyFileToContainer(
        MountableFile.forClasspathResource("/helper/check_db_user.sh"),
        "/check_db_user.sh");

try {
    Container.ExecResult result = oracleContainer.execInContainer("./wait_check.sh");
    log.debug(result.getStdout());
} catch (IOException | InterruptedException e) {
    log.error(e.getMessage());
}

Это работает, потому что oracleContainer.execInContainer не истекает по умолчанию. Он просто ждет, пока все, что вы делаете, не закончится. Я обнаружил это во время отладки, и решение работает для меня.

0
Simon 20 Авг 2019 в 12:14

Вы можете попробовать переопределить getTestQueryString OracleContainer

OracleContainer oracleContainer = new MyOracleContainer("webdizz/oracle-xe-11g-sa:latest")

...

public static class MyOracleContainer extends OracleContainer {
    public MyOracleContainer(String dockerImageName) {
        super(dockerImageName);
    }

    @Override
    public String getTestQueryString() {
        return "SELECT username FROM dba_users WHERE username = 'XYZ'";
    }
}
0
Madis 24 Окт 2019 в 09:34