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