This is an automated email from the ASF dual-hosted git repository.

davidzollo pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/seatunnel.git


The following commit(s) were added to refs/heads/dev by this push:
     new 64a3952245 [Improve][e2e] Improve the stability of sftp e2e testing 
e2e (#10972)
64a3952245 is described below

commit 64a3952245cfac6364aeb91ea79d0436d3b03c87
Author: zhiwei.niu <[email protected]>
AuthorDate: Sat May 30 13:04:16 2026 +0800

    [Improve][e2e] Improve the stability of sftp e2e testing e2e (#10972)
---
 .../e2e/connector/file/fstp/SftpFileIT.java        | 313 +++++++++++----------
 1 file changed, 169 insertions(+), 144 deletions(-)

diff --git 
a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-file-sftp-e2e/src/test/java/org/apache/seatunnel/e2e/connector/file/fstp/SftpFileIT.java
 
b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-file-sftp-e2e/src/test/java/org/apache/seatunnel/e2e/connector/file/fstp/SftpFileIT.java
index dc325c68c3..c11282f140 100644
--- 
a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-file-sftp-e2e/src/test/java/org/apache/seatunnel/e2e/connector/file/fstp/SftpFileIT.java
+++ 
b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-file-sftp-e2e/src/test/java/org/apache/seatunnel/e2e/connector/file/fstp/SftpFileIT.java
@@ -36,18 +36,14 @@ import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.TestTemplate;
 import org.testcontainers.containers.Container;
 import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.Wait;
 import org.testcontainers.lifecycle.Startables;
-import 
org.testcontainers.shaded.com.github.dockerjava.core.command.ExecStartResultCallback;
 
-import com.github.dockerjava.api.command.ExecCreateCmdResponse;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
@@ -59,14 +55,12 @@ import java.util.stream.Stream;
 @Slf4j
 public class SftpFileIT extends TestSuiteBase implements TestResource {
 
-    private static final String SFTP_IMAGE = "atmoz/sftp:latest";
+    private static final String SFTP_IMAGE = "atmoz/sftp:alpine-3.7";
 
     private static final String SFTP_CONTAINER_HOST = "sftp";
 
     private static final int SFTP_PORT = 22;
 
-    private static final int SFTP_BIND_PORT = 2222;
-
     private static final String SFTP_CONTAINER_HOME = "/home/seatunnel";
 
     private static final String USERNAME = "seatunnel";
@@ -84,10 +78,9 @@ public class SftpFileIT extends TestSuiteBase implements 
TestResource {
                         .withCommand(USERNAME + ":" + PASSWORD + ":::tmp")
                         .withNetwork(NETWORK)
                         .withNetworkAliases(SFTP_CONTAINER_HOST)
-                        .withExposedPorts(SFTP_PORT);
+                        .withExposedPorts(SFTP_PORT)
+                        .waitingFor(Wait.forListeningPort());
 
-        sftpContainer.setPortBindings(Collections.singletonList(SFTP_BIND_PORT 
+ ":" + SFTP_PORT));
-        sftpContainer.start();
         Startables.deepStart(Stream.of(sftpContainer)).join();
         log.info("Sftp container started");
 
@@ -132,7 +125,10 @@ public class SftpFileIT extends TestSuiteBase implements 
TestResource {
                 "/text/e2e.txt",
                 "/home/seatunnel/tmp/seatunnel/read/wildcard/e2e.txt",
                 sftpContainer);
-        sftpContainer.execInContainer("sh", "-c", "chown -R seatunnel 
/home/seatunnel/tmp/");
+        Container.ExecResult chownResult =
+                sftpContainer.execInContainer(
+                        "sh", "-c", "chown -R seatunnel /home/seatunnel/tmp/");
+        Assertions.assertEquals(0, chownResult.getExitCode(), 
chownResult.getStderr());
     }
 
     @TestTemplate
@@ -160,19 +156,19 @@ public class SftpFileIT extends TestSuiteBase implements 
TestResource {
                 "/text/e2e.txt",
                 
"/home/seatunnel/tmp/seatunnel/read/filter/text/name=tyrantlucifer/hobby=coding/e2e.txt",
                 sftpContainer);
-        sftpContainer.execInContainer("sh", "-c", "chown -R seatunnel 
/home/seatunnel/tmp/");
-
-        TestHelper helper = new TestHelper(container);
-        // -----filter based on the file directory at the same time, the 
expression needs to start
-        // with `path`--------
-        helper.execute("/json/sftp_to_access_for_json_path_filter.conf");
-
-        // -------filter based on file names, just simply write the regular 
file names--------
-        helper.execute("/json/sftp_to_access_for_json_name_filter.conf");
+        Container.ExecResult chownResult2 =
+                sftpContainer.execInContainer(
+                        "sh", "-c", "chown -R seatunnel /home/seatunnel/tmp/");
+        Assertions.assertEquals(0, chownResult2.getExitCode(), 
chownResult2.getStderr());
 
-        // delete path
         String filterPath = "/home/seatunnel/tmp/seatunnel/read/filter";
-        deleteFileFromContainer(filterPath);
+        try {
+            TestHelper helper = new TestHelper(container);
+            helper.execute("/json/sftp_to_access_for_json_path_filter.conf");
+            helper.execute("/json/sftp_to_access_for_json_name_filter.conf");
+        } finally {
+            deleteFileFromContainer(filterPath);
+        }
     }
 
     @TestTemplate
@@ -215,34 +211,51 @@ public class SftpFileIT extends TestSuiteBase implements 
TestResource {
         deleteFileFromContainer(homePath + sink01);
         deleteFileFromContainer(homePath + sink02);
         
helper.execute("/json/sftp_file_json_to_assert_with_multipletable.conf");
-        Assertions.assertEquals(getFileListFromContainer(homePath + 
sink01).size(), 1);
-        Assertions.assertEquals(getFileListFromContainer(homePath + 
sink02).size(), 1);
+        Awaitility.await()
+                .atMost(30, TimeUnit.SECONDS)
+                .pollInterval(2, TimeUnit.SECONDS)
+                .untilAsserted(
+                        () -> {
+                            Assertions.assertEquals(
+                                    1, getFileListFromContainer(homePath + 
sink01).size());
+                            Assertions.assertEquals(
+                                    1, getFileListFromContainer(homePath + 
sink02).size());
+                        });
     }
 
     @TestTemplate
     public void testSftpBinaryUpdateModeDistcp(TestContainer container)
             throws IOException, InterruptedException {
         resetUpdateTestPath();
-        putSftpFile(SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/update/src/test.bin", "abc");
-
-        TestHelper helper = new TestHelper(container);
-        helper.execute("/text/sftp_binary_update_distcp.conf");
-        Assertions.assertEquals(
-                "abc", readSftpFile(SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/update/dst/test.bin"));
-
-        // Make target newer with same length, distcp strategy should SKIP 
overwrite.
-        putSftpFile(SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/update/dst/test.bin", "zzz");
-        helper.execute("/text/sftp_binary_update_distcp.conf");
-        Assertions.assertEquals(
-                "zzz", readSftpFile(SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/update/dst/test.bin"));
-
-        // Change source length, distcp strategy should COPY overwrite.
-        putSftpFile(SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/update/src/test.bin", "abcd");
-        helper.execute("/text/sftp_binary_update_distcp.conf");
-        Assertions.assertEquals(
-                "abcd", readSftpFile(SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/update/dst/test.bin"));
-
-        deleteFileFromContainer(SFTP_CONTAINER_HOME + "/tmp/seatunnel/update");
+        try {
+            putSftpFile(SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/update/src/test.bin", "abc");
+
+            TestHelper helper = new TestHelper(container);
+            helper.execute("/text/sftp_binary_update_distcp.conf");
+            Assertions.assertEquals(
+                    "abc",
+                    readSftpFile(SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/update/dst/test.bin"));
+
+            // Make target newer with same length, distcp strategy should SKIP 
overwrite.
+            String srcPath = SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/update/src/test.bin";
+            String dstPath = SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/update/dst/test.bin";
+            long srcMtime = getSftpFileMtimeSeconds(srcPath);
+            waitUntilContainerTimeAfter(srcMtime);
+            putSftpFile(dstPath, "zzz");
+            helper.execute("/text/sftp_binary_update_distcp.conf");
+            Assertions.assertEquals(
+                    "zzz",
+                    readSftpFile(SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/update/dst/test.bin"));
+
+            // Change source length, distcp strategy should COPY overwrite.
+            putSftpFile(SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/update/src/test.bin", "abcd");
+            helper.execute("/text/sftp_binary_update_distcp.conf");
+            Assertions.assertEquals(
+                    "abcd",
+                    readSftpFile(SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/update/dst/test.bin"));
+        } finally {
+            deleteFileFromContainer(SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/update");
+        }
     }
 
     @TestTemplate
@@ -253,65 +266,73 @@ public class SftpFileIT extends TestSuiteBase implements 
TestResource {
     public void 
testSftpBinaryUpdateModeContinuousDiscoveryDistcp(TestContainer container)
             throws IOException, InterruptedException {
         resetContinuousTestPath();
-        putSftpFile(SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/continuous/src/test1.bin", "abc");
-
-        String jobId = String.valueOf(JobIdGenerator.newJobId());
-        CompletableFuture<Container.ExecResult> jobFuture =
-                CompletableFuture.supplyAsync(
-                        () -> {
-                            try {
-                                return container.executeJob(
-                                        
"/text/sftp_binary_update_distcp_continuous.conf", jobId);
-                            } catch (Exception e) {
-                                throw new RuntimeException(e);
-                            }
-                        });
-
-        Awaitility.await()
-                .atMost(60, TimeUnit.SECONDS)
-                .untilAsserted(
-                        () ->
-                                Assertions.assertEquals(
-                                        "abc",
-                                        readSftpFile(
-                                                SFTP_CONTAINER_HOME
-                                                        + 
"/tmp/seatunnel/continuous/dst/test1.bin")));
-
-        long firstMtimeSeconds =
-                getSftpFileMtimeSeconds(
-                        SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/continuous/dst/test1.bin");
-        Thread.sleep(2500);
-        long secondMtimeSeconds =
-                getSftpFileMtimeSeconds(
-                        SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/continuous/dst/test1.bin");
-        Assertions.assertEquals(
-                firstMtimeSeconds,
-                secondMtimeSeconds,
-                "Continuous discovery should skip unchanged files in update 
mode.");
-
-        putSftpFile(SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/continuous/src/test2.bin", "def");
-        Awaitility.await()
-                .atMost(60, TimeUnit.SECONDS)
-                .untilAsserted(
-                        () ->
-                                Assertions.assertEquals(
-                                        "def",
-                                        readSftpFile(
-                                                SFTP_CONTAINER_HOME
-                                                        + 
"/tmp/seatunnel/continuous/dst/test2.bin")));
-
-        Container.ExecResult cancelResult = container.cancelJob(jobId);
-        Assertions.assertEquals(0, cancelResult.getExitCode(), 
cancelResult.getStderr());
-
-        Container.ExecResult execResult;
         try {
-            execResult = jobFuture.get(120, TimeUnit.SECONDS);
-        } catch (Exception e) {
-            throw new RuntimeException("Wait continuous job exit failed.", e);
+            putSftpFile(SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/continuous/src/test1.bin", "abc");
+
+            String jobId = String.valueOf(JobIdGenerator.newJobId());
+            CompletableFuture<Container.ExecResult> jobFuture =
+                    CompletableFuture.supplyAsync(
+                            () -> {
+                                try {
+                                    return container.executeJob(
+                                            
"/text/sftp_binary_update_distcp_continuous.conf",
+                                            jobId);
+                                } catch (Exception e) {
+                                    throw new RuntimeException(e);
+                                }
+                            });
+
+            Awaitility.await()
+                    .atMost(120, TimeUnit.SECONDS)
+                    .pollInterval(2, TimeUnit.SECONDS)
+                    .untilAsserted(
+                            () ->
+                                    Assertions.assertEquals(
+                                            "abc",
+                                            readSftpFile(
+                                                    SFTP_CONTAINER_HOME
+                                                            + 
"/tmp/seatunnel/continuous/dst/test1.bin")));
+
+            String mtimePath = SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/continuous/dst/test1.bin";
+            long firstMtimeSeconds = getSftpFileMtimeSeconds(mtimePath);
+            Awaitility.await()
+                    .during(6, TimeUnit.SECONDS)
+                    .atMost(15, TimeUnit.SECONDS)
+                    .pollInterval(1, TimeUnit.SECONDS)
+                    .untilAsserted(
+                            () -> {
+                                long currentMtime = 
getSftpFileMtimeSeconds(mtimePath);
+                                Assertions.assertEquals(
+                                        firstMtimeSeconds,
+                                        currentMtime,
+                                        "Continuous discovery should skip 
unchanged files in update mode.");
+                            });
+
+            putSftpFile(SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/continuous/src/test2.bin", "def");
+            Awaitility.await()
+                    .atMost(120, TimeUnit.SECONDS)
+                    .pollInterval(2, TimeUnit.SECONDS)
+                    .untilAsserted(
+                            () ->
+                                    Assertions.assertEquals(
+                                            "def",
+                                            readSftpFile(
+                                                    SFTP_CONTAINER_HOME
+                                                            + 
"/tmp/seatunnel/continuous/dst/test2.bin")));
+
+            Container.ExecResult cancelResult = container.cancelJob(jobId);
+            Assertions.assertEquals(0, cancelResult.getExitCode(), 
cancelResult.getStderr());
+
+            Container.ExecResult execResult;
+            try {
+                execResult = jobFuture.get(120, TimeUnit.SECONDS);
+            } catch (Exception e) {
+                throw new RuntimeException("Wait continuous job exit failed.", 
e);
+            }
+            Assertions.assertEquals(0, execResult.getExitCode(), 
execResult.getStderr());
+        } finally {
+            deleteFileFromContainer(SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/continuous");
         }
-        Assertions.assertEquals(0, execResult.getExitCode(), 
execResult.getStderr());
-
-        deleteFileFromContainer(SFTP_CONTAINER_HOME + 
"/tmp/seatunnel/continuous");
     }
 
     @TestTemplate
@@ -324,27 +345,42 @@ public class SftpFileIT extends TestSuiteBase implements 
TestResource {
         String path2 = "/tmp/multiple_1/seatunnel/text/source_2";
         deleteFileFromContainer(homePath + path1);
         deleteFileFromContainer(homePath + path2);
-        Assertions.assertEquals(getFileListFromContainer(homePath + 
path1).size(), 0);
-        Assertions.assertEquals(getFileListFromContainer(homePath + 
path2).size(), 0);
+        Assertions.assertEquals(0, getFileListFromContainer(homePath + 
path1).size());
+        Assertions.assertEquals(0, getFileListFromContainer(homePath + 
path2).size());
         
helper.execute("/text/multiple_fake_to_sftp_file_text_recreate_schema.conf");
-        Assertions.assertEquals(getFileListFromContainer(homePath + 
path1).size(), 1);
-        Assertions.assertEquals(getFileListFromContainer(homePath + 
path2).size(), 1);
+        awaitFileCount(homePath + path1, 1);
+        awaitFileCount(homePath + path2, 1);
         
helper.execute("/text/multiple_fake_to_sftp_file_text_recreate_schema.conf");
-        Assertions.assertEquals(getFileListFromContainer(homePath + 
path1).size(), 1);
-        Assertions.assertEquals(getFileListFromContainer(homePath + 
path2).size(), 1);
+        awaitFileCount(homePath + path1, 1);
+        awaitFileCount(homePath + path2, 1);
         // test mult table and save_mode:CREATE_SCHEMA_WHEN_NOT_EXIST 
APPEND_DATA
         String path3 = "/tmp/multiple_2/seatunnel/text/source_1";
         String path4 = "/tmp/multiple_2/seatunnel/text/source_2";
         deleteFileFromContainer(homePath + path3);
         deleteFileFromContainer(homePath + path4);
-        Assertions.assertEquals(getFileListFromContainer(homePath + 
path3).size(), 0);
-        Assertions.assertEquals(getFileListFromContainer(homePath + 
path4).size(), 0);
+        Assertions.assertEquals(0, getFileListFromContainer(homePath + 
path3).size());
+        Assertions.assertEquals(0, getFileListFromContainer(homePath + 
path4).size());
         helper.execute("/text/multiple_fake_to_sftp_file_text_append.conf");
-        Assertions.assertEquals(getFileListFromContainer(homePath + 
path3).size(), 1);
-        Assertions.assertEquals(getFileListFromContainer(homePath + 
path4).size(), 1);
+        awaitFileCount(homePath + path3, 1);
+        awaitFileCount(homePath + path4, 1);
         helper.execute("/text/multiple_fake_to_sftp_file_text_append.conf");
-        Assertions.assertEquals(getFileListFromContainer(homePath + 
path3).size(), 2);
-        Assertions.assertEquals(getFileListFromContainer(homePath + 
path4).size(), 2);
+        awaitFileCount(homePath + path3, 2);
+        awaitFileCount(homePath + path4, 2);
+    }
+
+    private void awaitFileCount(String containerPath, int expectedCount) {
+        Awaitility.await()
+                .atMost(30, TimeUnit.SECONDS)
+                .pollInterval(2, TimeUnit.SECONDS)
+                .untilAsserted(
+                        () ->
+                                Assertions.assertEquals(
+                                        expectedCount,
+                                        
getFileListFromContainer(containerPath).size(),
+                                        "Expected "
+                                                + expectedCount
+                                                + " files in "
+                                                + containerPath));
     }
 
     private void resetUpdateTestPath() throws IOException, 
InterruptedException {
@@ -410,6 +446,18 @@ public class SftpFileIT extends TestSuiteBase implements 
TestResource {
         return catResult.getStdout() == null ? "" : 
catResult.getStdout().trim();
     }
 
+    private void waitUntilContainerTimeAfter(long epochSeconds) {
+        Awaitility.await()
+                .atMost(10, TimeUnit.SECONDS)
+                .pollInterval(200, TimeUnit.MILLISECONDS)
+                .until(
+                        () -> {
+                            Container.ExecResult r =
+                                    sftpContainer.execInContainer("sh", "-c", 
"date +%s");
+                            return Long.parseLong(r.getStdout().trim()) > 
epochSeconds;
+                        });
+    }
+
     private long getSftpFileMtimeSeconds(String containerPath)
             throws IOException, InterruptedException {
         Container.ExecResult result =
@@ -420,22 +468,12 @@ public class SftpFileIT extends TestSuiteBase implements 
TestResource {
 
     @SneakyThrows
     private List<String> getFileListFromContainer(String path) {
-        String command = "ls -1 " + path;
-        ExecCreateCmdResponse execCreateCmdResponse =
-                dockerClient
-                        .execCreateCmd(sftpContainer.getContainerId())
-                        .withCmd("sh", "-c", command)
-                        .withAttachStdout(true)
-                        .withAttachStderr(true)
-                        .exec();
-
-        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        dockerClient
-                .execStartCmd(execCreateCmdResponse.getId())
-                .exec(new ExecStartResultCallback(outputStream, System.err))
-                .awaitCompletion();
-
-        String output = new String(outputStream.toByteArray(), 
StandardCharsets.UTF_8).trim();
+        Container.ExecResult result = sftpContainer.execInContainer("sh", 
"-c", "ls -1 " + path);
+        if (result.getExitCode() != 0) {
+            log.info("ls failed for path {}: {}", path, result.getStderr());
+            return new ArrayList<>();
+        }
+        String output = result.getStdout() == null ? "" : 
result.getStdout().trim();
         List<String> fileList = new ArrayList<>();
         log.info("container path file list is :{}", output);
         String[] files = output.split("\n");
@@ -450,20 +488,7 @@ public class SftpFileIT extends TestSuiteBase implements 
TestResource {
 
     @SneakyThrows
     private void deleteFileFromContainer(String path) {
-        String command = "rm -rf " + path;
-        ExecCreateCmdResponse execCreateCmdResponse =
-                dockerClient
-                        .execCreateCmd(sftpContainer.getContainerId())
-                        .withCmd("sh", "-c", command)
-                        .withAttachStdout(true)
-                        .withAttachStderr(true)
-                        .exec();
-
-        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        dockerClient
-                .execStartCmd(execCreateCmdResponse.getId())
-                .exec(new ExecStartResultCallback(outputStream, System.err))
-                .awaitCompletion();
+        sftpContainer.execInContainer("sh", "-c", "rm -rf " + path);
     }
 
     @AfterAll

Reply via email to