[nifi] branch main updated: NIFI-9538: Add C2 heartbeat capability to minifi-c2-service
This is an automated email from the ASF dual-hosted git repository. kdoran pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/nifi.git The following commit(s) were added to refs/heads/main by this push: new b5e61109f6 NIFI-9538: Add C2 heartbeat capability to minifi-c2-service b5e61109f6 is described below commit b5e61109f6d5d7331d7cd0c7027ad9250c347852 Author: Matthew Burgess AuthorDate: Wed Feb 9 13:49:23 2022 -0500 NIFI-9538: Add C2 heartbeat capability to minifi-c2-service - Added content hash code to avoid repeatedly updating with the same flow - Gracefully handle agent classes and provide update URL to /config - Fixed JDK 8 build issue with ConfigService This closes #5755. Signed-off-by: Kevin Doran --- .../apache/nifi/minifi/c2/api/Configuration.java | 8 + minifi/minifi-c2/minifi-c2-assembly/pom.xml| 2 +- .../src/main/resources/conf/authorizations.yaml| 28 .../FileSystemWritableConfiguration.java | 11 ++ .../c2/cache/s3/S3WritableConfiguration.java | 8 +- .../minifi-c2-provider-nifi-rest/pom.xml | 7 +- minifi/minifi-c2/minifi-c2-service/pom.xml | 22 ++- .../minifi/c2/configuration/C2ResourceConfig.java | 3 + .../C2JsonProvider.java} | 32 ++-- .../C2JsonProviderFeature.java}| 23 ++- .../nifi/minifi/c2/service/C2ProtocolContext.java | 96 +++ .../C2ProtocolService.java}| 21 +-- .../nifi/minifi/c2/service/ConfigService.java | 182 +++-- .../minifi/c2/service/SimpleC2ProtocolService.java | 127 ++ minifi/pom.xml | 2 +- 15 files changed, 513 insertions(+), 59 deletions(-) diff --git a/minifi/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/Configuration.java b/minifi/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/Configuration.java index 90fbdba346..3f78b52269 100644 --- a/minifi/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/Configuration.java +++ b/minifi/minifi-c2/minifi-c2-api/src/main/java/org/apache/nifi/minifi/c2/api/Configuration.java @@ -18,6 +18,7 @@ package org.apache.nifi.minifi.c2.api; import java.io.InputStream; +import java.net.URL; /** * Represents a MiNiFi configuration of a given version, format matches the format of the ConfigurationProvider @@ -44,4 +45,11 @@ public interface Configuration { * @return an input stream to read the configuration with */ InputStream getInputStream() throws ConfigurationProviderException; + +/** + * Gets the URL of the resource + * + * @return the URL of the resource + */ +URL getURL() throws ConfigurationProviderException; } diff --git a/minifi/minifi-c2/minifi-c2-assembly/pom.xml b/minifi/minifi-c2/minifi-c2-assembly/pom.xml index ba2553e395..148a6efe7b 100644 --- a/minifi/minifi-c2/minifi-c2-assembly/pom.xml +++ b/minifi/minifi-c2/minifi-c2-assembly/pom.xml @@ -26,7 +26,7 @@ limitations under the License. pom This is the assembly of Apache MiNiFi's - Command And Control Server -10080 +10090 false ./conf/keystore.jks diff --git a/minifi/minifi-c2/minifi-c2-assembly/src/main/resources/conf/authorizations.yaml b/minifi/minifi-c2/minifi-c2-assembly/src/main/resources/conf/authorizations.yaml index 5669451940..14386e5c17 100644 --- a/minifi/minifi-c2/minifi-c2-assembly/src/main/resources/conf/authorizations.yaml +++ b/minifi/minifi-c2/minifi-c2-assembly/src/main/resources/conf/authorizations.yaml @@ -37,3 +37,31 @@ Paths: # Default authorization lets anonymous pull any config. Remove below to change that. - Authorization: ROLE_ANONYMOUS Action: allow + + /c2/config/heartbeat: +Default Action: deny +Actions: + - Authorization: CLASS_RASPI_3 +Query Parameters: + class: raspi3 +Action: allow + - Authorization: ROLE_SUPERUSER +Action: allow + + # Default authorization lets anonymous pull any config. Remove below to change that. + - Authorization: ROLE_ANONYMOUS +Action: allow + + /c2/config/acknowledge: +Default Action: deny +Actions: + - Authorization: CLASS_RASPI_3 +Query Parameters: + class: raspi3 +Action: allow + - Authorization: ROLE_SUPERUSER +Action: allow + + # Default authorization lets anonymous pull any config. Remove below to change that. + - Authorization: ROLE_ANONYMOUS +Action: allow diff --git a/minifi/minifi-c2/minifi-c2-cache/minifi-c2-cache-filesystem/src/main/java/org/apache/nifi/minifi/c2/cache/filesystem/FileSystemWritableConfiguration.java
[nifi] branch main updated: NIFI-9960 Add documentation for Sensitive Dynamic Properties (#6089)
This is an automated email from the ASF dual-hosted git repository. andrewmlim pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/nifi.git The following commit(s) were added to refs/heads/main by this push: new 5a2992c243 NIFI-9960 Add documentation for Sensitive Dynamic Properties (#6089) 5a2992c243 is described below commit 5a2992c243e81724ce13033a9818df28d4c3af95 Author: exceptionfactory AuthorDate: Thu Jun 2 07:12:22 2022 -0500 NIFI-9960 Add documentation for Sensitive Dynamic Properties (#6089) * NIFI-9960 Added documentation for Sensitive Dynamic Properties - Updated User Guide with Add Property details - Updated Developer Guide with annotation configuration details - Updated Document Writer to indicate Supports Sensitive Dynamic Properties status * NIFI-9960 Adjusted User Guide wording based on feedback --- nifi-docs/src/main/asciidoc/developer-guide.adoc | 34 ++--- .../images/add-property-sensitive-value-dialog.png | Bin 0 -> 15549 bytes nifi-docs/src/main/asciidoc/user-guide.adoc| 15 +++-- .../html/HtmlDocumentationWriter.java | 16 ++ .../html/ProcessorDocumentationWriterTest.java | 2 ++ 5 files changed, 61 insertions(+), 6 deletions(-) diff --git a/nifi-docs/src/main/asciidoc/developer-guide.adoc b/nifi-docs/src/main/asciidoc/developer-guide.adoc index a136e149a5..d654a7a77a 100644 --- a/nifi-docs/src/main/asciidoc/developer-guide.adoc +++ b/nifi-docs/src/main/asciidoc/developer-guide.adoc @@ -326,21 +326,47 @@ instance of the `PropertyDescriptor.Builder` object, calling the appropriate methods on the builder, and finally calling the `build` method. -While this method covers most of the use cases, it is sometimes += Dynamic Processor Properties + +In addition to standard properties, it is sometimes desirable to allow users to configure -additional properties whose name are not known. This can be achieved -by overriding the +additional properties whose names are not predefined. +This can be achieved by overriding the `getSupportedDynamicPropertyDescriptor` method. This method takes a `String` as its only argument, which indicates the name of the property. The method returns a `PropertyDescriptor` object that can be used to validate both the name of the property, as well as the value. Any PropertyDescriptor that is returned from this method -should be built setting the value of `isDynamic` to true in the +should be built setting the value of `isDynamic` to `true` in the `PropertyDescriptor.Builder` class. The default behavior of AbstractProcessor is to not allow any dynamically created properties. += Sensitive Dynamic Properties + +The default implementation for dynamic properties does not treat the +property values as sensitive. This approach is sufficient when configuring +features such as FlowFile attributes or custom expressions, but it does +not provide protection for values such as passwords or keys. + +NiFi 1.17.0 introduced framework support for sensitive dynamic properties +through a new behavior annotation named `SupportsSensitiveDynamicProperties`. +The annotation can be applied to a Processor, Controller Service, or +Reporting Task that supports dynamic properties through the +`getSupportedDynamicPropertyDescriptor` method. The annotation indicates +that the component allows individual dynamic properties to be marked as +sensitive for the purpose of persistence and framework processing. + +The `getSupportedDynamicPropertyDescriptor` must return a `PropertyDescriptor` +with the `sensitive` field set to `false` to allow customization of sensitive +status. Setting the `sensitive` field to `true` in this method forces all +dynamic properties to be handled as sensitive. This approach allows sensitive +status to be upgraded in supported components, but not downgraded. + +Secure handling of sensitive property values is the responsibility of the +annotated class. Components that support sensitive dynamic properties must +not log property values or provide property values as FlowFile attributes. Validating Processor Properties diff --git a/nifi-docs/src/main/asciidoc/images/add-property-sensitive-value-dialog.png b/nifi-docs/src/main/asciidoc/images/add-property-sensitive-value-dialog.png new file mode 100644 index 00..6bdf906064 Binary files /dev/null and b/nifi-docs/src/main/asciidoc/images/add-property-sensitive-value-dialog.png differ diff --git a/nifi-docs/src/main/asciidoc/user-guide.adoc b/nifi-docs/src/main/asciidoc/user-guide.adoc index 9b6286b40f..2dbc063db6 100644 --- a/nifi-docs/src/main/asciidoc/user-guide.adoc +++ b/nifi-docs/src/main/asciidoc/user-guide.adoc @@ -690,8 +690,19 @@ image::edit-property-dropdown.png["Edit Property with Dropdown"] In the top-right corner of the tab is a button for adding a New Property. Clicking this button will provide the DFM with a dialog to enter
[nifi] branch main updated: NIFI-10054: Improve SendTrapSNMP error handling
This is an automated email from the ASF dual-hosted git repository. pvillard pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/nifi.git The following commit(s) were added to refs/heads/main by this push: new 04aa32cd57 NIFI-10054: Improve SendTrapSNMP error handling 04aa32cd57 is described below commit 04aa32cd576ef47a7ec1b7a2df4f5f60b8b9a6bd Author: Lehel AuthorDate: Thu May 26 18:35:14 2022 +0200 NIFI-10054: Improve SendTrapSNMP error handling Signed-off-by: Pierre Villard This closes #6081. --- .../nifi/snmp/operations/SendTrapSNMPHandler.java | 10 +- .../snmp/operations/SendTrapSNMPHandlerTest.java | 41 +- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SendTrapSNMPHandler.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SendTrapSNMPHandler.java index f9f608d670..6b2a3bfc2a 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SendTrapSNMPHandler.java +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SendTrapSNMPHandler.java @@ -25,6 +25,8 @@ import org.apache.nifi.snmp.utils.SNMPUtils; import org.snmp4j.PDU; import org.snmp4j.Snmp; import org.snmp4j.Target; +import org.snmp4j.event.ResponseEvent; +import org.snmp4j.smi.TransportIpAddress; import java.io.IOException; import java.time.Instant; @@ -62,7 +64,13 @@ public class SendTrapSNMPHandler { logger.debug("No optional SNMP specific variables found in flowfile."); } -snmpManager.send(pdu, target); +final ResponseEvent response = snmpManager.send(pdu, target); +if (response == null) { +final int port = ((TransportIpAddress) target.getAddress()).getPort(); +throw new IOException(String.format("The sent PDU has not been confirmed, the target port [%d] may be unavailable.", port)); +} else if (response.getError() != null) { +throw new IOException("An error occurred while sending trap.", response.getError()); +} } V1TrapPDUFactory createV1TrapPduFactory(final Instant startTime) { diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SendTrapSNMPHandlerTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SendTrapSNMPHandlerTest.java index 6a202055f4..b7bed1d682 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SendTrapSNMPHandlerTest.java +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SendTrapSNMPHandlerTest.java @@ -18,6 +18,7 @@ package org.apache.nifi.snmp.operations; import org.apache.nifi.snmp.configuration.V1TrapConfiguration; import org.apache.nifi.snmp.configuration.V2TrapConfiguration; +import org.apache.nifi.snmp.exception.SNMPException; import org.apache.nifi.snmp.factory.trap.V1TrapPDUFactory; import org.apache.nifi.snmp.factory.trap.V2TrapPDUFactory; import org.apache.nifi.util.MockComponentLog; @@ -27,12 +28,16 @@ import org.junit.Test; import org.snmp4j.PDU; import org.snmp4j.Snmp; import org.snmp4j.Target; +import org.snmp4j.event.ResponseEvent; +import org.snmp4j.smi.TransportIpAddress; import java.io.IOException; import java.time.Instant; import java.util.Collections; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -42,6 +47,7 @@ public class SendTrapSNMPHandlerTest { private Target mockTarget; private Snmp mockSnmpManager; private PDU mockPdu; +private ResponseEvent mockResponseEvent; private MockComponentLog mockComponentLog; private V1TrapConfiguration mockV1TrapConfiguration; private V2TrapConfiguration mockV2TrapConfiguration; @@ -49,10 +55,11 @@ public class SendTrapSNMPHandlerTest { private SendTrapSNMPHandler sendTrapSNMPHandler; @Before -public void init() { +public void init() throws IOException { mockTarget = mock(Target.class); mockSnmpManager = mock(Snmp.class); mockPdu = mock(PDU.class); +mockResponseEvent = mock(ResponseEvent.class); mockComponentLog = new MockComponentLog("id", new Object()); mockV1TrapConfiguration = mock(V1TrapConfiguration.class); mockV2TrapConfiguration = mock(V2TrapConfiguration.class); @@ -61,6 +68,8 @@ public class SendTrapSNMPHandlerTest { V2TrapPDUFactory mockV2TrapPDUFactory =
[nifi] branch main updated: NIFI-6943 Set DataDogReportingTask API Key Property as Sensitive
This is an automated email from the ASF dual-hosted git repository. pvillard pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/nifi.git The following commit(s) were added to refs/heads/main by this push: new 7f93cb4c91 NIFI-6943 Set DataDogReportingTask API Key Property as Sensitive 7f93cb4c91 is described below commit 7f93cb4c91914d7e5cf4b2933deafa99d52893ee Author: exceptionfactory AuthorDate: Wed Jun 1 13:04:28 2022 -0500 NIFI-6943 Set DataDogReportingTask API Key Property as Sensitive - Corrected Logger handling and improved unit tests Signed-off-by: Pierre Villard This closes #6090. --- .../reporting/datadog/DataDogReportingTask.java| 18 ++-- .../datadog/TestDataDogReportingTask.java | 95 ++ 2 files changed, 48 insertions(+), 65 deletions(-) diff --git a/nifi-nar-bundles/nifi-datadog-bundle/nifi-datadog-reporting-task/src/main/java/org/apache/nifi/reporting/datadog/DataDogReportingTask.java b/nifi-nar-bundles/nifi-datadog-bundle/nifi-datadog-reporting-task/src/main/java/org/apache/nifi/reporting/datadog/DataDogReportingTask.java index 7026a2d416..9ac94bcd4c 100644 --- a/nifi-nar-bundles/nifi-datadog-bundle/nifi-datadog-reporting-task/src/main/java/org/apache/nifi/reporting/datadog/DataDogReportingTask.java +++ b/nifi-nar-bundles/nifi-datadog-bundle/nifi-datadog-reporting-task/src/main/java/org/apache/nifi/reporting/datadog/DataDogReportingTask.java @@ -35,8 +35,6 @@ import org.apache.nifi.reporting.AbstractReportingTask; import org.apache.nifi.reporting.ReportingContext; import org.apache.nifi.reporting.datadog.metrics.MetricsService; import org.coursera.metrics.datadog.DynamicTagsCallback; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.Collections; import java.util.Map; @@ -69,6 +67,7 @@ public class DataDogReportingTask extends AbstractReportingTask { .name("API key") .description("Datadog API key. If specified value is 'agent', local Datadog agent will be used.") .required(false) +.sensitive(true) .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) .build(); @@ -96,11 +95,9 @@ public class DataDogReportingTask extends AbstractReportingTask { private MetricRegistry metricRegistry; private String metricsPrefix; private String environment; -private String statusId; private ConcurrentHashMap metricsMap; private Map defaultTags; private volatile JmxJvmMetrics virtualMachineMetrics; -private Logger logger = LoggerFactory.getLogger(getClass().getName()); @OnScheduled public void setup(final ConfigurationContext context) { @@ -130,15 +127,14 @@ public class DataDogReportingTask extends AbstractReportingTask { metricsPrefix = context.getProperty(METRICS_PREFIX).evaluateAttributeExpressions().getValue(); environment = context.getProperty(ENVIRONMENT).evaluateAttributeExpressions().getValue(); -statusId = status.getId(); final Map tags = new HashMap<>(); tags.put("env", environment); -tags.put("dataflow_id", statusId); +tags.put("dataflow_id", status.getId()); defaultTags = Collections.unmodifiableMap(tags); try { updateDataDogTransport(context); } catch (IOException e) { -logger.warn("Unable to update data dog transport", e); +getLogger().warn("Unable to update data dog transport", e); } updateAllMetricGroups(status); ddMetricRegistryBuilder.getDatadogReporter().report(); @@ -147,7 +143,7 @@ public class DataDogReportingTask extends AbstractReportingTask { protected void updateMetrics(Map metrics, Map tags) { for (Map.Entry entry : metrics.entrySet()) { final String metricName = buildMetricName(entry.getKey()); -logger.debug(metricName + ": " + entry.getValue()); +getLogger().debug("Metric [{}] Value [{}]", metricName, entry.getValue()); //if metric is not registered yet - register it if (!metricsMap.containsKey(metricName)) { metricsMap.put(metricName, entry.getValue()); @@ -189,9 +185,9 @@ public class DataDogReportingTask extends AbstractReportingTask { updateMetrics(metricsService.getDataFlowMetrics(processGroupStatus), defaultTags); } -private class MetricGauge implements Gauge, DynamicTagsCallback { -private Map tags; -private String metricName; +private class MetricGauge implements Gauge, DynamicTagsCallback { +private final Map tags; +private final String metricName; public MetricGauge(String metricName, Map tagsMap) { this.tags = tagsMap; diff --git
[nifi] branch main updated: NIFI-10075 Improved TestListSFTP configuration verification
This is an automated email from the ASF dual-hosted git repository. pvillard pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/nifi.git The following commit(s) were added to refs/heads/main by this push: new 1f9672c18b NIFI-10075 Improved TestListSFTP configuration verification 1f9672c18b is described below commit 1f9672c18bd6ccac4386bae8083793d8e74dd9df Author: exceptionfactory AuthorDate: Wed Jun 1 16:28:54 2022 -0500 NIFI-10075 Improved TestListSFTP configuration verification - Changed assertVerificationSuccess() to separate testVerificationSuccessful() method - Upgraded TestListSFTP to JUnit 5 Signed-off-by: Pierre Villard This closes #6092. --- .../nifi/processors/standard/TestListSFTP.java | 46 ++ 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestListSFTP.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestListSFTP.java index 6dd969d8cc..f9077f8fbd 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestListSFTP.java +++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestListSFTP.java @@ -22,7 +22,6 @@ import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; @@ -43,29 +42,28 @@ import org.apache.nifi.serialization.record.MockRecordWriter; import org.apache.nifi.util.MockFlowFile; import org.apache.nifi.util.TestRunner; import org.apache.nifi.util.TestRunners; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class TestListSFTP { private static final String REMOTE_DIRECTORY = "/"; +private static final int TEMPORARY_FILES = 3; + private static final byte[] FILE_CONTENTS = String.class.getName().getBytes(StandardCharsets.UTF_8); private TestRunner runner; private SSHTestServer sshServer; -private List testFileNames; - -@Before -public void setUp() throws Exception { +@BeforeEach +public void startServer() throws Exception { sshServer = new SSHTestServer(); sshServer.startServer(); -testFileNames = new ArrayList(); -writeTempFile(3); +writeTempFile(); runner = TestRunners.newTestRunner(ListSFTP.class); runner.setProperty(ListSFTP.HOSTNAME, sshServer.getHost()); runner.setProperty(ListSFTP.USERNAME, sshServer.getUsername()); @@ -74,17 +72,16 @@ public class TestListSFTP { runner.setProperty(ListSFTP.REMOTE_PATH, REMOTE_DIRECTORY); runner.setProperty(ListFile.TARGET_SYSTEM_TIMESTAMP_PRECISION, ListFile.PRECISION_MILLIS); runner.assertValid(); -assertVerificationSuccess(); } -@After -public void tearDown() throws Exception { +@AfterEach +public void stopServer() throws Exception { sshServer.stopServer(); Files.deleteIfExists(Paths.get(sshServer.getVirtualFileSystemPath())); } @Test -public void testRunFileFound() throws InterruptedException { +public void testRunFileFound() { runner.run(1); runner.assertTransferCount(ListSFTP.REL_SUCCESS, 3); runner.assertAllFlowFilesContainAttribute("sftp.remote.host"); @@ -102,7 +99,7 @@ public class TestListSFTP { } @Test -public void testRunWithRecordWriter() throws InitializationException, InterruptedException { +public void testRunWithRecordWriter() throws InitializationException { RecordSetWriterFactory recordWriter = getCsvRecordWriter(); runner.addControllerService("csv-record-writer", recordWriter); runner.setProperty(AbstractListProcessor.RECORD_WRITER, "csv-record-writer"); @@ -114,7 +111,7 @@ public class TestListSFTP { } @Test -public void testRunWithRecordWriterNoTracking() throws InitializationException, InterruptedException { +public void testRunWithRecordWriterNoTracking() throws InitializationException { RecordSetWriterFactory recordWriter = getCsvRecordWriter(); runner.addControllerService("csv-record-writer", recordWriter); runner.setProperty(AbstractListProcessor.RECORD_WRITER, "csv-record-writer"); @@ -126,7 +123,7 @@ public class TestListSFTP { } @Test -public void