You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2022/05/02 18:40:31 UTC

[camel-spring-boot] branch main updated: CAMEL-17993 Add tests in camel-ftp-starter (#550)

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

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-spring-boot.git


The following commit(s) were added to refs/heads/main by this push:
     new 570f8bd91ce CAMEL-17993 Add tests in camel-ftp-starter (#550)
570f8bd91ce is described below

commit 570f8bd91cead1cb4caecf2ef4ceebd58a314096
Author: JiriOndrusek <on...@gmail.com>
AuthorDate: Mon May 2 20:40:26 2022 +0200

    CAMEL-17993 Add tests in camel-ftp-starter (#550)
---
 components-starter/camel-ftp-starter/pom.xml       |  47 +++++
 .../camel-ftp-starter/src/test/data/bar.xml        |  20 +++
 .../camel-ftp-starter/src/test/data/foo.xml        |  20 +++
 .../src/test/data/ftpbinarytest/logo.jpeg          | Bin 0 -> 10249 bytes
 .../src/test/data/ftpbinarytest/logo1.jpeg         | Bin 0 -> 10249 bytes
 .../src/test/data/ftpbinarytest/logo2.png          | Bin 0 -> 93934 bytes
 .../src/test/data/ftpbinarytest/logo3.jpeg         | Bin 0 -> 5488717 bytes
 .../file/remote/springboot/AbstractBaseFtp.java    |  97 +++++++++++
 .../file/remote/springboot/ftp/BaseFtp.java        |  33 ++++
 .../remote/springboot/ftp/FromFtpFilterTest.java   | 105 +++++++++++
 .../ftp/FromFtpMoveFileRecursiveTest.java          |  90 ++++++++++
 .../springboot/ftp/FromFtpToBinaryFileTest.java    | 113 ++++++++++++
 .../remote/springboot/ftp/FtpAnonymousTest.java    |  82 +++++++++
 .../ftp/FtpConsumerMaxMessagesPerPollTest.java     |  93 ++++++++++
 .../remote/springboot/ftp/FtpEmbeddedService.java  | 193 +++++++++++++++++++++
 .../springboot/ftp/FtpProducerConcurrentTest.java  | 100 +++++++++++
 ...FtpSimpleConsumeStreamingStepwiseFalseTest.java |  97 +++++++++++
 .../FtpSimpleConsumeStreamingStepwiseTrueTest.java |  58 +++++++
 .../remote/springboot/ftp/FtpSoTimeoutTest.java    | 119 +++++++++++++
 .../remote/springboot/ftps/BaseFtpsClientAuth.java |  18 ++
 .../ftps/BaseFtpsImplicitClientAuth.java           |  18 ++
 .../FileToFtpsImplicitSSLWithClientAuthTest.java   |  80 +++++++++
 ...leToFtpsWithCustomTrustStorePropertiesTest.java |  79 +++++++++
 .../springboot/ftps/FtpsEmbeddedService.java       | 101 +++++++++++
 .../ftps/FtpsImplicitEmbeddedService.java          | 101 +++++++++++
 .../file/remote/springboot/ftps/FtpsTest.java      |  78 +++++++++
 .../file/remote/springboot/sftp/BaseSftp.java      |  36 ++++
 .../sftp/SftpConsumerLocalWorkDirectoryTest.java   | 127 ++++++++++++++
 .../springboot/sftp/SftpEmbeddedService.java       | 174 +++++++++++++++++++
 .../sftp/SftpKeyExchangeProtocolsTest.java         | 140 +++++++++++++++
 .../springboot/sftp/SftpSetOperationsTest.java     |  56 ++++++
 .../sftp/SftpSimpleProduceThroughProxyTest.java    | 147 ++++++++++++++++
 .../springboot/sftp/SftpUseListFalseTest.java      |  90 ++++++++++
 .../src/test/resources/hostkey.pem                 |  15 ++
 .../src/test/resources/readme.txt                  |   1 +
 .../src/test/resources/server.jks                  | Bin 0 -> 2421 bytes
 36 files changed, 2528 insertions(+)

diff --git a/components-starter/camel-ftp-starter/pom.xml b/components-starter/camel-ftp-starter/pom.xml
index c93e589ac81..a8b22c895b1 100644
--- a/components-starter/camel-ftp-starter/pom.xml
+++ b/components-starter/camel-ftp-starter/pom.xml
@@ -39,6 +39,53 @@
       <artifactId>camel-ftp</artifactId>
       <version>${camel-version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.ftpserver</groupId>
+      <artifactId>ftpserver-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.ftpserver</groupId>
+      <artifactId>ftplet-api</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-test-infra-ftp</artifactId>
+      <version>${camel-version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <!-- for testing sftp -->
+    <dependency>
+      <groupId>org.apache.sshd</groupId>
+      <artifactId>sshd-sftp</artifactId>
+      <version>${sshd-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.sshd</groupId>
+      <artifactId>sshd-scp</artifactId>
+      <version>${sshd-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <!-- for testing sftp through http proxy -->
+    <dependency>
+      <groupId>org.littleshoot</groupId>
+      <artifactId>littleproxy</artifactId>
+      <version>1.1.2</version>
+      <scope>test</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>log4j</groupId>
+          <artifactId>log4j</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.slf4j</groupId>
+          <artifactId>slf4j-log4j12</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
     <!--START OF GENERATED CODE-->
     <dependency>
       <groupId>org.apache.camel.springboot</groupId>
diff --git a/components-starter/camel-ftp-starter/src/test/data/bar.xml b/components-starter/camel-ftp-starter/src/test/data/bar.xml
new file mode 100644
index 00000000000..4c768881014
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/data/bar.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<hello>bar</hello>
diff --git a/components-starter/camel-ftp-starter/src/test/data/foo.xml b/components-starter/camel-ftp-starter/src/test/data/foo.xml
new file mode 100644
index 00000000000..ce3c19fd1db
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/data/foo.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<hello>foo</hello>
diff --git a/components-starter/camel-ftp-starter/src/test/data/ftpbinarytest/logo.jpeg b/components-starter/camel-ftp-starter/src/test/data/ftpbinarytest/logo.jpeg
new file mode 100644
index 00000000000..b635017d1e2
Binary files /dev/null and b/components-starter/camel-ftp-starter/src/test/data/ftpbinarytest/logo.jpeg differ
diff --git a/components-starter/camel-ftp-starter/src/test/data/ftpbinarytest/logo1.jpeg b/components-starter/camel-ftp-starter/src/test/data/ftpbinarytest/logo1.jpeg
new file mode 100644
index 00000000000..b635017d1e2
Binary files /dev/null and b/components-starter/camel-ftp-starter/src/test/data/ftpbinarytest/logo1.jpeg differ
diff --git a/components-starter/camel-ftp-starter/src/test/data/ftpbinarytest/logo2.png b/components-starter/camel-ftp-starter/src/test/data/ftpbinarytest/logo2.png
new file mode 100644
index 00000000000..5389aa856f4
Binary files /dev/null and b/components-starter/camel-ftp-starter/src/test/data/ftpbinarytest/logo2.png differ
diff --git a/components-starter/camel-ftp-starter/src/test/data/ftpbinarytest/logo3.jpeg b/components-starter/camel-ftp-starter/src/test/data/ftpbinarytest/logo3.jpeg
new file mode 100644
index 00000000000..d8884435da9
Binary files /dev/null and b/components-starter/camel-ftp-starter/src/test/data/ftpbinarytest/logo3.jpeg differ
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/AbstractBaseFtp.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/AbstractBaseFtp.java
new file mode 100644
index 00000000000..cdae4306210
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/AbstractBaseFtp.java
@@ -0,0 +1,97 @@
+package org.apache.camel.component.file.remote.springboot;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.Assertions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import static org.apache.camel.language.simple.SimpleLanguage.simple;
+
+public abstract class AbstractBaseFtp {
+    protected static final String AUTH_VALUE_SSL = "SSLv3";
+    protected static final String AUTH_VALUE_TLS = "TLSv1.2";
+
+    @Autowired
+    protected CamelContext context;
+
+    @Autowired
+    protected ProducerTemplate template;
+
+    protected abstract int getPort();
+
+    protected void assertMockEndpointsSatisfied() throws InterruptedException {
+        MockEndpoint.assertIsSatisfied(this.context);
+    }
+
+    protected void sendFile(String url, Object body, String fileName) {
+        template.sendBodyAndHeader(url, body, Exchange.FILE_NAME, simple(fileName));
+    }
+
+    protected static void assertFileExists(String filename) {
+        File file = new File(filename);
+        Assertions.assertTrue(file.exists(), "File " + filename + " should exist");
+        Assertions.assertTrue(file.isFile(), "File " + filename + " should be a file");
+    }
+
+    protected static void assertFileNotExists(Path file) {
+        Assertions.assertFalse(Files.exists(file, new LinkOption[0]), "File " + file + " should not exist");
+    }
+
+    protected static void assertFileExists(Path file, String content) throws IOException {
+        Assertions.assertTrue(Files.exists(file, new LinkOption[0]), "File " + file + " should exist");
+        Assertions.assertTrue(Files.isRegularFile(file, new LinkOption[0]), "File " + file + " should be a file");
+        Assertions.assertEquals(content, new String(Files.readAllBytes(file)), "File " + file + " has unexpected content");
+    }
+
+
+    protected Path testFile(String dir) {
+        return this.testDirectory().resolve(dir);
+    }
+
+    protected Path testDirectory() {
+        return this.testDirectory(false);
+    }
+
+    protected Path testDirectory(boolean create) {
+        Class<?> testClass = this.getClass();
+        return testDirectory(testClass, create);
+    }
+
+    public static Path testDirectory(Class<?> testClass, boolean create) {
+        Path dir = Paths.get("target", "data", testClass.getSimpleName());
+        if (create) {
+            try {
+                Files.createDirectories(dir);
+            } catch (IOException var4) {
+                throw new IllegalStateException("Unable to create test directory: " + dir, var4);
+            }
+        }
+
+        return dir;
+    }
+
+    protected String fileUri(String query) {
+        Path var10000 = this.testDirectory();
+        return "file:" + var10000 + (query.startsWith("?") ? "" : "/") + query;
+    }
+
+
+    // *************************************
+    // Config
+    // *************************************
+
+    @Configuration
+    public static class TestConfiguration {
+
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/BaseFtp.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/BaseFtp.java
new file mode 100644
index 00000000000..d4654b56e5f
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/BaseFtp.java
@@ -0,0 +1,33 @@
+package org.apache.camel.component.file.remote.springboot.ftp;
+
+import org.apache.camel.component.file.remote.springboot.AbstractBaseFtp;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import java.nio.file.Path;
+
+
+public class BaseFtp extends AbstractBaseFtp {
+    protected static final String AUTH_VALUE_SSL = "SSLv3";
+    protected static final String AUTH_VALUE_TLS = "TLSv1.2";
+
+    @RegisterExtension
+    static FtpEmbeddedService service = new FtpEmbeddedService();
+
+    @Override
+    protected int getPort() {
+        return service.getPort();
+    }
+
+    protected Path ftpFile(String file) {
+        return service.getFtpRootDir().resolve(file);
+    }
+
+    protected String getFtpUrl(String user, String password) {
+        StringBuilder url = new StringBuilder("ftp://");
+        url.append(user == null ? "" : user + "@");
+        url.append("localhost:" + service.getPort() + "/");
+        url.append(password == null ? "" : "?password=" + password);
+        return url.toString();
+    }
+
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FromFtpFilterTest.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FromFtpFilterTest.java
new file mode 100644
index 00000000000..a8d3be23373
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FromFtpFilterTest.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file.remote.springboot.ftp;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.file.GenericFile;
+import org.apache.camel.component.file.GenericFileFilter;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+        classes = {
+                CamelAutoConfiguration.class,
+                FromFtpFilterTest.class,
+                FromFtpFilterTest.TestConfiguration.class
+        }
+)
+//Based on FromFtpFilterIT
+public class FromFtpFilterTest extends BaseFtp {
+
+    @EndpointInject("mock:result")
+    private MockEndpoint mock;
+
+    protected String getFtpUrl() {
+        return "ftp://admin@localhost:" + getPort() + "/filter?password=admin&binary=false&filter=#myFilter";
+    }
+
+    @Test
+    public void testFilterFiles() throws Exception {
+        mock.expectedMessageCount(0);
+
+        sendFile(getFtpUrl(), "This is a file to be filtered", "skipme.txt");
+
+        mock.setResultWaitTime(3000);
+        mock.assertIsSatisfied();
+    }
+
+    @Test
+    public void testFilterFilesWithARegularFile() throws Exception {
+        mock.expectedMessageCount(1);
+        mock.expectedBodiesReceived("Hello World");
+
+        sendFile(getFtpUrl(), "This is a file to be filtered", "skipme.txt");
+
+        sendFile(getFtpUrl(), "Hello World", "hello.txt");
+
+        mock.assertIsSatisfied();
+    }
+
+    // *************************************
+    // Config
+    // *************************************
+
+    @Configuration
+    public class TestConfiguration extends  BaseFtp.TestConfiguration {
+        @Bean
+        public RouteBuilder routeBuilder() {
+
+            return new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from(getFtpUrl()).to("mock:result");
+                }
+            };
+        }
+
+        @Bean(value = "myFilter")
+        public MyFileFilter filter() {
+            return new MyFileFilter();
+        }
+    }
+
+    // START SNIPPET: e1
+    public class MyFileFilter<T> implements GenericFileFilter<T> {
+        @Override
+        public boolean accept(GenericFile<T> file) {
+            // we don't accept any files starting with skip in the name
+            return !file.getFileName().startsWith("skip");
+        }
+    }
+    // END SNIPPET: e1
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FromFtpMoveFileRecursiveTest.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FromFtpMoveFileRecursiveTest.java
new file mode 100644
index 00000000000..b1da84bb63e
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FromFtpMoveFileRecursiveTest.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file.remote.springboot.ftp;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+        classes = {
+                CamelAutoConfiguration.class,
+                FromFtpMoveFileRecursiveTest.class,
+                FromFtpMoveFileRecursiveTest.TestConfiguration.class
+        }
+)
+// Based on FromFtpMoveFileRecursiveIT
+public class FromFtpMoveFileRecursiveTest extends BaseFtp {
+
+    @EndpointInject("mock:result")
+    private MockEndpoint result;
+
+    protected String getFtpUrl() {
+        return "ftp://admin@localhost:" + getPort() + "/movefile?password=admin&recursive=true&binary=false"
+               + "&move=.done/${file:name}.old&initialDelay=2500&delay=5000";
+    }
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        prepareFtpServer();
+    }
+
+    @Test
+    public void testPollFileAndShouldBeMoved() throws Exception {
+        result.expectedBodiesReceivedInAnyOrder("Hello", "Bye", "Goodday");
+        result.expectedFileExists(ftpFile("movefile/.done/hello.txt.old"));
+        result.expectedFileExists(ftpFile("movefile/.done/bye/bye.txt.old"));
+        result.expectedFileExists(ftpFile("movefile/.done/goodday/goodday.txt.old"));
+
+        result.assertIsSatisfied();
+    }
+
+    private void prepareFtpServer() {
+        sendFile(getFtpUrl(), "Hello", "hello.txt");
+        sendFile(getFtpUrl(), "Bye", "bye/bye.txt");
+        sendFile(getFtpUrl(), "Goodday", "goodday/goodday.txt");
+    }
+
+    // *************************************
+    // Config
+    // *************************************
+
+    @Configuration
+    public class TestConfiguration extends  BaseFtp.TestConfiguration {
+        @Bean
+        public RouteBuilder routeBuilder() {
+
+            return new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from(getFtpUrl()).to("mock:result");
+                }
+            };
+        }
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FromFtpToBinaryFileTest.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FromFtpToBinaryFileTest.java
new file mode 100644
index 00000000000..e2497af049d
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FromFtpToBinaryFileTest.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file.remote.springboot.ftp;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.Producer;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.converter.IOConverter;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+
+import java.io.File;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+        classes = {
+                CamelAutoConfiguration.class,
+                FromFtpToBinaryFileTest.class,
+                FromFtpToBinaryFileTest.TestConfiguration.class
+        }
+)
+//Baaed on FromFtpToBinaryFileIT
+public class FromFtpToBinaryFileTest extends BaseFtp {
+
+    @EndpointInject("mock:result")
+    private MockEndpoint resultEndpoint;
+
+    // must user "consumer." prefix on the parameters to the file component
+    private String getFtpUrl() {
+        return "ftp://admin@localhost:" + getPort() + "/tmp4/camel?password=admin&binary=true"
+               + "&delay=5000&recursive=false";
+    }
+
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        prepareFtpServer();
+    }
+
+
+    @Test
+    public void testFtpRoute() throws Exception {
+        resultEndpoint.expectedMessageCount(1);
+        resultEndpoint.assertIsSatisfied();
+        Exchange ex = resultEndpoint.getExchanges().get(0);
+        byte[] bytes = ex.getIn().getBody(byte[].class);
+        assertTrue(bytes.length > 10000, "Logo size wrong");
+
+        // assert the file
+        File file = testFile("deleteme.jpg").toFile();
+        assertTrue(file.exists(), "The binary file should exists");
+        assertTrue(file.length() > 10000, "Logo size wrong");
+    }
+
+    private void prepareFtpServer() throws Exception {
+        // prepares the FTP Server by creating a file on the server that we want
+        // to unit
+        // test that we can pool and store as a local file
+        Endpoint endpoint = context.getEndpoint(getFtpUrl());
+        Exchange exchange = endpoint.createExchange();
+        exchange.getIn().setBody(IOConverter.toFile("src/test/data/ftpbinarytest/logo.jpeg"));
+        exchange.getIn().setHeader(Exchange.FILE_NAME, "logo.jpeg");
+        Producer producer = endpoint.createProducer();
+        producer.start();
+        producer.process(exchange);
+        producer.stop();
+    }
+
+    // *************************************
+    // Config
+    // *************************************
+
+    @Configuration
+    public class TestConfiguration extends  BaseFtp.TestConfiguration {
+        @Bean
+        public RouteBuilder routeBuilder() {
+
+            return new RouteBuilder() {
+                @Override
+                public void configure() {
+                    String fileUrl = fileUri("?noop=true&fileExist=Override");
+                    from(getFtpUrl()).setHeader(Exchange.FILE_NAME, constant("deleteme.jpg")).to(fileUrl, "mock:result");
+                }
+            };
+        }
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpAnonymousTest.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpAnonymousTest.java
new file mode 100644
index 00000000000..eb7f5d52024
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpAnonymousTest.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file.remote.springboot.ftp;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+
+/**
+ * Unit test that ftp consumer for anonymous login
+ */
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+        classes = {
+                CamelAutoConfiguration.class,
+                FtpAnonymousTest.class,
+                FtpAnonymousTest.TestConfiguration.class
+        }
+)
+//Based on FtpAnonymousIT
+public class FtpAnonymousTest extends BaseFtp {
+
+    @EndpointInject("mock:result")
+    private MockEndpoint result;
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        prepareFtpServer();
+    }
+
+    @Test
+    public void testAnonymous() throws Exception {
+        result.expectedMessageCount(1);
+
+        result.assertIsSatisfied();
+    }
+
+    private void prepareFtpServer() {
+        sendFile(getFtpUrl("admin", "admin"), "Hello World", "hello.xml");
+    }
+
+    // *************************************
+    // Config
+    // *************************************
+
+    @Configuration
+    public class TestConfiguration extends  BaseFtp.TestConfiguration {
+        @Bean
+        public RouteBuilder routeBuilder() {
+
+            return new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from(getFtpUrl(null, null)).to("mock:result");
+                }
+            };
+        }
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpConsumerMaxMessagesPerPollTest.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpConsumerMaxMessagesPerPollTest.java
new file mode 100644
index 00000000000..64ba3d36b28
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpConsumerMaxMessagesPerPollTest.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file.remote.springboot.ftp;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+        classes = {
+                CamelAutoConfiguration.class,
+                FtpConsumerMaxMessagesPerPollTest.class,
+                FtpConsumerMaxMessagesPerPollTest.TestConfiguration.class
+        }
+)
+//Based on FtpConsumerMaxMessagesPerPollIT
+public class FtpConsumerMaxMessagesPerPollTest extends BaseFtp {
+
+    @EndpointInject("mock:result")
+    private MockEndpoint mock;
+
+    private String getFtpUrl() {
+        return "ftp://admin@localhost:" + getPort() + "/poll/?password=admin&delay=6000&delete=true&sortBy=file:name&maxMessagesPerPoll=2";
+    }
+
+    @BeforeEach
+    void prepareFtpServer() {
+        sendFile(getFtpUrl(), "Bye World", "bye.txt");
+        sendFile(getFtpUrl(), "Hello World", "hello.txt");
+        sendFile(getFtpUrl(), "Godday World", "godday.txt");
+    }
+
+    @Test
+    public void testMaxMessagesPerPoll() throws Exception {
+        // start route
+        context.getRouteController().startRoute("foo");
+
+        mock.expectedBodiesReceived("Bye World", "Godday World");
+        mock.setResultWaitTime(4000);
+        mock.expectedPropertyReceived(Exchange.BATCH_SIZE, 2);
+
+        assertMockEndpointsSatisfied();
+
+        mock.reset();
+        mock.expectedBodiesReceived("Hello World");
+        mock.expectedPropertyReceived(Exchange.BATCH_SIZE, 1);
+
+        assertMockEndpointsSatisfied();
+    }
+
+    // *************************************
+    // Config
+    // *************************************
+
+    @Configuration
+    public class TestConfiguration extends  BaseFtp.TestConfiguration {
+        @Bean
+        public RouteBuilder routeBuilder() {
+
+            return new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from(getFtpUrl()).noAutoStartup().routeId("foo").to("mock:result");
+                }
+            };
+        }
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpEmbeddedService.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpEmbeddedService.java
new file mode 100644
index 00000000000..8067059363e
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpEmbeddedService.java
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.component.file.remote.springboot.ftp;
+
+import org.apache.camel.test.infra.common.services.AbstractTestService;
+import org.apache.camel.test.infra.ftp.common.FtpProperties;
+import org.apache.camel.test.infra.ftp.services.FtpService;
+import org.apache.ftpserver.ConnectionConfigFactory;
+import org.apache.ftpserver.FtpServer;
+import org.apache.ftpserver.FtpServerFactory;
+import org.apache.ftpserver.filesystem.nativefs.NativeFileSystemFactory;
+import org.apache.ftpserver.ftplet.FtpException;
+import org.apache.ftpserver.ftplet.UserManager;
+import org.apache.ftpserver.impl.DefaultFtpServer;
+import org.apache.ftpserver.impl.FtpIoSession;
+import org.apache.ftpserver.listener.Listener;
+import org.apache.ftpserver.listener.ListenerFactory;
+import org.apache.ftpserver.usermanager.ClearTextPasswordEncryptor;
+import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory;
+import org.apache.ftpserver.usermanager.impl.BaseUser;
+import org.apache.ftpserver.usermanager.impl.WritePermission;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiConsumer;
+
+import static org.apache.camel.test.junit5.TestSupport.createCleanDirectory;
+
+public class FtpEmbeddedService extends AbstractTestService implements FtpService {
+    protected static final String DEFAULT_LISTENER = "default";
+
+    private static final Logger LOG = LoggerFactory.getLogger(FtpEmbeddedService.class);
+
+    protected FtpServer ftpServer;
+
+    protected int port;
+
+    protected Path rootDir;
+
+    public FtpEmbeddedService() {
+    }
+
+    public void setUp() throws Exception {
+        rootDir = testDirectory().resolve("res/home");
+        createCleanDirectory(rootDir);
+
+        FtpServerFactory factory = createFtpServerFactory();
+        ftpServer = factory.createServer();
+        ftpServer.start();
+
+        port = ((DefaultFtpServer) ftpServer).getListeners().values().stream()
+                .map(Listener::getPort).findAny().get();
+    }
+
+    private Path testDirectory() {
+        return Paths.get("target", "ftp", context.getRequiredTestClass().getSimpleName());
+    }
+
+    protected void createUser(UserManager userMgr, String name, String password, Path home, boolean writePermission) {
+        try {
+            BaseUser user = new BaseUser();
+            user.setName(name);
+            user.setPassword(password);
+            user.setHomeDirectory(home.toString());
+            if (writePermission) {
+                user.setAuthorities(Collections.singletonList(new WritePermission()));
+            }
+            userMgr.save(user);
+        } catch (FtpException e) {
+            throw new IllegalStateException("Unable to create FTP user", e);
+        }
+    }
+
+    protected FtpServerFactory createFtpServerFactory() {
+        NativeFileSystemFactory fsf = new NativeFileSystemFactory();
+        fsf.setCreateHome(true);
+
+        PropertiesUserManagerFactory pumf = new PropertiesUserManagerFactory();
+        pumf.setAdminName("admin");
+        pumf.setPasswordEncryptor(new ClearTextPasswordEncryptor());
+        pumf.setFile(null);
+        UserManager userMgr = pumf.createUserManager();
+        createUser(userMgr, "admin", "admin", rootDir, true);
+        createUser(userMgr, "scott", "tiger", rootDir, true);
+        createUser(userMgr, "dummy", "foo", rootDir, false);
+        createUser(userMgr, "us@r", "t%st", rootDir, true);
+        createUser(userMgr, "anonymous", null, rootDir, false);
+        createUser(userMgr, "joe", "p+%w0&r)d", rootDir, true);
+        createUser(userMgr, "jane", "%j#7%c6i", rootDir, true);
+
+        ListenerFactory factory = new ListenerFactory();
+        factory.setPort(port);
+
+        FtpServerFactory serverFactory = new FtpServerFactory();
+        serverFactory.setUserManager(userMgr);
+        serverFactory.setFileSystem(fsf);
+        serverFactory.setConnectionConfig(new ConnectionConfigFactory().createConnectionConfig());
+        serverFactory.addListener(DEFAULT_LISTENER, factory.createListener());
+
+        return serverFactory;
+    }
+
+    public void tearDown() {
+        try {
+            if (ftpServer != null) {
+                ftpServer.stop();
+            }
+        } catch (Exception e) {
+            // ignore while shutting down as we could be polling during
+            // shutdown
+            // and get errors when the ftp server is stopping. This is only
+            // an issue
+            // since we host the ftp server embedded in the same jvm for
+            // unit testing
+
+            LOG.trace("Exception while shutting down: {}", e.getMessage(), e);
+        } finally {
+            ftpServer = null;
+        }
+
+        //        if (port != null) {
+        //            port.release();
+        //        }
+    }
+
+    public void disconnectAllSessions() {
+        // stop all listeners
+        Map<String, Listener> listeners = ((DefaultFtpServer) ftpServer).getListeners();
+        for (Listener listener : listeners.values()) {
+            Set<FtpIoSession> sessions = listener.getActiveSessions();
+            for (FtpIoSession session : sessions) {
+                session.closeNow();
+            }
+        }
+    }
+
+    @Override
+    protected void registerProperties(BiConsumer<String, String> store) {
+        store.accept(FtpProperties.SERVER_HOST, "localhost");
+        store.accept(FtpProperties.SERVER_PORT, String.valueOf(getPort()));
+        store.accept(FtpProperties.ROOT_DIR, rootDir.toString());
+    }
+
+    public Path getFtpRootDir() {
+        return rootDir;
+    }
+
+    public void suspend() {
+        ftpServer.suspend();
+    }
+
+    public void resume() {
+        ftpServer.resume();
+        port = ((DefaultFtpServer) ftpServer).getListeners().values().stream()
+                .map(Listener::getPort).findAny().get();
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public int countConnections() {
+        int count = 0;
+
+        // stop all listeners
+        Map<String, Listener> listeners = ((DefaultFtpServer) ftpServer).getListeners();
+        for (Listener listener : listeners.values()) {
+            count += listener.getActiveSessions().size();
+        }
+
+        return count;
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpProducerConcurrentTest.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpProducerConcurrentTest.java
new file mode 100644
index 00000000000..f35d8a20443
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpProducerConcurrentTest.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file.remote.springboot.ftp;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+@CamelSpringBootTest
+@SpringBootTest(
+        classes = {
+                CamelAutoConfiguration.class,
+                FtpProducerConcurrentTest.class,
+                FtpProducerConcurrentTest.TestConfiguration.class
+        }
+)
+//Based on FtpProducerConcurrentIT
+public class FtpProducerConcurrentTest extends BaseFtp {
+
+    @EndpointInject("mock:result")
+    private MockEndpoint result;
+
+    private String getFtpUrl() {
+        return "ftp://admin@localhost:" + getPort() + "/concurrent?binary=false&password=admin";
+    }
+
+    @Test
+    public void testNoConcurrentProducers() throws Exception {
+        doSendMessages(1, 1);
+    }
+
+    @Test
+    public void testConcurrentProducers() throws Exception {
+        doSendMessages(10, 5);
+    }
+
+    private void doSendMessages(int files, int poolSize) throws Exception {
+        result.reset();
+        result.expectedMessageCount(files);
+
+        ExecutorService executor = Executors.newFixedThreadPool(poolSize);
+        for (int i = 0; i < files; i++) {
+            result.expectedFileExists(ftpFile("concurrent/" + i + ".txt"));
+
+            final int index = i;
+            executor.submit(new Callable<Object>() {
+                public Object call() {
+                    sendFile("direct:start", "Hello World", index + ".txt");
+                    return null;
+                }
+            });
+        }
+
+        assertMockEndpointsSatisfied();
+        executor.shutdownNow();
+    }
+
+
+    // *************************************
+    // Config
+    // *************************************
+
+    @Configuration
+    public class TestConfiguration extends  BaseFtp.TestConfiguration {
+        @Bean
+        public RouteBuilder routeBuilder() {
+
+            return new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from("direct:start").to(getFtpUrl(), "mock:result");
+                }
+            };
+        }
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpSimpleConsumeStreamingStepwiseFalseTest.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpSimpleConsumeStreamingStepwiseFalseTest.java
new file mode 100644
index 00000000000..a83e72597de
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpSimpleConsumeStreamingStepwiseFalseTest.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file.remote.springboot.ftp;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.file.GenericFile;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+
+import java.io.InputStream;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+        classes = {
+                CamelAutoConfiguration.class,
+                FtpSimpleConsumeStreamingStepwiseFalseTest.class,
+                FtpSimpleConsumeStreamingStepwiseFalseTest.TestConfiguration.class
+        }
+)
+public class FtpSimpleConsumeStreamingStepwiseFalseTest extends BaseFtp {
+
+    @EndpointInject("mock:result")
+    MockEndpoint mock;
+
+    boolean isStepwise() {
+        return false;
+    }
+
+    @Test
+    public void testFtpSimpleConsumeAbsolute() throws Exception {
+        String expected = "Hello World";
+
+        String path = ftpFile("tmp/mytemp").toString();
+        template.sendBodyAndHeader("file:" + path, expected, Exchange.FILE_NAME, "hello.txt");
+
+        configureMock();
+
+        assertMockEndpointsSatisfied();
+        assertMore(mock);
+    }
+
+    void configureMock() {
+        mock.expectedMessageCount(1);
+        mock.expectedHeaderReceived(Exchange.FILE_NAME, "hello.txt");
+    }
+
+    void assertMore(MockEndpoint mock) {
+        GenericFile<?> remoteFile = (GenericFile<?>) mock.getExchanges().get(0).getIn().getBody();
+        assertTrue(remoteFile.getBody() instanceof InputStream);
+    }
+
+    // *************************************
+    // Config
+    // *************************************
+
+    @Configuration
+    public class TestConfiguration extends  BaseFtp.TestConfiguration {
+        @Bean
+        public RouteBuilder routeBuilder() {
+
+            return new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from("ftp://localhost:" + getPort() 
+                            + "/tmp/mytemp?username=admin&password=admin&delay=10000&disconnect=true&streamDownload=true&stepwise="
+                            + isStepwise())
+                            .to("mock:result");
+                }
+            };
+        }
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpSimpleConsumeStreamingStepwiseTrueTest.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpSimpleConsumeStreamingStepwiseTrueTest.java
new file mode 100644
index 00000000000..377a48a66de
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpSimpleConsumeStreamingStepwiseTrueTest.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file.remote.springboot.ftp;
+
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+        classes = {
+                CamelAutoConfiguration.class,
+                FtpSimpleConsumeStreamingStepwiseTrueTest.class,
+                FtpSimpleConsumeStreamingStepwiseTrueTest.TestConfiguration.class
+        }
+)
+public class FtpSimpleConsumeStreamingStepwiseTrueTest extends FtpSimpleConsumeStreamingStepwiseFalseTest {
+
+    @Override
+    boolean isStepwise() {
+        return true;
+    }
+
+    @Override
+    void configureMock() {
+        mock.expectedMessageCount(0);
+    }
+
+    @Override
+    void assertMore(MockEndpoint mock) {
+    }
+
+    // *************************************
+    // Config
+    // *************************************
+
+    @Configuration
+    public class TestConfiguration extends  FtpSimpleConsumeStreamingStepwiseFalseTest.TestConfiguration {
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpSoTimeoutTest.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpSoTimeoutTest.java
new file mode 100644
index 00000000000..64e8337bff4
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftp/FtpSoTimeoutTest.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file.remote.springboot.ftp;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.apache.commons.net.ftp.FTPClient;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+        classes = {
+                CamelAutoConfiguration.class,
+                FtpSoTimeoutTest.class,
+                FtpSoTimeoutTest.TestConfiguration.class
+        }
+)
+//Based on FtpSoTimeoutTest
+public class FtpSoTimeoutTest {
+
+    @Autowired
+    protected CamelContext context;
+
+    @Autowired
+    protected ProducerTemplate template;
+
+    @AfterEach
+    public void after() throws IOException {
+        context.getRegistry().findSingleByType(ServerSocket.class).close();
+    }
+
+    @Test
+    @Timeout(value = 10, unit = TimeUnit.SECONDS)
+    public void testWithDefaultTimeout() {
+        assertThrows(CamelExecutionException.class, () -> {
+            // send exchange to the route using the custom FTPClient (with a
+            // default timeout)
+            // the soTimeout triggers in time and test is successful
+            template.sendBody("direct:with", "");
+        });
+    }
+
+    @Test
+    @Timeout(value = 10, unit = TimeUnit.SECONDS)
+    public void testWithoutDefaultTimeout() {
+        assertThrows(CamelExecutionException.class, () -> {
+            // send exchange to the route using the default FTPClient (without a
+            // default timeout)
+            // the soTimeout never triggers and test fails after its own timeout
+            template.sendBody("direct:without", "");
+        });
+    }
+
+    // *************************************
+    // Config
+    // *************************************
+
+    @Configuration
+    public class TestConfiguration extends  BaseFtp.TestConfiguration {
+
+        @Bean
+        public ServerSocket createServerSocket() throws IOException {
+            return new ServerSocket(0);
+        }
+        @Bean
+        public RouteBuilder routeBuilder(ServerSocket serverSocket) {
+
+            return new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from("direct:with").to("ftp://localhost:" + serverSocket.getLocalPort()
+                            + "?ftpClient=#myftpclient&connectTimeout=300&soTimeout=300&reconnectDelay=100");
+
+                    from("direct:without").to("ftp://localhost:" + serverSocket.getLocalPort()
+                            + "?connectTimeout=300&soTimeout=300&reconnectDelay=100");
+                }
+            };
+        }
+
+        @Bean(value = "myftpclient")
+        public FTPClient createFtpClient() {
+            FTPClient ftpClient = new FTPClient();
+            ftpClient.setDefaultTimeout(300);
+            return ftpClient;
+        }
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/BaseFtpsClientAuth.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/BaseFtpsClientAuth.java
new file mode 100644
index 00000000000..941ad63f2d3
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/BaseFtpsClientAuth.java
@@ -0,0 +1,18 @@
+package org.apache.camel.component.file.remote.springboot.ftps;
+
+import org.apache.camel.component.file.remote.springboot.AbstractBaseFtp;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+
+public class BaseFtpsClientAuth extends AbstractBaseFtp {
+    protected static final String AUTH_VALUE_SSL = "SSLv3";
+    protected static final String AUTH_VALUE_TLS = "TLSv1.2";
+
+    @RegisterExtension
+    static FtpsEmbeddedService service = new FtpsEmbeddedService(false, AUTH_VALUE_TLS, true);
+
+    @Override
+    protected int getPort() {
+        return service.getPort();
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/BaseFtpsImplicitClientAuth.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/BaseFtpsImplicitClientAuth.java
new file mode 100644
index 00000000000..6406c6cdc4d
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/BaseFtpsImplicitClientAuth.java
@@ -0,0 +1,18 @@
+package org.apache.camel.component.file.remote.springboot.ftps;
+
+import org.apache.camel.component.file.remote.springboot.AbstractBaseFtp;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+
+public class BaseFtpsImplicitClientAuth extends AbstractBaseFtp {
+    protected static final String AUTH_VALUE_SSL = "SSLv3";
+    protected static final String AUTH_VALUE_TLS = "TLSv1.2";
+
+    @RegisterExtension
+    static FtpsEmbeddedService service = new FtpsEmbeddedService(true, AUTH_VALUE_TLS, true);
+
+    @Override
+    protected int getPort() {
+        return service.getPort();
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/FileToFtpsImplicitSSLWithClientAuthTest.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/FileToFtpsImplicitSSLWithClientAuthTest.java
new file mode 100644
index 00000000000..f9a1d2c5b56
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/FileToFtpsImplicitSSLWithClientAuthTest.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file.remote.springboot.ftps;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.file.remote.springboot.ftp.BaseFtp;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledIf;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@CamelSpringBootTest
+@SpringBootTest(
+        classes = {
+                CamelAutoConfiguration.class,
+                FileToFtpsImplicitSSLWithClientAuthTest.class,
+                FileToFtpsImplicitSSLWithClientAuthTest.TestConfiguration.class
+        }
+)
+//Based on FileToFtpsImplicitSSLWithClientAuthIT
+public class FileToFtpsImplicitSSLWithClientAuthTest extends BaseFtpsImplicitClientAuth {
+
+    @EndpointInject("mock:result")
+    private MockEndpoint mock;
+
+    protected String getFtpUrl() {
+        return "ftps://admin@localhost:" + getPort()
+               + "/tmp2/camel?password=admin&initialDelay=2000&disableSecureDataChannelDefaults=true"
+               + "&securityProtocol=TLSv1.2&implicit=true&ftpClient.keyStore.file=./src/test/resources/server.jks&ftpClient.keyStore.type=JKS"
+               + "&ftpClient.keyStore.algorithm=SunX509&ftpClient.keyStore.password=password&ftpClient.keyStore.keyPassword=password&delete=true";
+    }
+
+    @Test
+    public void testFromFileToFtp() throws Exception {
+
+        mock.expectedMessageCount(2);
+
+        assertMockEndpointsSatisfied();
+    }
+
+    // *************************************
+    // Config
+    // *************************************
+
+    @Configuration
+    public class TestConfiguration extends  BaseFtp.TestConfiguration {
+        @Bean
+        public RouteBuilder routeBuilder() {
+
+            return new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from("file:src/test/data?noop=true").log("Got ${file:name}").to(getFtpUrl());
+
+                    from(getFtpUrl()).to("mock:result");
+                }
+            };
+        }
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/FileToFtpsWithCustomTrustStorePropertiesTest.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/FileToFtpsWithCustomTrustStorePropertiesTest.java
new file mode 100644
index 00000000000..d37ca393898
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/FileToFtpsWithCustomTrustStorePropertiesTest.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file.remote.springboot.ftps;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.file.remote.springboot.ftp.BaseFtp;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@CamelSpringBootTest
+@SpringBootTest(
+        classes = {
+                CamelAutoConfiguration.class,
+                FileToFtpsWithCustomTrustStorePropertiesTest.class,
+                FileToFtpsWithCustomTrustStorePropertiesTest.TestConfiguration.class
+        }
+)
+//based on FileToFtpsWithCustomTrustStorePropertiesIT
+public class FileToFtpsWithCustomTrustStorePropertiesTest extends BaseFtpsClientAuth {
+
+    @EndpointInject("mock:result")
+    private MockEndpoint result;
+
+    private String getFtpUrl() {
+        return "ftps://admin@localhost:" + getPort()
+               + "/tmp2/camel?password=admin&initialDelay=2000&disableSecureDataChannelDefaults=true"
+               + "&securityProtocol=TLSv1.2&implicit=false&ftpClient.trustStore.file=./src/test/resources/server.jks&ftpClient.trustStore.type=PKCS12"
+               + "&ftpClient.trustStore.algorithm=SunX509&ftpClient.trustStore.password=password&delete=true";
+
+    }
+
+    @Test
+    public void testFromFileToFtp() throws Exception {
+
+        result.expectedMessageCount(2);
+
+        assertMockEndpointsSatisfied();
+    }
+
+    // *************************************
+    // Config
+    // *************************************
+
+    @Configuration
+    public class TestConfiguration extends  BaseFtp.TestConfiguration {
+        @Bean
+        public RouteBuilder routeBuilder() {
+
+            return new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from("file:src/test/data?noop=true").log("Got ${file:name}").to(getFtpUrl());
+
+                    from(getFtpUrl()).to("mock:result");
+                }
+            };
+        }
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/FtpsEmbeddedService.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/FtpsEmbeddedService.java
new file mode 100644
index 00000000000..46610e290a4
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/FtpsEmbeddedService.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.component.file.remote.springboot.ftps;
+
+import org.apache.camel.component.file.remote.springboot.ftp.FtpEmbeddedService;
+import org.apache.ftpserver.FtpServerFactory;
+import org.apache.ftpserver.listener.ListenerFactory;
+import org.apache.ftpserver.ssl.SslConfigurationFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.File;
+import java.security.NoSuchAlgorithmException;
+
+public class FtpsEmbeddedService extends FtpEmbeddedService {
+    private static final Logger LOG = LoggerFactory.getLogger(FtpsEmbeddedService.class);
+    private static final File FTPSERVER_KEYSTORE = new File("./src/test/resources/server.jks");
+    private static final String FTPSERVER_KEYSTORE_PASSWORD = "password";
+
+    private boolean useImplicit;
+    private String authValue;
+    private boolean clientAuth;
+
+    public FtpsEmbeddedService(boolean useImplicit, String authValue, boolean clientAuth) {
+        super();
+
+        this.useImplicit = useImplicit;
+        this.authValue = authValue;
+        this.clientAuth = clientAuth;
+    }
+
+    @Override
+    protected FtpServerFactory createFtpServerFactory() {
+        FtpServerFactory serverFactory = super.createFtpServerFactory();
+
+        ListenerFactory listenerFactory = new ListenerFactory(serverFactory.getListener(DEFAULT_LISTENER));
+        listenerFactory.setPort(port);
+        listenerFactory.setImplicitSsl(useImplicit);
+        listenerFactory.setSslConfiguration(createSslConfiguration().createSslConfiguration());
+
+        serverFactory.addListener(DEFAULT_LISTENER, listenerFactory.createListener());
+
+        return serverFactory;
+    }
+
+    protected SslConfigurationFactory createSslConfiguration() {
+        // comment in, if you have trouble with SSL
+         System.setProperty("javax.net.debug", "all");
+
+        SslConfigurationFactory sslConfigFactory = new SslConfigurationFactory();
+        sslConfigFactory.setSslProtocol(authValue);
+
+        sslConfigFactory.setKeystoreFile(FTPSERVER_KEYSTORE);
+        sslConfigFactory.setKeystoreType("PKCS12");
+        sslConfigFactory.setKeystorePassword(FTPSERVER_KEYSTORE_PASSWORD);
+        sslConfigFactory.setKeyPassword(FTPSERVER_KEYSTORE_PASSWORD);
+
+        sslConfigFactory.setClientAuthentication(authValue);
+
+        if (clientAuth) {
+            sslConfigFactory.setTruststoreFile(FTPSERVER_KEYSTORE);
+            sslConfigFactory.setTruststoreType("PKCS12");
+            sslConfigFactory.setTruststorePassword(FTPSERVER_KEYSTORE_PASSWORD);
+        }
+
+        return sslConfigFactory;
+    }
+
+    public static boolean hasRequiredAlgorithms() {
+        LOG.info("Checking if the system has the required algorithms for the test execution");
+        try {
+            KeyManagerFactory.getInstance("SunX509");
+            TrustManagerFactory.getInstance("SunX509");
+
+            return true;
+        } catch (NoSuchAlgorithmException e) {
+            String name = System.getProperty("os.name");
+            String message = e.getMessage();
+
+            LOG.warn("SunX509 is not available on this platform [{}] Testing is skipped! Real cause: {}", name, message, e);
+            return false;
+        }
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/FtpsImplicitEmbeddedService.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/FtpsImplicitEmbeddedService.java
new file mode 100644
index 00000000000..bcd1674776b
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/FtpsImplicitEmbeddedService.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.component.file.remote.springboot.ftps;
+
+import org.apache.camel.component.file.remote.springboot.ftp.FtpEmbeddedService;
+import org.apache.ftpserver.FtpServerFactory;
+import org.apache.ftpserver.listener.ListenerFactory;
+import org.apache.ftpserver.ssl.SslConfigurationFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.File;
+import java.security.NoSuchAlgorithmException;
+
+public class FtpsImplicitEmbeddedService extends FtpEmbeddedService {
+    private static final Logger LOG = LoggerFactory.getLogger(FtpsImplicitEmbeddedService.class);
+    private static final File FTPSERVER_KEYSTORE = new File("./src/test/resources/server.jks");
+    private static final String FTPSERVER_KEYSTORE_PASSWORD = "password";
+
+    private boolean useImplicit;
+    private String authValue;
+    private boolean clientAuth;
+
+    public FtpsImplicitEmbeddedService(boolean useImplicit, String authValue, boolean clientAuth) {
+        super();
+
+        this.useImplicit = useImplicit;
+        this.authValue = authValue;
+        this.clientAuth = clientAuth;
+    }
+
+    @Override
+    protected FtpServerFactory createFtpServerFactory() {
+        FtpServerFactory serverFactory = super.createFtpServerFactory();
+
+        ListenerFactory listenerFactory = new ListenerFactory(serverFactory.getListener(DEFAULT_LISTENER));
+        listenerFactory.setPort(port);
+        listenerFactory.setImplicitSsl(useImplicit);
+        listenerFactory.setSslConfiguration(createSslConfiguration().createSslConfiguration());
+
+        serverFactory.addListener(DEFAULT_LISTENER, listenerFactory.createListener());
+
+        return serverFactory;
+    }
+
+    protected SslConfigurationFactory createSslConfiguration() {
+        // comment in, if you have trouble with SSL
+         System.setProperty("javax.net.debug", "all");
+
+        SslConfigurationFactory sslConfigFactory = new SslConfigurationFactory();
+        sslConfigFactory.setSslProtocol(authValue);
+
+        sslConfigFactory.setKeystoreFile(FTPSERVER_KEYSTORE);
+        sslConfigFactory.setKeystoreType("PKCS12");
+        sslConfigFactory.setKeystorePassword(FTPSERVER_KEYSTORE_PASSWORD);
+        sslConfigFactory.setKeyPassword(FTPSERVER_KEYSTORE_PASSWORD);
+
+        sslConfigFactory.setClientAuthentication(authValue);
+
+        if (clientAuth) {
+            sslConfigFactory.setTruststoreFile(FTPSERVER_KEYSTORE);
+            sslConfigFactory.setTruststoreType("PKCS12");
+            sslConfigFactory.setTruststorePassword(FTPSERVER_KEYSTORE_PASSWORD);
+        }
+
+        return sslConfigFactory;
+    }
+
+    public static boolean hasRequiredAlgorithms() {
+        LOG.info("Checking if the system has the required algorithms for the test execution");
+        try {
+            KeyManagerFactory.getInstance("SunX509");
+            TrustManagerFactory.getInstance("SunX509");
+
+            return true;
+        } catch (NoSuchAlgorithmException e) {
+            String name = System.getProperty("os.name");
+            String message = e.getMessage();
+
+            LOG.warn("SunX509 is not available on this platform [{}] Testing is skipped! Real cause: {}", name, message, e);
+            return false;
+        }
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/FtpsTest.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/FtpsTest.java
new file mode 100644
index 00000000000..96cfb9df580
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/ftps/FtpsTest.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file.remote.springboot.ftps;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.file.remote.springboot.ftp.BaseFtp;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@CamelSpringBootTest
+@SpringBootTest(
+        classes = {
+                CamelAutoConfiguration.class,
+                FtpsTest.class,
+                FtpsTest.TestConfiguration.class
+        }
+)
+//based on FileToFtpsWithCustomTrustStorePropertiesIT
+public class FtpsTest extends BaseFtpsClientAuth {
+
+    @EndpointInject("mock:result")
+    private MockEndpoint result;
+
+    private String getFtpUrl() {
+        return "ftps://admin@localhost:" + getPort()
+               + "/tmp1/camel?password=admin&initialDelay=2000&disableSecureDataChannelDefaults=true"
+               + "&securityProtocol=TLSv1.2&implicit=false";
+
+    }
+
+    @Test
+    public void testFromFileToFtp() throws Exception {
+
+        result.expectedMessageCount(2);
+
+        assertMockEndpointsSatisfied();
+    }
+
+    // *************************************
+    // Config
+    // *************************************
+
+    @Configuration
+    public class TestConfiguration extends  BaseFtp.TestConfiguration {
+        @Bean
+        public RouteBuilder routeBuilder() {
+
+            return new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from("file:src/test/data?noop=true").log("Got ${file:name}").to(getFtpUrl());
+
+                    from(getFtpUrl()).to("mock:result");
+                }
+            };
+        }
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/BaseSftp.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/BaseSftp.java
new file mode 100644
index 00000000000..884a8028eea
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/BaseSftp.java
@@ -0,0 +1,36 @@
+package org.apache.camel.component.file.remote.springboot.sftp;
+
+import org.apache.camel.component.file.remote.springboot.AbstractBaseFtp;
+import org.apache.camel.component.file.remote.springboot.ftp.FtpEmbeddedService;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import java.nio.file.Path;
+
+
+public class BaseSftp extends AbstractBaseFtp {
+
+    @RegisterExtension
+    static SftpEmbeddedService service = new SftpEmbeddedService();
+
+    @Override
+    protected int getPort() {
+        return service.getPort();
+    }
+
+    protected String getRootDir() {
+        return service.getFtpRootDir().toString();
+    }
+
+    protected Path ftpFile(String file) {
+        return service.getFtpRootDir().resolve(file);
+    }
+
+    protected String getFtpUrl(String user, String password) {
+        StringBuilder url = new StringBuilder("ftp://");
+        url.append(user == null ? "" : user + "@");
+        url.append("localhost:" + service.getPort() + "/");
+        url.append(password == null ? "" : "?password=" + password);
+        return url.toString();
+    }
+
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/SftpConsumerLocalWorkDirectoryTest.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/SftpConsumerLocalWorkDirectoryTest.java
new file mode 100644
index 00000000000..23e7ba6f14a
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/SftpConsumerLocalWorkDirectoryTest.java
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file.remote.springboot.sftp;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.builder.NotifyBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.file.remote.springboot.ftp.BaseFtp;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.apache.camel.util.FileUtil;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.io.File;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@CamelSpringBootTest
+@SpringBootTest(
+        classes = {
+                CamelAutoConfiguration.class,
+                SftpConsumerLocalWorkDirectoryTest.class,
+                SftpConsumerLocalWorkDirectoryTest.TestConfiguration.class
+        }
+)
+//Based on SftpConsumerLocalWorkDirectoryIT
+public class SftpConsumerLocalWorkDirectoryTest extends BaseSftp {
+
+    @EndpointInject("mock:result")
+    private MockEndpoint mock;
+
+    protected String getFtpUrl() {
+        return "sftp://localhost:" + getPort() + "/" + getRootDir() + "/?password=admin"
+               + "&localWorkDirectory=" + ftpFile("lwd")
+               + "&noop=true";
+    }
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        prepareFtpServer();
+    }
+
+    private void prepareFtpServer() throws Exception {
+        // prepares the FTP Server by creating a file on the server that we want
+        // to unit test that we can pool
+        Endpoint endpoint = context.getEndpoint(getFtpUrl());
+        Exchange exchange = endpoint.createExchange();
+        exchange.getIn().setBody("Hello World");
+        exchange.getIn().setHeader(Exchange.FILE_NAME, "hello.txt");
+        Producer producer = endpoint.createProducer();
+        producer.start();
+        producer.process(exchange);
+        producer.stop();
+    }
+
+    @Test
+    public void testLocalWorkDirectory() throws Exception {
+        NotifyBuilder notify = new NotifyBuilder(context).whenDone(1).create();
+
+        mock.expectedBodiesReceived("Hello World");
+        mock.expectedMessageCount(1);
+
+        context.getRouteController().startRoute("myRoute");
+
+        assertMockEndpointsSatisfied();
+
+        assertMockEndpointsSatisfied();
+        assertTrue(notify.matchesWaitTime());
+
+        // and the out file should exists
+        assertFileExists(ftpFile("out/hello.txt"), "Hello World");
+
+        // now the lwd file should be deleted
+        assertFileNotExists(ftpFile("lwd/hello.txt"));
+    }
+
+    // *************************************
+    // Config
+    // *************************************
+
+    @Configuration
+    public class TestConfiguration extends  BaseFtp.TestConfiguration {
+        @Bean
+        public RouteBuilder routeBuilder() {
+
+            return new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from(getFtpUrl()).routeId("myRoute").noAutoStartup().process(new Processor() {
+                        public void process(Exchange exchange) {
+                            File body = exchange.getIn().getBody(File.class);
+                            assertNotNull(body);
+                            assertTrue(body.exists(), "Local work file should exists");
+                            assertEquals(FileUtil.normalizePath(ftpFile("lwd/hello.txt").toString()), body.getPath());
+                        }
+                    }).to("mock:result", "file:" + ftpFile("out"));
+                }
+            };
+        }
+    }
+
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/SftpEmbeddedService.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/SftpEmbeddedService.java
new file mode 100644
index 00000000000..2f9d3c24f00
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/SftpEmbeddedService.java
@@ -0,0 +1,174 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.component.file.remote.springboot.sftp;
+
+import org.apache.camel.test.infra.common.services.AbstractTestService;
+import org.apache.camel.test.infra.ftp.common.FtpProperties;
+import org.apache.camel.test.infra.ftp.services.FtpService;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
+import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
+import org.apache.sshd.common.session.helpers.AbstractSession;
+import org.apache.sshd.common.signature.BuiltinSignatures;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.scp.server.ScpCommandFactory;
+import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
+import org.apache.sshd.sftp.server.SftpSubsystemFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.BiConsumer;
+
+public class SftpEmbeddedService extends AbstractTestService implements FtpService {
+    private static final Logger LOG = LoggerFactory.getLogger(SftpEmbeddedService.class);
+    private static final String KNOWN_HOSTS = "[localhost]:%d ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDdfIWeSV4o68dRrKS"
+                                              + "zFd/Bk51E65UTmmSrmW0O1ohtzi6HzsDPjXgCtlTt3FqTcfFfI92IlTr4JWqC9UK1QT1ZTeng0MkPQmv68hDANHbt5CpETZHjW5q4OOgWhV"
+                                              + "vj5IyOC2NZHtKlJBkdsMAa15ouOOJLzBvAvbqOR/yUROsEiQ==";
+
+    protected SshServer sshd;
+    protected final boolean rootDirMode;
+    protected int port;
+
+    private Path rootDir;
+    private Path knownHosts;
+
+    public SftpEmbeddedService() {
+        this(false);
+    }
+
+    public SftpEmbeddedService(boolean rootDirMode) {
+        this.rootDirMode = rootDirMode;
+    }
+
+    public void setUp() throws Exception {
+        rootDir = testDirectory().resolve("res/home");
+        knownHosts = testDirectory().resolve("user-home/.ssh/known_hosts");
+        Files.createDirectories(knownHosts.getParent());
+        Files.write(knownHosts, buildKnownHosts());
+        setUpServer();
+    }
+
+    private Path testDirectory() {
+        return Paths.get("target", "ftp", context.getRequiredTestClass().getSimpleName());
+    }
+
+    public void setUpServer() throws Exception {
+        sshd = SshServer.setUpDefaultServer();
+        sshd.setPort(port);
+        sshd.setKeyPairProvider(new FileKeyPairProvider(Paths.get("src/test/resources/hostkey.pem")));
+        sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory()));
+        sshd.setCommandFactory(new ScpCommandFactory());
+        sshd.setPasswordAuthenticator((username, password, session) -> true);
+        sshd.setPublickeyAuthenticator(getPublickeyAuthenticator());
+
+        if (rootDirMode) {
+            sshd.setFileSystemFactory(new VirtualFileSystemFactory(testDirectory().resolve("res").toAbsolutePath()));
+        }
+        List<NamedFactory<Signature>> signatureFactories = sshd.getSignatureFactories();
+        signatureFactories.clear();
+        // use only one, quite strong signature algorithms for 3 kinds of keys - RSA, EC, EDDSA
+        signatureFactories.add(BuiltinSignatures.rsaSHA512);
+        signatureFactories.add(BuiltinSignatures.nistp521);
+        signatureFactories.add(BuiltinSignatures.ed25519);
+        sshd.setSignatureFactories(signatureFactories);
+        sshd.start();
+
+        port = ((InetSocketAddress) sshd.getBoundAddresses().iterator().next()).getPort();
+    }
+
+    protected PublickeyAuthenticator getPublickeyAuthenticator() {
+        return (username, key, session) -> true;
+    }
+
+    public void tearDown() {
+        tearDownServer();
+    }
+
+    public void tearDownServer() {
+        try {
+            // stop asap as we may hang forever
+            if (sshd != null) {
+                sshd.stop(true);
+            }
+        } catch (Exception e) {
+            // ignore while shutting down as we could be polling during
+            // shutdown
+            // and get errors when the ftp server is stopping. This is only
+            // an issue
+            // since we host the ftp server embedded in the same jvm for
+            // unit testing
+            LOG.trace("Exception while shutting down: {}", e.getMessage(), e);
+        } finally {
+            sshd = null;
+        }
+    }
+
+    // disconnect all existing SSH sessions to test reconnect functionality
+    public void disconnectAllSessions() throws IOException {
+        List<AbstractSession> sessions = sshd.getActiveSessions();
+        for (AbstractSession session : sessions) {
+            session.disconnect(4, "dummy");
+        }
+    }
+
+    public byte[] buildKnownHosts() {
+        return String.format(KNOWN_HOSTS, port).getBytes();
+    }
+
+    public String getKnownHostsFile() {
+        return knownHosts.toString();
+    }
+
+    public Path getFtpRootDir() {
+        return rootDir;
+    }
+
+    @Override
+    protected void registerProperties(BiConsumer<String, String> store) {
+        store.accept(FtpProperties.SERVER_HOST, "localhost");
+        store.accept(FtpProperties.SERVER_PORT, String.valueOf(port));
+        store.accept(FtpProperties.ROOT_DIR, rootDir.toString());
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public static boolean hasRequiredAlgorithms() {
+        try {
+            FileKeyPairProvider provider = new FileKeyPairProvider(Paths.get("src/test/resources/hostkey.pem"));
+
+            provider.loadKeys(null);
+            return true;
+        } catch (Exception e) {
+            String name = System.getProperty("os.name");
+            String message = e.getMessage();
+
+            LOG.warn("SunX509 is not available on this platform [{}] Testing is skipped! Real cause: {}", name, message, e);
+            return false;
+        }
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/SftpKeyExchangeProtocolsTest.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/SftpKeyExchangeProtocolsTest.java
new file mode 100644
index 00000000000..b52c5588f4c
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/SftpKeyExchangeProtocolsTest.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file.remote.springboot.sftp;
+
+import com.jcraft.jsch.JSch;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.file.remote.springboot.ftp.BaseFtp;
+import org.apache.camel.component.file.remote.springboot.ftp.FtpAnonymousTest;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.parallel.Isolated;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+        classes = {
+                CamelAutoConfiguration.class,
+                SftpKeyExchangeProtocolsTest.class,
+                SftpKeyExchangeProtocolsTest.TestConfiguration.class
+        }
+)
+//Based on SftpKeyExchangeProtocolsIT
+@Isolated
+public class SftpKeyExchangeProtocolsTest extends BaseSftp {
+
+    @EndpointInject("mock:result")
+    private MockEndpoint result;
+
+    private static String kex;
+
+    @BeforeAll
+    public static void beforeTests() {
+        kex = JSch.getConfig("kex");
+    }
+
+    @AfterAll
+    public static void afterTests() {
+        // restore after test
+        JSch.setConfig("kex", kex);
+    }
+
+    protected String getFtpUrl() {
+        return "sftp://admin@localhost:" + getPort() + "/" + getRootDir() + "/keyExchangeProtocols/?password=admin"
+               + "&noop=true";
+    }
+
+    @Test
+    public void testNonExistingKey() {
+        Throwable exception = Assertions.assertThrows(CamelExecutionException.class,
+                () -> template
+                        .sendBodyAndHeader("sftp://admin@localhost:" + getPort() + "/" + getRootDir() + "}/keyExchangeProtocols?" +
+                                           "password=admin" +
+                                           "&keyExchangeProtocols=nonExistingKeyExchange",
+                                "a", Exchange.FILE_NAME,
+                                "a.txt"));
+
+        final List<String> errorMessages = new ArrayList<>();
+        while (exception.getCause() != null) {
+            errorMessages.add(exception.getCause().getMessage());
+            exception = exception.getCause();
+        }
+
+        MatcherAssert.assertThat(errorMessages, Matchers.hasItem("Algorithm negotiation fail"));
+    }
+
+    @Test
+    public void testSingleKey() throws Exception {
+        result.expectedMessageCount(1);
+
+        template.sendBodyAndHeader("sftp://admin@localhost:" + getPort() + "/" + getRootDir() + "/keyExchangeProtocols" +
+                                   "?password=admin" +
+                                   "&keyExchangeProtocols=ecdh-sha2-nistp384",
+                "a", Exchange.FILE_NAME,
+                "a.txt");
+
+        result.assertIsSatisfied();
+    }
+
+    @Test
+    public void testMultipleKey() throws Exception {
+        result.expectedMessageCount(1);
+
+        template.sendBodyAndHeader("sftp://admin@localhost:" + getPort() + "/" + getRootDir() + "/keyExchangeProtocols" +
+                                   "?password=admin" +
+                                   "&keyExchangeProtocols=ecdh-sha2-nistp384,diffie-hellman-group-exchange-sha256,nonExistingKey",
+                "a", Exchange.FILE_NAME,
+                "a.txt");
+
+        result.assertIsSatisfied();
+    }
+
+    // *************************************
+    // Config
+    // *************************************
+
+    @Configuration
+    public class TestConfiguration extends  BaseFtp.TestConfiguration {
+        @Bean
+        public RouteBuilder routeBuilder() {
+
+            return new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from(getFtpUrl()).routeId("myRoute").to("mock:result");
+                }
+            };
+        }
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/SftpSetOperationsTest.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/SftpSetOperationsTest.java
new file mode 100644
index 00000000000..52cb86a5449
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/SftpSetOperationsTest.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file.remote.springboot.sftp;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.file.remote.SftpEndpoint;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledIf;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.io.File;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@SpringBootTest(
+        classes = {
+                CamelAutoConfiguration.class,
+                SftpSetOperationsTest.class
+        }
+)
+//Based on SftpSetOperationsTest
+public class SftpSetOperationsTest extends BaseSftp {
+
+    @Test
+    public void testSftpSetOperations() {
+        String preferredAuthentications = "password,publickey";
+        String uri = "sftp://localhost:" + getPort() + "/" + getRootDir()
+                     + "?username=admin&password=admin&ciphers=aes256-ctr" + "&preferredAuthentications=password,publickey";
+        template.sendBodyAndHeader(uri, "Hello World", Exchange.FILE_NAME, "hello.txt");
+
+        // test setting the cipher doesn't interfere with message payload
+        File file = ftpFile("hello.txt").toFile();
+        assertTrue(file.exists(), "File should exist: " + file);
+        assertEquals("Hello World", context.getTypeConverter().convertTo(String.class, file));
+
+        // did we actually set the preferredAuthentications
+        SftpEndpoint endpoint = context.getEndpoint(uri, SftpEndpoint.class);
+        assertEquals(preferredAuthentications, endpoint.getConfiguration().getPreferredAuthentications());
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/SftpSimpleProduceThroughProxyTest.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/SftpSimpleProduceThroughProxyTest.java
new file mode 100644
index 00000000000..1bb356978a9
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/SftpSimpleProduceThroughProxyTest.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file.remote.springboot.sftp;
+
+import com.jcraft.jsch.ProxyHTTP;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.file.remote.springboot.ftp.BaseFtp;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.AvailablePortFinder;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.littleshoot.proxy.HttpProxyServer;
+import org.littleshoot.proxy.ProxyAuthenticator;
+import org.littleshoot.proxy.impl.DefaultHttpProxyServer;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+
+import java.io.File;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+        classes = {
+                CamelAutoConfiguration.class,
+                SftpSimpleProduceThroughProxyTest.class,
+                SftpSimpleProduceThroughProxyTest.TestConfiguration.class
+        }
+)
+//Based on SftpSimpleProduceThroughProxyIT
+public class SftpSimpleProduceThroughProxyTest extends BaseSftp {
+
+    private static HttpProxyServer proxyServer;
+    private static final int proxyPort = AvailablePortFinder.getNextAvailable();
+
+    @BeforeAll
+    public static void setupProxy() {
+        proxyServer = DefaultHttpProxyServer.bootstrap()
+                .withPort(proxyPort)
+                .withProxyAuthenticator(new ProxyAuthenticator() {
+                    @Override
+                    public boolean authenticate(String userName, String password) {
+                        return "user".equals(userName) && "password".equals(password);
+                    }
+
+                    @Override
+                    public String getRealm() {
+                        return "myrealm";
+                    }
+                }).start();
+    }
+
+    @AfterAll
+    public static void cleanup() {
+        proxyServer.stop();
+    }
+
+    @Test
+    public void testSftpSimpleProduceThroughProxy() {
+        template.sendBodyAndHeader(
+                "sftp://localhost:" + getPort() + "/" + getRootDir()
+                                   + "?username=admin&password=admin&proxy=#proxy",
+                "Hello World", Exchange.FILE_NAME,
+                "hello.txt");
+
+        File file = ftpFile("hello.txt").toFile();
+        assertTrue(file.exists(), "File should exist: " + file);
+        assertEquals("Hello World", context.getTypeConverter().convertTo(String.class, file));
+    }
+
+    @Test
+    public void testSftpSimpleSubPathProduceThroughProxy() {
+        template.sendBodyAndHeader(
+                "sftp://localhost:" + getPort() + "/" + getRootDir()
+                                   + "/mysub?username=admin&password=admin&proxy=#proxy",
+                "Bye World", Exchange.FILE_NAME,
+                "bye.txt");
+
+        File file = ftpFile("mysub/bye.txt").toFile();
+        assertTrue(file.exists(), "File should exist: " + file);
+        assertEquals("Bye World", context.getTypeConverter().convertTo(String.class, file));
+    }
+
+    @Test
+    public void testSftpSimpleTwoSubPathProduceThroughProxy() {
+        template.sendBodyAndHeader("sftp://localhost:" + getPort() + "/" + getRootDir()
+                                   + "/mysub/myother?username=admin&password=admin&proxy=#proxy",
+                "Farewell World",
+                Exchange.FILE_NAME, "farewell.txt");
+
+        File file = ftpFile("mysub/myother/farewell.txt").toFile();
+        assertTrue(file.exists(), "File should exist: " + file);
+        assertEquals("Farewell World", context.getTypeConverter().convertTo(String.class, file));
+    }
+
+
+
+
+    // *************************************
+    // Config
+    // *************************************
+
+    @Configuration
+    public class TestConfiguration extends  BaseFtp.TestConfiguration {
+        @Bean
+        public RouteBuilder routeBuilder() {
+
+            return new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from("direct:one").to("sftp://localhost:" + getPort() + "/" + getRootDir()
+                            + "?username=admin&password=admin&proxy=#proxy");
+                }
+            };
+        }
+
+        @Bean(value = "proxy")
+        public ProxyHTTP createProxy() {
+
+            final ProxyHTTP proxyHTTP = new ProxyHTTP("localhost", proxyPort);
+            proxyHTTP.setUserPasswd("user", "password");
+            return proxyHTTP;
+        }
+    }
+
+}
diff --git a/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/SftpUseListFalseTest.java b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/SftpUseListFalseTest.java
new file mode 100644
index 00000000000..e754d0cc096
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/java/org/apache/camel/component/file/remote/springboot/sftp/SftpUseListFalseTest.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file.remote.springboot.sftp;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.file.remote.springboot.ftp.BaseFtp;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.apache.camel.util.FileUtil;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledIf;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.io.File;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@CamelSpringBootTest
+@SpringBootTest(
+        classes = {
+                CamelAutoConfiguration.class,
+                SftpUseListFalseTest.class,
+                SftpUseListFalseTest.TestConfiguration.class
+        }
+)
+//Based on SftpUseListFalseIT
+public class SftpUseListFalseTest extends BaseSftp {
+
+    @EndpointInject("mock:result")
+    private MockEndpoint mock;
+
+    @Test
+    public void testSftpUseListFalse() throws Exception {
+        String expected = "Hello World";
+
+        // create file using regular file
+        template.sendBodyAndHeader("file://" + service.getFtpRootDir(), expected, Exchange.FILE_NAME, "report.txt");
+
+        mock.expectedMessageCount(1);
+        mock.expectedHeaderReceived(Exchange.FILE_NAME, "report.txt");
+        mock.expectedBodiesReceived(expected);
+
+        context.getRouteController().startRoute("foo");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    // *************************************
+    // Config
+    // *************************************
+
+    @Configuration
+    public class TestConfiguration extends  BaseFtp.TestConfiguration {
+        @Bean
+        public RouteBuilder routeBuilder() {
+
+            return new RouteBuilder() {
+                @Override
+                public void configure() {
+                    from("sftp://localhost:" + getPort() + "/" + getRootDir()
+                            + "?username=admin&password=admin&delay=10000&disconnect=true&stepwise=false&useList=false&fileName=report.txt&delete=true")
+                            .routeId("foo").noAutoStartup()
+                            .to("mock:result");
+                }
+            };
+        }
+    }
+}
diff --git a/components-starter/camel-ftp-starter/src/test/resources/hostkey.pem b/components-starter/camel-ftp-starter/src/test/resources/hostkey.pem
new file mode 100644
index 00000000000..9b215f45bb4
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/resources/hostkey.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQDdfIWeSV4o68dRrKSzFd/Bk51E65UTmmSrmW0O1ohtzi6HzsDP
+jXgCtlTt3FqTcfFfI92IlTr4JWqC9UK1QT1ZTeng0MkPQmv68hDANHbt5CpETZHj
+W5q4OOgWhVvj5IyOC2NZHtKlJBkdsMAa15ouOOJLzBvAvbqOR/yUROsEiQIDAQAB
+AoGBANG3JDW6NoP8rF/zXoeLgLCj+tfVUPSczhGFVrQkAk4mWfyRkhN0WlwHFOec
+K89MpkV1ij/XPVzU4MNbQ2yod1KiDylzvweYv+EaEhASCmYNs6LS03punml42SL9
+97tOmWfVJXxlQoLiY6jHPU97vTc65k8gL+gmmrpchsW0aqmZAkEA/c8zfmKvY37T
+cxcLLwzwsqqH7g2KZGTf9aRmx2ebdW+QKviJJhbdluDgl1TNNFj5vCLznFDRHiqJ
+wq0wkZ39cwJBAN9l5v3kdXj21UrurNPdlV0n2GZBt2vblooQC37XHF97r2zM7Ou+
+Lg6MyfJClyguhWL9dxnGbf3btQ0l3KDstxMCQCRaiEqjAfIjWVATzeNIXDWLHXso
+b1kf5cA+cwY+vdKdTy4IeUR+Y/DXdvPWDqpf0C11aCVMohdLCn5a5ikFUycCQDhV
+K/BuAallJNfmY7JxN87r00fF3ojWMJnT/fIYMFFrkQrwifXQWTDWE76BSDibsosJ
+u1TGksnm8zrDh2UVC/0CQFrHTiSl/3DHvWAbOJawGKg46cnlDcAhSyV8Frs8/dlP
+7YGG3eqkw++lsghqmFO6mRUTKsBmiiB2wgLGhL5pyYY=
+-----END RSA PRIVATE KEY-----
\ No newline at end of file
diff --git a/components-starter/camel-ftp-starter/src/test/resources/readme.txt b/components-starter/camel-ftp-starter/src/test/resources/readme.txt
new file mode 100644
index 00000000000..2af7c47bcf7
--- /dev/null
+++ b/components-starter/camel-ftp-starter/src/test/resources/readme.txt
@@ -0,0 +1 @@
+server.jks is copied from camel-quarkus/integration-tests/ftp/src/test/resources/server.jks
\ No newline at end of file
diff --git a/components-starter/camel-ftp-starter/src/test/resources/server.jks b/components-starter/camel-ftp-starter/src/test/resources/server.jks
new file mode 100644
index 00000000000..80637220890
Binary files /dev/null and b/components-starter/camel-ftp-starter/src/test/resources/server.jks differ