You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2020/09/18 06:14:53 UTC
[mina-sshd] 01/02: [SSHD-1077] Added command line option to request
specific SFTP version in SftpCommandMain
This is an automated email from the ASF dual-hosted git repository.
lgoldstein pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git
commit 6e68b7621edcb620be010277d234962a6abfbc3f
Author: Lyor Goldstein <lg...@apache.org>
AuthorDate: Thu Sep 17 11:02:32 2020 +0300
[SSHD-1077] Added command line option to request specific SFTP version in SftpCommandMain
---
CHANGES.md | 1 +
.../apache/sshd/cli/client/SftpCommandMain.java | 113 +++++++++++++++------
.../java/org/apache/sshd/common/NamedResource.java | 6 ++
.../sshd/sftp/client/SftpVersionSelector.java | 89 +++++++++++++---
.../sshd/sftp/client/SftpVersionResolverTest.java | 100 ++++++++++++++++++
5 files changed, 264 insertions(+), 45 deletions(-)
diff --git a/CHANGES.md b/CHANGES.md
index a86f891..938bfd5 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -27,6 +27,7 @@ or `-key-file` command line option.
* [SSHD-1060](https://issues.apache.org/jira/browse/SSHD-1060) Do not store logger level in fields.
* [SSHD-1064](https://issues.apache.org/jira/browse/SSHD-1064) Fixed `ClientSession#executeRemoteCommand` handling of STDERR in case of exception to behave according to its documentation
* [SSHD-1076](https://issues.apache.org/jira/browse/SSHD-1076) Break down `ClientUserAuthService#auth` method into several to allow for flexible override
+* [SSHD-1077](https://issues.apache.org/jira/browse/SSHD-1077) Added command line option to request specific SFTP version in `SftpCommandMain`
## Behavioral changes and enhancements
diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java
index 399208f..42a4d1f 100644
--- a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java
+++ b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java
@@ -65,10 +65,13 @@ import org.apache.sshd.common.util.buffer.BufferUtils;
import org.apache.sshd.common.util.io.IoUtils;
import org.apache.sshd.common.util.io.NoCloseInputStream;
import org.apache.sshd.common.util.threads.ThreadUtils;
+import org.apache.sshd.server.config.SshServerConfigFileReader;
import org.apache.sshd.sftp.client.SftpClient;
import org.apache.sshd.sftp.client.SftpClient.Attributes;
import org.apache.sshd.sftp.client.SftpClient.DirEntry;
import org.apache.sshd.sftp.client.SftpClientFactory;
+import org.apache.sshd.sftp.client.SftpVersionSelector;
+import org.apache.sshd.sftp.client.SftpVersionSelector.NamedVersionSelector;
import org.apache.sshd.sftp.client.extensions.openssh.OpenSSHStatExtensionInfo;
import org.apache.sshd.sftp.client.extensions.openssh.OpenSSHStatPathExtension;
import org.apache.sshd.sftp.client.fs.SftpFileSystemProvider;
@@ -268,34 +271,21 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
return sb;
}
- public static SftpClientFactory resolveSftpClientFactory(String... args) {
- int numArgs = GenericUtils.length(args);
- ClassLoader cl = ThreadUtils.resolveDefaultClassLoader(SftpClientFactory.class);
- for (int index = 0; index < numArgs; index++) {
- String argVal = args[index];
- if ("-o".equals(argVal)) {
- index++;
-
- String opt = args[index];
- int idx = opt.indexOf('=');
- ValidateUtils.checkTrue(idx > 0, "bad syntax for option: %s %s", argVal, opt);
-
- String optName = opt.substring(0, idx);
- String optValue = opt.substring(idx + 1);
- if (!Objects.equals(SftpClientFactory.class.getSimpleName(), optName)) {
- continue;
- }
+ /* -------------------------------------------------------------------- */
- try {
- Class<?> clazz = cl.loadClass(optValue);
- return SftpClientFactory.class.cast(clazz.newInstance());
- } catch (Throwable t) {
- System.err.append("Failed (").append(t.getClass().getSimpleName()).append(')')
- .append(" to instantiate ").append(optValue)
- .append(": ").println(t.getMessage());
- System.err.flush();
- throw GenericUtils.toRuntimeException(t, true);
- }
+ public static SftpClientFactory resolveSftpClientFactory(ClientSession session) {
+ ClassLoader cl = ThreadUtils.resolveDefaultClassLoader(SftpClientFactory.class);
+ String factoryName = session.getString(SftpClientFactory.class.getSimpleName());
+ if (GenericUtils.isNotEmpty(factoryName)) {
+ try {
+ Class<?> clazz = cl.loadClass(factoryName);
+ return SftpClientFactory.class.cast(clazz.newInstance());
+ } catch (Throwable t) {
+ System.err.append("Failed (").append(t.getClass().getSimpleName()).append(')')
+ .append(" to instantiate ").append(factoryName)
+ .append(": ").println(t.getMessage());
+ System.err.flush();
+ throw GenericUtils.toRuntimeException(t, true);
}
}
@@ -313,6 +303,15 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
return SftpClientFactory.instance();
}
+ /* -------------------------------------------------------------------- */
+
+ public static NamedVersionSelector resolveVersionSelector(ClientSession session) {
+ String selector = session.getString(SshServerConfigFileReader.SFTP_FORCED_VERSION_PROP.getName());
+ return SftpVersionSelector.resolveVersionSelector(selector);
+ }
+
+ /* -------------------------------------------------------------------- */
+
public static void main(String[] args) throws Exception {
PrintStream stdout = System.out;
PrintStream stderr = System.err;
@@ -330,15 +329,23 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
if (session == null) {
System.err.println("usage: sftp [-v[v][v]] [-E logoutput] [-i identity] [-io nio2|mina|netty]"
+ " [-J proxyJump] [-l login] [" + SFTP_PORT_OPTION + " port] [-o option=value]"
- + " [-w password] [-c cipherlist] [-m maclist] [-C] hostname/user@host");
+ + " [-w password] [-c cipherlist] [-m maclist] [-C] hostname/user@host");
System.exit(-1);
return;
}
try {
- // TODO allow command-line specification of SftpClientFactory
- SftpClientFactory clientFactory = resolveSftpClientFactory(args);
- try (SftpClient sftpClient = clientFactory.createSftpClient(session);
+ SftpClientFactory clientFactory = resolveSftpClientFactory(session);
+ if ((level != null) && (level.intValue() <= Level.INFO.intValue())) {
+ stdout.append("Using factory=").println(clientFactory.getClass().getSimpleName());
+ }
+
+ SftpVersionSelector versionSelector = resolveVersionSelector(session);
+ if ((level != null) && (level.intValue() <= Level.INFO.intValue())) {
+ stdout.append("Using version selector=").println(versionSelector);
+ }
+
+ try (SftpClient sftpClient = clientFactory.createSftpClient(session, versionSelector);
SftpCommandMain sftp = new SftpCommandMain(sftpClient)) {
// TODO allow injection of extra CommandExecutor(s) via command line and/or service loading
sftp.doInteractive(stdin, stdout, stderr);
@@ -353,6 +360,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ //////////////////////////////////////////////////////////////////////////
+
private static class ExitCommandExecutor implements SftpCommandExecutor {
ExitCommandExecutor() {
super();
@@ -373,6 +382,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class PwdCommandExecutor implements SftpCommandExecutor {
protected PwdCommandExecutor() {
super();
@@ -394,6 +405,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class SessionCommandExecutor implements SftpCommandExecutor {
SessionCommandExecutor() {
super();
@@ -424,6 +437,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class KexCommandExecutor implements SftpCommandExecutor {
KexCommandExecutor() {
super();
@@ -456,6 +471,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class ClientCommandExecutor implements SftpCommandExecutor {
ClientCommandExecutor() {
super();
@@ -494,6 +511,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class InfoCommandExecutor implements SftpCommandExecutor {
InfoCommandExecutor() {
super();
@@ -534,6 +553,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class VersionCommandExecutor implements SftpCommandExecutor {
VersionCommandExecutor() {
super();
@@ -555,6 +576,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class CdCommandExecutor extends PwdCommandExecutor {
CdCommandExecutor() {
super();
@@ -578,6 +601,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class LcdCommandExecutor extends PwdCommandExecutor {
LcdCommandExecutor() {
super();
@@ -605,6 +630,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class MkdirCommandExecutor implements SftpCommandExecutor {
MkdirCommandExecutor() {
super();
@@ -628,6 +655,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class LsCommandExecutor implements SftpCommandExecutor {
LsCommandExecutor() {
super();
@@ -670,6 +699,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class RmCommandExecutor implements SftpCommandExecutor {
RmCommandExecutor() {
super();
@@ -757,6 +788,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class RmdirCommandExecutor implements SftpCommandExecutor {
RmdirCommandExecutor() {
super();
@@ -780,6 +813,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class RenameCommandExecutor implements SftpCommandExecutor {
RenameCommandExecutor() {
super();
@@ -805,6 +840,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class StatVfsCommandExecutor implements SftpCommandExecutor {
StatVfsCommandExecutor() {
super();
@@ -846,6 +883,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class LStatCommandExecutor implements SftpCommandExecutor {
LStatCommandExecutor() {
super();
@@ -871,6 +910,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class ReadLinkCommandExecutor implements SftpCommandExecutor {
ReadLinkCommandExecutor() {
super();
@@ -895,6 +936,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class HelpCommandExecutor implements SftpCommandExecutor {
HelpCommandExecutor() {
super();
@@ -918,6 +961,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private abstract class TransferCommandExecutor implements SftpCommandExecutor {
protected TransferCommandExecutor() {
super();
@@ -1101,6 +1146,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class GetCommandExecutor extends TransferCommandExecutor {
GetCommandExecutor() {
super();
@@ -1120,6 +1167,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class PutCommandExecutor extends TransferCommandExecutor {
PutCommandExecutor() {
super();
@@ -1139,6 +1188,8 @@ public class SftpCommandMain extends SshClientCliSupport implements Channel {
}
}
+ /* -------------------------------------------------------------------- */
+
private class ProgressCommandExecutor implements SftpCommandExecutor {
ProgressCommandExecutor() {
super();
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/NamedResource.java b/sshd-common/src/main/java/org/apache/sshd/common/NamedResource.java
index 6421539..256ecfd 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/NamedResource.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/NamedResource.java
@@ -122,4 +122,10 @@ public interface NamedResource {
}
};
}
+
+ static int safeCompareByName(NamedResource r1, NamedResource r2, boolean caseSensitive) {
+ String n1 = (r1 == null) ? null : r1.getName();
+ String n2 = (r2 == null) ? null : r2.getName();
+ return GenericUtils.safeCompare(n1, n2, caseSensitive);
+ }
}
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/SftpVersionSelector.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/SftpVersionSelector.java
index 0099960..3dac99e 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/SftpVersionSelector.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/SftpVersionSelector.java
@@ -21,9 +21,12 @@ package org.apache.sshd.sftp.client;
import java.util.Collection;
import java.util.List;
+import java.util.Objects;
+import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.NamedResource;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.NumberUtils;
import org.apache.sshd.common.util.ValidateUtils;
@@ -36,12 +39,12 @@ public interface SftpVersionSelector {
/**
* An {@link SftpVersionSelector} that returns the current version
*/
- SftpVersionSelector CURRENT = new NamedVersionSelector("CURRENT", (session, initial, current, available) -> current);
+ NamedVersionSelector CURRENT = new NamedVersionSelector("CURRENT", (session, initial, current, available) -> current);
/**
* An {@link SftpVersionSelector} that returns the maximum available version
*/
- SftpVersionSelector MAXIMUM = new NamedVersionSelector(
+ NamedVersionSelector MAXIMUM = new NamedVersionSelector(
"MAXIMUM",
(session, initial, current, available) -> GenericUtils.stream(available).mapToInt(Integer::intValue).max()
.orElse(current));
@@ -49,7 +52,7 @@ public interface SftpVersionSelector {
/**
* An {@link SftpVersionSelector} that returns the minimum available version
*/
- SftpVersionSelector MINIMUM = new NamedVersionSelector(
+ NamedVersionSelector MINIMUM = new NamedVersionSelector(
"MINIMUM",
(session, initial, current, available) -> GenericUtils.stream(available).mapToInt(Integer::intValue).min()
.orElse(current));
@@ -70,9 +73,9 @@ public interface SftpVersionSelector {
* eventually thrown by the client during re-negotiation phase.
*
* @param version The requested version
- * @return The {@link SftpVersionSelector}
+ * @return The {@link NamedVersionSelector} wrapping the requested version
*/
- static SftpVersionSelector fixedVersionSelector(int version) {
+ static NamedVersionSelector fixedVersionSelector(int version) {
return new NamedVersionSelector(Integer.toString(version), (session, initial, current, available) -> version);
}
@@ -83,10 +86,10 @@ public interface SftpVersionSelector {
*
* @param preferred The preferred versions in decreasing order of preference (i.e., most preferred is 1st) - may
* not be {@code null}/empty
- * @return A {@link SftpVersionSelector} that attempts to select the most preferred version that is also
+ * @return A {@link NamedVersionSelector} that attempts to select the most preferred version that is also
* listed as available.
*/
- static SftpVersionSelector preferredVersionSelector(int... preferred) {
+ static NamedVersionSelector preferredVersionSelector(int... preferred) {
return preferredVersionSelector(NumberUtils.asList(preferred));
}
@@ -96,10 +99,10 @@ public interface SftpVersionSelector {
* is invoked
*
* @param preferred The preferred versions in decreasing order of preference (i.e., most preferred is 1st)
- * @return A {@link SftpVersionSelector} that attempts to select the most preferred version that is also
+ * @return A {@link NamedVersionSelector} that attempts to select the most preferred version that is also
* listed as available.
*/
- static SftpVersionSelector preferredVersionSelector(Iterable<? extends Number> preferred) {
+ static NamedVersionSelector preferredVersionSelector(Iterable<? extends Number> preferred) {
ValidateUtils.checkNotNullAndNotEmpty((Collection<?>) preferred, "Empty preferred versions");
return new NamedVersionSelector(
GenericUtils.join(preferred, ','),
@@ -111,13 +114,46 @@ public interface SftpVersionSelector {
"Preferred versions (" + preferred + ") not available: " + available)));
}
- class NamedVersionSelector implements SftpVersionSelector {
+ /**
+ * Parses the input string to see if it matches one of the "known" selectors names (case insensitive). If
+ * not, then checks if it is a single number and uses it as a {@link #fixedVersionSelector(int) fixed} version.
+ * Otherwise, assumes a comma separated list of versions in preferred order.
+ *
+ * @param selector The selector value - if {@code null}/empty then returns {@link #CURRENT}
+ * @return Parsed {@link NamedVersionSelector}
+ */
+ static NamedVersionSelector resolveVersionSelector(String selector) {
+ if (GenericUtils.isEmpty(selector)) {
+ return SftpVersionSelector.CURRENT;
+ } else if (selector.equalsIgnoreCase(SftpVersionSelector.CURRENT.getName())) {
+ return SftpVersionSelector.CURRENT;
+ } else if (selector.equalsIgnoreCase(SftpVersionSelector.MINIMUM.getName())) {
+ return SftpVersionSelector.MINIMUM;
+ } else if (selector.equalsIgnoreCase(SftpVersionSelector.MAXIMUM.getName())) {
+ return SftpVersionSelector.MAXIMUM;
+ } else if (NumberUtils.isIntegerNumber(selector)) {
+ return SftpVersionSelector.fixedVersionSelector(Integer.parseInt(selector));
+ } else {
+ String[] preferred = GenericUtils.split(selector, ',');
+ int[] prefs = Stream.of(preferred).mapToInt(Integer::parseInt).toArray();
+ return SftpVersionSelector.preferredVersionSelector(prefs);
+ }
+ }
+
+ /**
+ * Wraps a {@link SftpVersionSelector} and assigns it a name. <B>Note:</B> {@link NamedVersionSelector} are
+ * considered equal if they are assigned the same name - case <U>insensitive</U>
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+ class NamedVersionSelector implements SftpVersionSelector, NamedResource {
+ protected final SftpVersionSelector selector;
+
private final String name;
- private final SftpVersionSelector selector;
public NamedVersionSelector(String name, SftpVersionSelector selector) {
- this.name = name;
- this.selector = selector;
+ this.name = ValidateUtils.checkNotNullAndNotEmpty(name, "No name provided");
+ this.selector = Objects.requireNonNull(selector, "No delegate selector provided");
}
@Override
@@ -126,8 +162,33 @@ public interface SftpVersionSelector {
}
@Override
- public String toString() {
+ public String getName() {
return name;
}
+
+ @Override
+ public int hashCode() {
+ return GenericUtils.hashCode(getName(), Boolean.TRUE);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ return NamedResource.safeCompareByName(this, (NamedVersionSelector) obj, false) == 0;
+ }
+
+ @Override
+ public String toString() {
+ return getName();
+ }
}
}
diff --git a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/SftpVersionResolverTest.java b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/SftpVersionResolverTest.java
new file mode 100644
index 0000000..527fc8e
--- /dev/null
+++ b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/SftpVersionResolverTest.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.sshd.sftp.client;
+
+import java.util.Collection;
+import java.util.LinkedList;
+
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.sftp.client.SftpVersionSelector.NamedVersionSelector;
+import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.Assume;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Parameterized.UseParametersRunnerFactory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests
+@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Category({ NoIoTestCase.class })
+public class SftpVersionResolverTest extends JUnitTestSupport {
+ private final NamedVersionSelector expected;
+ private final NamedVersionSelector actual;
+
+ public SftpVersionResolverTest(String selector, NamedVersionSelector expected) {
+ this.expected = expected;
+ this.actual = SftpVersionSelector.resolveVersionSelector(selector);
+ }
+
+ @Parameters(name = "selector={0}")
+ public static Collection<Object[]> parameters() {
+ return new LinkedList<Object[]>() {
+ // Not serializing it
+ private static final long serialVersionUID = 1L;
+
+ {
+ addTestCase(null, SftpVersionSelector.CURRENT);
+ addTestCase("", SftpVersionSelector.CURRENT);
+ addTestCase(SftpVersionSelector.CURRENT);
+ addTestCase(SftpVersionSelector.MINIMUM);
+ addTestCase(SftpVersionSelector.MAXIMUM);
+ addTestCase(SftpVersionSelector.fixedVersionSelector(3));
+ addTestCase(SftpVersionSelector.preferredVersionSelector(3, 4, 5));
+ }
+
+ private void addTestCase(NamedVersionSelector expected) {
+ addTestCase(expected.getName(), expected);
+ }
+
+ private void addTestCase(String selector, NamedVersionSelector expected) {
+ add(new Object[] { selector, expected });
+ }
+ };
+ }
+
+ @Test
+ public void testResolvedResult() {
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testPreDefinedSelectorResolution() {
+ Assume.assumeTrue("Pre-defined selector ?",
+ (NamedResource.safeCompareByName(SftpVersionSelector.CURRENT, expected, false) == 0)
+ || (NamedResource.safeCompareByName(SftpVersionSelector.MINIMUM, expected, false) == 0)
+ || (NamedResource.safeCompareByName(SftpVersionSelector.MAXIMUM, expected, false) == 0));
+ assertSame(expected, actual);
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[expected=" + expected + ", actual=" + actual + "]";
+ }
+}