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

apupier pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 7e959e4c42be CAMEL-25667: fix flaky FtpRecursiveDepth*IT tests
7e959e4c42be is described below

commit 7e959e4c42be8b18da1922fda373158e40806e28
Author: AurĂ©lien Pupier <[email protected]>
AuthorDate: Wed Oct 14 21:08:07 2026 +0200

    CAMEL-25667: fix flaky FtpRecursiveDepth*IT tests
    
    The three FtpRecursiveDepth*IT tests uploaded files to the FTP server
    inside the test method while the consumer route was already running.
    This created a race condition: the FTP consumer could start its first
    directory poll before all files had been uploaded, causing it to see
    only a partial file tree. Because the default post-processing strategy
    moves consumed files to a .camel/ subdirectory rather than deleting
    them, a subsequent poll could then pick up previously-consumed files
    again, resulting in duplicate or missing messages in the mock endpoint.
    
    Fix: mark each consumer route autoStartup(false), upload all test
    files synchronously first, then start the route explicitly via
    context.getRouteController().startRoute(...). This ensures the
    consumer's first poll always sees the complete, stable directory tree.
    
    The same pattern is already used by FtpSimpleConsumeAbsoluteIT,
    FtpSimpleConsumeStreamingWithMultipleFilesIT, and others in the same
    test suite. FromFtpRecursiveNoopIT was already safe because it uploads
    in doPostSetup() before routes start.
    
    Co-authored-by: IBM Bob 2.2.1 <[email protected]>
    Signed-off-by: AurĂ©lien Pupier <[email protected]>
---
 .../file/remote/integration/FtpRecursiveDepth2IT.java   | 17 ++++++++++-------
 .../file/remote/integration/FtpRecursiveDepth3IT.java   | 13 +++++++++----
 .../file/remote/integration/FtpRecursiveDepthIT.java    | 13 +++++++++----
 3 files changed, 28 insertions(+), 15 deletions(-)

diff --git 
a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/integration/FtpRecursiveDepth2IT.java
 
b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/integration/FtpRecursiveDepth2IT.java
index 91685807392c..e5ea4b462307 100644
--- 
a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/integration/FtpRecursiveDepth2IT.java
+++ 
b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/integration/FtpRecursiveDepth2IT.java
@@ -16,8 +16,6 @@
  */
 package org.apache.camel.component.file.remote.integration;
 
-import java.util.concurrent.TimeUnit;
-
 import org.apache.camel.Exchange;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
