testcontainers oracle 数据库容器在创建数据库用户之前启动

testcontainers oracle database container starts before database user is created

我想进行自动化测试,以测试从数据源 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 从不等待它完成。

我在网上找到的关于 "bug" 或 "problem" 的所有信息都是 github 上的错误报告: https://github.com/testcontainers/testcontainers-java/issues/1292

似乎用户甚至使用与我相同的容器。但是问题中提到的解决方案对我不起作用。

我通过创建一个脚本(实际上是两个,但可以放在一个中)来解决这个问题,该脚本检查数据库用户 "XYZ" 是否存在,如果存在则 returns 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 默认情况下不会超时。它只是等到你所做的一切完成。 我在调试时发现了这一点,该解决方案对我有用。

您可以尝试覆盖 OracleContainer 的 getTestQueryString

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'";
    }
}