You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Testcontainers FTP容器与真实服务器路径导航不一致问题求助

解决Testcontainers FTP容器与真实服务器路径导航不一致的问题

问题描述

测试连接公共FTP并获取文件名的类时,遇到目录结构相同但Testcontainers FTP容器与真实服务器路径导航行为不一致的情况:

  • 真实服务器中,调用ftp.changeWorkingDirectory("/out/published")可成功切换目录;但在Testcontainers容器中该方法返回false,必须改用相对路径ftp.changeWorkingDirectory("out/published")才能生效。
  • 真实服务器上执行ftp.listNames("/out/published/tverskaya_obl/purchaseNotice/daily")能正常获取文件列表;但容器中仅能使用相对路径ftp.listNames("tverskaya_obl/purchaseNotice/daily")成功。

测试代码

创建Testcontainers容器和目录的代码如下:

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@SpringBootTest(properties = "ftp.host = localhost")
class PurchaseFZ223FtpServiceTest {

    private static final int PORT = 21;
    private static final String USER = "";
    private static final String PASSWORD = "";

    private static final int PASSIVE_MODE_PORT = 21000;

    @Autowired
    FtpService ftpService;

    private static final FixedHostPortGenericContainer ftp = new FixedHostPortGenericContainer<>(
            "delfer/alpine-ftp-server:latest")
            .withFixedExposedPort(PASSIVE_MODE_PORT, PASSIVE_MODE_PORT)
            .withExposedPorts(PORT)
            .withEnv("USERS", USER + "|" + PASSWORD)
            .withEnv("MIN_PORT", String.valueOf(PASSIVE_MODE_PORT))
            .withEnv("MAX_PORT", String.valueOf(PASSIVE_MODE_PORT));

    @BeforeAll
    void init() throws NoSuchFieldException, IllegalAccessException, IOException {
        ftp.start();
  
        FTPClient client =new FTPClient();
        client.connect("localhost", ftp.getMappedPort(PORT));
        client.enterLocalPassiveMode();
        client.login(USER, PASSWORD);
        client.makeDirectory("out");
        client.makeDirectory("out/published");
        client.makeDirectory("out/published/tverskaya_obl");
        client.makeDirectory("out/published/tverskaya_obl/purchaseNotice");
        client.makeDirectory("out/published/tverskaya_obl/purchaseNotice/daily");
        client.changeWorkingDirectory("out/published");
        client.storeFile("list_regions.txt", new ByteArrayInputStream("tverskaya_obl".getBytes(StandardCharsets.UTF_8)));
        client.changeWorkingDirectory("tverskaya_obl/purchaseNotice/daily");
        client.storeFile("purchaseNotice_Tverskaya_obl_20221209_000000_20221209_235959_daily_001.xml.txt", new ByteArrayInputStream("test".getBytes(StandardCharsets.UTF_8)));
    }
}

问题原因

你使用的delfer/alpine-ftp-server容器默认会给用户开启chroot jail限制,用户登录后默认处于专属的家目录(如/home/<user>),所有路径都会被限制在这个目录内。而真实FTP服务器可能未开启chroot,或者根目录直接映射到系统根路径,因此绝对路径/out/published在真实服务器中指向系统根下的目录,在容器中却会被解析为用户家目录外的路径,自然无法找到。

解决办法

方案1:修改容器配置,禁用chroot限制

添加CHROOT=false环境变量,关闭容器的chroot限制,让用户登录后直接处于系统根目录,这样容器的路径行为就和真实服务器一致:

private static final FixedHostPortGenericContainer ftp = new FixedHostPortGenericContainer<>(
        "delfer/alpine-ftp-server:latest")
        .withFixedExposedPort(PASSIVE_MODE_PORT, PASSIVE_MODE_PORT)
        .withExposedPorts(PORT)
        .withEnv("USERS", USER + "|" + PASSWORD)
        .withEnv("MIN_PORT", String.valueOf(PASSIVE_MODE_PORT))
        .withEnv("MAX_PORT", String.valueOf(PASSIVE_MODE_PORT))
        .withEnv("CHROOT", "false"); // 新增该行禁用chroot

方案2:统一测试中的路径处理逻辑

若不想修改容器配置,可在测试代码中统一使用相对路径,或者先获取用户当前工作目录,再基于该目录构建路径:

// 登录后获取当前工作目录
String currentWorkingDir = client.printWorkingDirectory();
// 后续操作统一使用相对路径,或基于currentWorkingDir拼接绝对路径

内容的提问来源于stack exchange,提问作者user19282140

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 13:40:27