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 2015/11/16 07:13:38 UTC
mina-sshd git commit: [SSHD-583] ssh_config Host entry should support
'!' pattern
Repository: mina-sshd
Updated Branches:
refs/heads/master ef317acff -> bc0ab58ba
[SSHD-583] ssh_config Host entry should support '!' pattern
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/bc0ab58b
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/bc0ab58b
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/bc0ab58b
Branch: refs/heads/master
Commit: bc0ab58ba229c6733a5b94eac7d98a8f9521015e
Parents: ef317ac
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Mon Nov 16 08:13:21 2015 +0200
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Mon Nov 16 08:13:21 2015 +0200
----------------------------------------------------------------------
.../client/config/hosts/HostConfigEntry.java | 237 +++++++++----------
.../hosts/HostConfigEntryResolverTest.java | 21 ++
.../config/hosts/HostConfigEntryTest.java | 72 +++---
3 files changed, 172 insertions(+), 158 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/bc0ab58b/sshd-core/src/main/java/org/apache/sshd/client/config/hosts/HostConfigEntry.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/config/hosts/HostConfigEntry.java b/sshd-core/src/main/java/org/apache/sshd/client/config/hosts/HostConfigEntry.java
index 7485d4e..884aee5 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/config/hosts/HostConfigEntry.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/config/hosts/HostConfigEntry.java
@@ -54,6 +54,7 @@ import org.apache.sshd.common.config.SshConfigFileReader;
import org.apache.sshd.common.config.keys.IdentityUtils;
import org.apache.sshd.common.config.keys.PublicKeyEntry;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Pair;
import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.io.IoUtils;
import org.apache.sshd.common.util.io.NoCloseInputStream;
@@ -66,7 +67,7 @@ import org.apache.sshd.common.util.io.NoCloseReader;
* file format</A>
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class HostConfigEntry implements Cloneable, UsernameHolder {
+public class HostConfigEntry implements UsernameHolder {
/**
* Used in a host pattern to denote zero or more consecutive characters
@@ -85,9 +86,14 @@ public class HostConfigEntry implements Cloneable, UsernameHolder {
public static final char SINGLE_CHAR_PATTERN = '?';
/**
+ * Used to negate a host pattern
+ */
+ public static final char NEGATION_CHAR_PATTERN = '!';
+
+ /**
* The available pattern characters
*/
- public static final String PATTERN_CHARS = new String(new char[]{WILDCARD_PATTERN, SINGLE_CHAR_PATTERN});
+ public static final String PATTERN_CHARS = new String(new char[]{WILDCARD_PATTERN, SINGLE_CHAR_PATTERN, NEGATION_CHAR_PATTERN});
public static final String HOST_CONFIG_PROP = "Host";
public static final String HOST_NAME_CONFIG_PROP = "HostName";
@@ -126,12 +132,12 @@ public class HostConfigEntry implements Cloneable, UsernameHolder {
private static final Path KEYS_FILE = PublicKeyEntry.getDefaultKeysFolderPath().resolve(STD_CONFIG_FILENAME);
}
- private String hostValue;
- private Pattern hostPattern;
+ private String host;
private String hostName;
private int port;
private String username;
private Boolean exclusiveIdentites;
+ private Collection<Pair<Pattern, Boolean>> patterns = new LinkedList<>();
private Collection<String> identities = Collections.emptyList();
private Map<String, String> properties = Collections.emptyMap();
@@ -147,35 +153,35 @@ public class HostConfigEntry implements Cloneable, UsernameHolder {
}
/**
- * @return The host <U>pattern</U> represented by this entry
- * @see <A HREF="http://www.gsp.com/cgi-bin/man.cgi?topic=ssh_config#3">Host Patterns</A>
+ * @return The <U>pattern(s)</U> represented by this entry
*/
public String getHost() {
- return hostValue;
+ return host;
}
- public Pattern getHostPattern() {
- return hostPattern;
+ public void setHost(String host) {
+ this.host = host;
+ this.patterns = parsePatterns(parseConfigValue(host));
}
- /**
- * @param host The host name/address/pattern represented by the entry
- */
- public void setHost(String host) {
- hostValue = host;
- hostPattern = toPattern(host);
+ public void setHost(Collection<String> patterns) {
+ this.host = GenericUtils.join(ValidateUtils.checkNotNullAndNotEmpty(patterns, "No patterns"), ',');
+ this.patterns = parsePatterns(patterns);
+ }
+
+ public Collection<Pair<Pattern, Boolean>> getPatterns() {
+ return patterns;
}
/**
- * Checks if a given host name / address matches the entry's host pattern
+ * Checks if a given host name / address matches the entry's host pattern(s)
*
* @param host The host name / address - ignored if {@code null}/empty
- * @return {@code true} if the name / address matches the pattern
- * @see #getHostPattern()
+ * @return {@code true} if the name / address matches the pattern(s)
* @see #isHostMatch(String, Pattern)
*/
public boolean isHostMatch(String host) {
- return isHostMatch(host, getHostPattern());
+ return isHostMatch(host, getPatterns());
}
/**
@@ -601,35 +607,6 @@ public class HostConfigEntry implements Cloneable, UsernameHolder {
}
@Override
- public HostConfigEntry clone() {
- try {
- HostConfigEntry other = getClass().cast(super.clone());
-
- // avoid shared instances
- other.setIdentities(null);
- Collection<String> ids = this.getIdentities();
- if (GenericUtils.size(ids) > 0) {
- for (String kp : ids) {
- other.addIdentity(kp);
- }
- }
-
- // avoid shared instances
- other.setProperties(null);
- Map<String, String> props = this.getProperties();
- if (GenericUtils.size(props) > 0) {
- for (Map.Entry<String, String> pe : props.entrySet()) {
- other.setProperty(pe.getKey(), pe.getValue());
- }
- }
-
- return other;
- } catch (CloneNotSupportedException e) {
- throw new RuntimeException("Failed (" + e.getClass().getSimpleName() + ") to clone " + toString() + ": " + e.getMessage(), e);
- }
- }
-
- @Override
public String toString() {
return getHost() + ": " + getUsername() + "@" + getHostName() + ":" + getPort();
}
@@ -769,14 +746,20 @@ public class HostConfigEntry implements Cloneable, UsernameHolder {
*/
public static HostConfigEntry normalizeEntry(HostConfigEntry entry, String host, int port, String username) throws IOException {
if (entry == null) {
- return entry;
+ return null;
}
- HostConfigEntry normal = entry.clone();
+ HostConfigEntry normal = new HostConfigEntry();
+ normal.setHost(host);
normal.setHostName(entry.resolveHostName(host));
normal.setPort(entry.resolvePort(port));
normal.setUsername(entry.resolveUsername(username));
+ Map<String, String> props = entry.getProperties();
+ if (GenericUtils.size(props) > 0) {
+ normal.setProperties(new TreeMap<String, String>(props));
+ }
+
Collection<String> ids = entry.getIdentities();
if (GenericUtils.isEmpty(ids)) {
return normal;
@@ -882,6 +865,7 @@ public class HostConfigEntry implements Cloneable, UsernameHolder {
* @return {@code true} if the pattern is not empty and contains no wildcard characters
* @see #WILDCARD_PATTERN
* @see #SINGLE_CHAR_PATTERN
+ * @see #SINGLE_CHAR_PATTERN
*/
public static boolean isSpecificHostPattern(String pattern) {
if (GenericUtils.isEmpty(pattern)) {
@@ -997,17 +981,39 @@ public class HostConfigEntry implements Cloneable, UsernameHolder {
}
}
- /**
- * Checks if a given host name / address matches a host pattern
- *
- * @param host The host name / address - ignored if {@code null}/empty
- * @param pattern The host pattern string - ignored if {@code null}/empty
- * @return {@code true} if the name / address matches the pattern
- * @see #toPattern(String)
- * @see #isHostMatch(String, Pattern)
- */
- public static boolean isHostMatch(String host, CharSequence pattern) {
- return isHostMatch(host, toPattern(pattern));
+ public static boolean isHostMatch(String host, Collection<Pair<Pattern, Boolean>> patterns) {
+ if (GenericUtils.isEmpty(patterns)) {
+ return false;
+ }
+
+ boolean matchFound = false;
+ for (Pair<Pattern, Boolean> pp : patterns) {
+ Boolean negated = pp.getSecond();
+ /*
+ * If already found a match we are interested only in negations
+ */
+ if (matchFound && (!negated.booleanValue())) {
+ continue;
+ }
+
+ if (!isHostMatch(host, pp.getFirst())) {
+ continue;
+ }
+
+ /*
+ * According to https://www.freebsd.org/cgi/man.cgi?query=ssh_config&sektion=5:
+ *
+ * If a negated entry is matched, then the Host entry is ignored,
+ * regardless of whether any other patterns on the line match.
+ */
+ if (negated.booleanValue()) {
+ return false;
+ }
+
+ matchFound = true;
+ }
+
+ return matchFound;
}
/**
@@ -1026,22 +1032,37 @@ public class HostConfigEntry implements Cloneable, UsernameHolder {
return m.matches();
}
+ public static List<Pair<Pattern, Boolean>> parsePatterns(Collection<? extends CharSequence> patterns) {
+ if (GenericUtils.isEmpty(patterns)) {
+ return Collections.emptyList();
+ }
+
+ List<Pair<Pattern, Boolean>> result = new ArrayList<>(patterns.size());
+ for (CharSequence p : patterns) {
+ result.add(ValidateUtils.checkNotNull(toPattern(p), "No pattern for %s", p));
+ }
+
+ return result;
+ }
+
/**
* Converts a host pattern string to a regular expression matcher.
* <B>Note:</B> pattern matching is <U>case insensitive</U>
*
* @param pattern The original pattern string - ignored if {@code null}/empty
- * @return The regular expression matcher {@link Pattern} - {@code null}
- * if empty original string
+ * @return The regular expression matcher {@link Pattern} and the indication
+ * whether it is a negating pattern or not - {@code null} if no original string
* @see #WILDCARD_PATTERN
* @see #SINGLE_CHAR_PATTERN
+ * @see #NEGATION_CHAR_PATTERN
*/
- public static Pattern toPattern(CharSequence pattern) {
+ public static Pair<Pattern, Boolean> toPattern(CharSequence pattern) {
if (GenericUtils.isEmpty(pattern)) {
return null;
}
StringBuilder sb = new StringBuilder(pattern.length());
+ boolean negated = false;
for (int curPos = 0; curPos < pattern.length(); curPos++) {
char ch = pattern.charAt(curPos);
ValidateUtils.checkTrue(isValidPatternChar(ch), "Invalid host pattern char in %s", pattern);
@@ -1056,12 +1077,17 @@ public class HostConfigEntry implements Cloneable, UsernameHolder {
case WILDCARD_PATTERN:
sb.append(".*");
break;
+ case NEGATION_CHAR_PATTERN:
+ ValidateUtils.checkTrue(!negated, "Double negation in %s", pattern);
+ ValidateUtils.checkTrue(curPos == 0, "Negation must be 1st char: %s", pattern);
+ negated = true;
+ break;
default:
sb.append(ch);
}
}
- return Pattern.compile(sb.toString(), Pattern.CASE_INSENSITIVE);
+ return new Pair<Pattern, Boolean>(Pattern.compile(sb.toString(), Pattern.CASE_INSENSITIVE), Boolean.valueOf(negated));
}
/**
@@ -1097,7 +1123,7 @@ public class HostConfigEntry implements Cloneable, UsernameHolder {
if ("-_.".indexOf(ch) >= 0) {
return true;
}
- if ((ch == SINGLE_CHAR_PATTERN) || (ch == WILDCARD_PATTERN)) {
+ if (PATTERN_CHARS.indexOf(ch) >= 0) {
return true;
}
return false;
@@ -1148,7 +1174,6 @@ public class HostConfigEntry implements Cloneable, UsernameHolder {
HostConfigEntry curEntry = null;
HostConfigEntry globalEntry = null;
List<HostConfigEntry> entries = null;
- List<String> multiHosts = Collections.emptyList();
int lineNumber = 1;
for (String line = rdr.readLine(); line != null; line = rdr.readLine(), lineNumber++) {
@@ -1200,21 +1225,14 @@ public class HostConfigEntry implements Cloneable, UsernameHolder {
curEntry.processGlobalValues(globalEntry);
}
- entries = updateEntriesList(entries, curEntry, multiHosts);
+ entries = updateEntriesList(entries, curEntry);
curEntry = new HostConfigEntry();
- curEntry.setHost(valsList.get(0));
- // allow for multiple hosts patterns
- if (valsList.size() > 1) {
- multiHosts = valsList.subList(1, valsList.size());
- } else {
- multiHosts = Collections.emptyList();
- }
+ curEntry.setHost(valsList);
} else if (curEntry == null) {
// if 1st encountered property is NOT for a specific host, then configuration applies to ALL
curEntry = new HostConfigEntry();
- curEntry.setHost(ALL_HOSTS_PATTERN);
- multiHosts = Collections.emptyList();
+ curEntry.setHost(Collections.singletonList(ALL_HOSTS_PATTERN));
globalEntry = curEntry;
}
@@ -1231,7 +1249,7 @@ public class HostConfigEntry implements Cloneable, UsernameHolder {
curEntry.processGlobalValues(globalEntry);
}
- entries = updateEntriesList(entries, curEntry, multiHosts);
+ entries = updateEntriesList(entries, curEntry);
if (entries == null) {
return Collections.emptyList();
} else {
@@ -1239,6 +1257,18 @@ public class HostConfigEntry implements Cloneable, UsernameHolder {
}
}
+ public static List<HostConfigEntry> updateEntriesList(List<HostConfigEntry> entries, HostConfigEntry curEntry) {
+ if (curEntry == null) {
+ return entries;
+ }
+
+ if (entries == null) {
+ entries = new ArrayList<>();
+ }
+
+ entries.add(curEntry);
+ return entries;
+ }
public static void writeHostConfigEntries(File file, Collection<? extends HostConfigEntry> entries) throws IOException {
writeHostConfigEntries(ValidateUtils.checkNotNull(file, "No file").toPath(), entries, IoUtils.EMPTY_OPEN_OPTIONS);
}
@@ -1272,57 +1302,6 @@ public class HostConfigEntry implements Cloneable, UsernameHolder {
}
/**
- * @param entries The original list - if {@code null} one will be allocated if necessary
- * @param curEntry The current entry - ignored if {@code null}
- * @param hosts The extra host patterns to be attached to the entry - ignored
- * if {@code null}/empty
- * @return The updated list of entries - same as input if nothing added
- * @see #duplicateConfiguration(HostConfigEntry, Collection)
- */
- public static List<HostConfigEntry> updateEntriesList(List<HostConfigEntry> entries, HostConfigEntry curEntry, Collection<String> hosts) {
- if (curEntry == null) {
- return entries;
- }
-
- // TODO consider allowing multiple patterns for same entry instead of duplicating the entries
- Collection<HostConfigEntry> dups = duplicateConfiguration(curEntry, hosts);
- int extraHosts = Math.max(0, GenericUtils.size(dups));
- if (entries == null) {
- entries = new ArrayList<>(Math.max(1 + extraHosts, Byte.SIZE));
- }
-
- entries.add(curEntry);
-
- if (extraHosts > 0) {
- entries.addAll(dups);
- }
-
- return entries;
- }
-
- /**
- * @param entry The original entry to duplicate - ignored if {@code null}
- * @param hosts The hosts patterns to attach to each duplicated entry -
- * ignored if {@code null}/empty
- * @return A {@link List} of duplicated entries where each new entry host
- * pattern is updated from the given one
- */
- public static List<HostConfigEntry> duplicateConfiguration(HostConfigEntry entry, Collection<String> hosts) {
- if ((entry == null) || GenericUtils.isEmpty(hosts)) {
- return Collections.emptyList();
- }
-
- List<HostConfigEntry> dups = new ArrayList<>(hosts.size());
- for (String pattern : hosts) {
- HostConfigEntry cloned = entry.clone();
- cloned.setHost(pattern);
- dups.add(cloned);
- }
-
- return dups;
- }
-
- /**
* Checks if this is a multi-value - allow space and comma
*
* @param value The value - ignored if {@code null}/empty (after trimming)
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/bc0ab58b/sshd-core/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryResolverTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryResolverTest.java b/sshd-core/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryResolverTest.java
index 7680b46..b0c9029 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryResolverTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryResolverTest.java
@@ -27,6 +27,7 @@ import java.nio.file.Path;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.PublicKey;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
@@ -110,6 +111,26 @@ public class HostConfigEntryResolverTest extends BaseTestSupport {
}
@Test
+ public void testNegatedHostEntriesResolution() throws Exception {
+ HostConfigEntry positiveEntry = new HostConfigEntry(TEST_LOCALHOST, TEST_LOCALHOST, port, getCurrentTestName());
+ HostConfigEntry negativeEntry = new HostConfigEntry(
+ String.valueOf(HostConfigEntry.NEGATION_CHAR_PATTERN) + positiveEntry.getHost(),
+ positiveEntry.getHostName(),
+ getMovedPortNumber(positiveEntry.getPort()),
+ getClass().getPackage().getName());
+ client.setHostConfigEntryResolver(HostConfigEntry.toHostConfigEntryResolver(Arrays.asList(negativeEntry, positiveEntry)));
+ client.start();
+
+ try(ClientSession session = client.connect(negativeEntry.getUsername(), negativeEntry.getHostName(), negativeEntry.getPort()).verify(7L, TimeUnit.SECONDS).getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+ assertEffectiveRemoteAddress(session, positiveEntry);
+ } finally {
+ client.stop();
+ }
+ }
+
+ @Test
public void testPreloadedIdentities() throws Exception {
final KeyPair identity = Utils.getFirstKeyPair(sshd);
final String USER = getCurrentTestName();
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/bc0ab58b/sshd-core/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryTest.java b/sshd-core/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryTest.java
index 394871b..fe43b62 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/config/hosts/HostConfigEntryTest.java
@@ -25,10 +25,10 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
import java.util.regex.Pattern;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Pair;
import org.apache.sshd.util.test.BaseTestSupport;
import org.junit.FixMethodOrder;
import org.junit.Test;
@@ -44,6 +44,38 @@ public class HostConfigEntryTest extends BaseTestSupport {
}
@Test
+ public void testNegatingPatternOverridesAll() {
+ String testHost = "37.77.34.7";
+ String[] elements = GenericUtils.split(testHost, '.');
+ StringBuilder sb = new StringBuilder(testHost.length() + Byte.SIZE);
+ List<Pair<Pattern, Boolean>> patterns = new ArrayList<>(elements.length + 1);
+ // all wildcard patterns are not negated - only the actual host
+ patterns.add(HostConfigEntry.toPattern(String.valueOf(HostConfigEntry.NEGATION_CHAR_PATTERN) + testHost));
+
+ for (int i = 0; i < elements.length; i++) {
+ sb.setLength(0);
+
+ for (int j = 0; j < elements.length; j++) {
+ if (j > 0) {
+ sb.append('.');
+ }
+ if (i == j) {
+ sb.append(HostConfigEntry.WILDCARD_PATTERN);
+ } else {
+ sb.append(elements[j]);
+ }
+ }
+
+ patterns.add(HostConfigEntry.toPattern(sb));
+ }
+
+ for (int index = 0; index < patterns.size(); index++) {
+ assertFalse("Unexpected match for " + patterns, HostConfigEntry.isHostMatch(testHost, patterns));
+ Collections.shuffle(patterns);
+ }
+ }
+
+ @Test
public void testHostWildcardPatternMatching() {
String pkgName = getClass().getPackage().getName();
String[] elements = GenericUtils.split(pkgName, '.');
@@ -53,7 +85,8 @@ public class HostConfigEntryTest extends BaseTestSupport {
}
String value = sb.toString();
- Pattern pattern = HostConfigEntry.toPattern(value);
+ Pair<Pattern, Boolean> pp = HostConfigEntry.toPattern(value);
+ Pattern pattern = pp.getFirst();
String domain = value.substring(1); // chomp the wildcard prefix
for (String host : new String[] {
getClass().getSimpleName(),
@@ -73,7 +106,7 @@ public class HostConfigEntryTest extends BaseTestSupport {
StringBuilder sb = new StringBuilder().append("10.0.0.");
int sbLen = sb.length();
- Pattern pattern = HostConfigEntry.toPattern(sb.append(HostConfigEntry.WILDCARD_PATTERN));
+ Pattern pattern = HostConfigEntry.toPattern(sb.append(HostConfigEntry.WILDCARD_PATTERN)).getFirst();
for (int v = 0; v <= 255; v++) {
sb.setLength(sbLen); // start from scratch
sb.append(v);
@@ -90,7 +123,7 @@ public class HostConfigEntryTest extends BaseTestSupport {
for (boolean restoreOriginal : new boolean[] { true, false }) {
for (int index = 0; index < value.length(); index++) {
sb.setCharAt(index, HostConfigEntry.SINGLE_CHAR_PATTERN);
- testCaseInsensitivePatternMatching(value, HostConfigEntry.toPattern(sb.toString()), true);
+ testCaseInsensitivePatternMatching(value, HostConfigEntry.toPattern(sb.toString()).getFirst(), true);
if (restoreOriginal) {
sb.setCharAt(index, value.charAt(index));
}
@@ -112,9 +145,10 @@ public class HostConfigEntryTest extends BaseTestSupport {
for (int index = sbLen; index < sb.length(); index++) {
sb.setCharAt(index, HostConfigEntry.SINGLE_CHAR_PATTERN);
}
- String pattern = sb.toString();
- assertTrue("No match for " + address + " on pattern=" + pattern, HostConfigEntry.isHostMatch(address, pattern));
+ String pattern = sb.toString();
+ Pair<Pattern, Boolean> pp = HostConfigEntry.toPattern(pattern);
+ assertTrue("No match for " + address + " on pattern=" + pattern, HostConfigEntry.isHostMatch(address, Collections.singletonList(pp)));
}
}
@@ -141,7 +175,7 @@ public class HostConfigEntryTest extends BaseTestSupport {
}
for (char ch : new char[] {
- '(', ')', '{', '}', '[', ']', '!', '@',
+ '(', ')', '{', '}', '[', ']', '@',
'#', '$', '^', '&', '%', '~', '<', '>',
',', '/', '\\', '\'', '"', ':', ';' }) {
assertFalse("Unexpected valid character: " + String.valueOf(ch), HostConfigEntry.isValidPatternChar(ch));
@@ -201,28 +235,8 @@ public class HostConfigEntryTest extends BaseTestSupport {
@Test
public void testReadMultipleHostPatterns() throws IOException {
List<HostConfigEntry> entries = validateHostConfigEntries(readHostConfigEntries());
- assertEquals("Mismatched number of duplicates", 3, GenericUtils.size(entries));
-
- HostConfigEntry prototype = entries.get(0);
- String protoIds = GenericUtils.join(prototype.getIdentities(), ',');
- Collection<Map.Entry<String,String>> protoProps = prototype.getProperties().entrySet();
- for (int index = 1; index < entries.size(); index++) {
- HostConfigEntry entry = entries.get(index);
- assertEquals("Mismatched host name for " + entry, prototype.getHostName(), entry.getHostName());
- assertEquals("Mismatched port for " + entry, prototype.getPort(), entry.getPort());
- assertSame("Mismatched user for " + entry, prototype.getUsername(), entry.getUsername());
- assertEquals("Mismatched identities for " + entry, protoIds, GenericUtils.join(entry.getIdentities(), ','));
-
- Map<String,String> entryProps = entry.getProperties();
- assertEquals("Mismatched properties count for " + entry, GenericUtils.size(protoProps), GenericUtils.size(entryProps));
-
- for (Map.Entry<String,String> ppe : protoProps) {
- String key = ppe.getKey();
- String expected = ppe.getValue();
- String actual = entryProps.get(key);
- assertEquals("Mismatched value for " + key + " property of " + entry, expected, actual);
- }
- }
+ assertEquals("Mismatched number of entries", 1, GenericUtils.size(entries));
+ assertEquals("Mismatched number of patterns", 3, GenericUtils.size(entries.get(0).getPatterns()));
}
@Test