testcontainers контейнер базы данных Oracle запускается до создания пользователя базы данных

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

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

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);

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

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

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


person Simon    schedule 16.08.2019    source источник


Ответы (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 не истекает по умолчанию. Он просто ждет, пока все, что вы делаете, не закончится. Я обнаружил это во время отладки, и решение мне подходит.

person Simon    schedule 20.08.2019

Вы можете попробовать переопределить 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'";
    }
}
person Madis    schedule 24.10.2019