@@ -31,9 +29,8 @@ public class FtpRecursiveDepth2IT extends 
FtpServerTestSupport {
 
     @Test
     public void testDepthMin2Max99() throws Exception {
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedBodiesReceivedInAnyOrder("a2", "b2", "a3", "b3");
-
+        // Upload all files before starting the consumer to avoid a race where
+        // the route picks up files mid-upload and produces inconsistent 
results.
         
template.sendBodyAndHeader("ftp://admin@localhost:{{ftp.server.port}}/depth2?password=admin";,
 "a", Exchange.FILE_NAME,
                 "a.txt");
         
template.sendBodyAndHeader("ftp://admin@localhost:{{ftp.server.port}}/depth2?password=admin";,
 "b", Exchange.FILE_NAME,
@@ -47,7 +44,12 @@ public class FtpRecursiveDepth2IT extends 
FtpServerTestSupport {
         
template.sendBodyAndHeader("ftp://admin@localhost:{{ftp.server.port}}/depth2/bar/foo?password=admin";,
 "b3",
                 Exchange.FILE_NAME, "b3.txt");
 
-        MockEndpoint.assertIsSatisfied(context, 20, TimeUnit.SECONDS);
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedBodiesReceivedInAnyOrder("a2", "b2", "a3", "b3");
+
+        context.getRouteController().startRoute("ftp-recursive-depth2");
+
+        MockEndpoint.assertIsSatisfied(context);
     }
 
     @Override
@@ -55,7 +57,8 @@ public class FtpRecursiveDepth2IT extends 
FtpServerTestSupport {
         return new RouteBuilder() {
             @Override
             public void configure() {
-                from(getFtpUrl() + 
"&minDepth=2&maxDepth=99").convertBodyTo(String.class).to("mock:result");
+                from(getFtpUrl() + 
"&minDepth=2&maxDepth=99").routeId("ftp-recursive-depth2").autoStartup(false)
+                        .convertBodyTo(String.class).to("mock:result");
             }
         };
     }
diff --git 
a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/integration/FtpRecursiveDepth3IT.java
 
b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/integration/FtpRecursiveDepth3IT.java
index 9a1f22ecfefe..89a0fd1c51b0 100644
--- 
a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/integration/FtpRecursiveDepth3IT.java
+++ 
b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/integration/FtpRecursiveDepth3IT.java
@@ -29,9 +29,8 @@ public class FtpRecursiveDepth3IT extends 
FtpServerTestSupport {
 
     @Test
     public void testDepthMin1Max1() throws Exception {
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedBodiesReceivedInAnyOrder("a", "b");
-
+        // Upload all files before starting the consumer to avoid a race where
+        // the route picks up files mid-upload and produces inconsistent 
results.
         
template.sendBodyAndHeader("ftp://admin@localhost:{{ftp.server.port}}/depth3?password=admin";,
 "a", Exchange.FILE_NAME,
                 "a.txt");
         
template.sendBodyAndHeader("ftp://admin@localhost:{{ftp.server.port}}/depth3?password=admin";,
 "b", Exchange.FILE_NAME,
@@ -45,6 +44,11 @@ public class FtpRecursiveDepth3IT extends 
FtpServerTestSupport {
         
template.sendBodyAndHeader("ftp://admin@localhost:{{ftp.server.port}}/depth3/bar/foo?password=admin";,
 "b3",
                 Exchange.FILE_NAME, "b.txt");
 
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedBodiesReceivedInAnyOrder("a", "b");
+
+        context.getRouteController().startRoute("ftp-recursive-depth3");
+
         MockEndpoint.assertIsSatisfied(context);
     }
 
@@ -53,7 +57,8 @@ public class FtpRecursiveDepth3IT extends 
FtpServerTestSupport {
         return new RouteBuilder() {
             @Override
             public void configure() {
-                from(getFtpUrl() + 
"&minDepth=1&maxDepth=1").convertBodyTo(String.class).to("mock:result");
+                from(getFtpUrl() + 
"&minDepth=1&maxDepth=1").routeId("ftp-recursive-depth3").autoStartup(false)
+                        .convertBodyTo(String.class).to("mock:result");
             }
         };
     }
diff --git 
a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/integration/FtpRecursiveDepthIT.java
 
b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/integration/FtpRecursiveDepthIT.java
index 0e71eb9ca7b6..abd4af82d460 100644
--- 
a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/integration/FtpRecursiveDepthIT.java
+++ 
b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/integration/FtpRecursiveDepthIT.java
@@ -29,9 +29,8 @@ public class FtpRecursiveDepthIT extends FtpServerTestSupport 
{
 
     @Test
     public void testDepth() throws Exception {
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedBodiesReceivedInAnyOrder("a2", "b2");
-
+        // Upload all files before starting the consumer to avoid a race where
+        // the route picks up files mid-upload and produces inconsistent 
results.
         
template.sendBodyAndHeader("ftp://admin@localhost:{{ftp.server.port}}/depth?password=admin";,
 "a", Exchange.FILE_NAME,
                 "a.txt");
         
template.sendBodyAndHeader("ftp://admin@localhost:{{ftp.server.port}}/depth?password=admin";,
 "b", Exchange.FILE_NAME,
@@ -47,6 +46,11 @@ public class FtpRecursiveDepthIT extends 
FtpServerTestSupport {
         
template.sendBodyAndHeader("ftp://admin@localhost:{{ftp.server.port}}/depth/bar/foo?password=admin";,
 "b3",
                 Exchange.FILE_NAME, "b.txt");
 
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedBodiesReceivedInAnyOrder("a2", "b2");
+
+        context.getRouteController().startRoute("ftp-recursive-depth");
+
         // only expect 2 of the 6 sent, those at depth 2
         MockEndpoint.assertIsSatisfied(context);
     }
@@ -56,7 +60,8 @@ public class FtpRecursiveDepthIT extends FtpServerTestSupport 
{
         return new RouteBuilder() {
             @Override
             public void configure() {
-                from(getFtpUrl() + 
"&minDepth=2&maxDepth=2").convertBodyTo(String.class).to("mock:result");
+                from(getFtpUrl() + 
"&minDepth=2&maxDepth=2").routeId("ftp-recursive-depth").autoStartup(false)
+                        .convertBodyTo(String.class).to("mock:result");
             }
         };
     }

Reply via email to