commit cb9c62a90e30052db5599bc469da95de161af087 Author: Karsten Loesing karsten.loesing@gmx.net Date: Thu Dec 15 20:45:42 2011 +0100
Make votes use the general network-status parsing code. --- .../descriptor/RelayNetworkStatusVote.java | 11 +- .../descriptor/impl/NetworkStatusImpl.java | 20 +- .../impl/RelayNetworkStatusVoteImpl.java | 577 ++++++++++++-------- .../impl/RelayNetworkStatusVoteImplTest.java | 574 +++++++++++++++++++ 4 files changed, 933 insertions(+), 249 deletions(-)
diff --git a/src/org/torproject/descriptor/RelayNetworkStatusVote.java b/src/org/torproject/descriptor/RelayNetworkStatusVote.java index 6bfdd6f..aab90bd 100644 --- a/src/org/torproject/descriptor/RelayNetworkStatusVote.java +++ b/src/org/torproject/descriptor/RelayNetworkStatusVote.java @@ -27,8 +27,11 @@ public interface RelayNetworkStatusVote extends Descriptor { /* Return the valid-until time in milliseconds. */ public long getValidUntilMillis();
- /* Return a list of the voting-delay times in seconds. */ - public List<Long> getVotingDelay(); + /* Return the VoteSeconds time in seconds. */ + public long getVoteSeconds(); + + /* Return the DistSeconds time in seconds. */ + public long getDistSeconds();
/* Return recommended server versions or null if the authority doesn't * recommend server versions. */ @@ -65,6 +68,10 @@ public interface RelayNetworkStatusVote extends Descriptor { /* Return the directory key certificate version. */ public int getDirKeyCertificateVersion();
+ /* Return the legacy key or null if the directory authority does not use + * a legacy key. */ + public String getLegacyKey(); + /* Return the directory key publication timestamp. */ public long getDirKeyPublishedMillis();
diff --git a/src/org/torproject/descriptor/impl/NetworkStatusImpl.java b/src/org/torproject/descriptor/impl/NetworkStatusImpl.java index 6ca546e..af8b9e2 100644 --- a/src/org/torproject/descriptor/impl/NetworkStatusImpl.java +++ b/src/org/torproject/descriptor/impl/NetworkStatusImpl.java @@ -51,6 +51,7 @@ public abstract class NetworkStatusImpl { protected NetworkStatusImpl(byte[] rawDescriptorBytes) throws DescriptorParseException { this.rawDescriptorBytes = rawDescriptorBytes; + this.countKeywords(rawDescriptorBytes); this.splitAndParseParts(rawDescriptorBytes); }
@@ -126,7 +127,6 @@ public abstract class NetworkStatusImpl { System.arraycopy(this.rawDescriptorBytes, start, headerBytes, 0, end - start); this.rememberFirstKeyword(headerBytes); - this.countKeywords(headerBytes); this.parseHeader(headerBytes); }
@@ -153,7 +153,6 @@ public abstract class NetworkStatusImpl { byte[] directoryFooterBytes = new byte[end - start]; System.arraycopy(this.rawDescriptorBytes, start, directoryFooterBytes, 0, end - start); - this.countKeywords(directoryFooterBytes); this.parseFooter(directoryFooterBytes); }
@@ -264,17 +263,17 @@ public abstract class NetworkStatusImpl { * subclasses. */ private Map<String, Integer> parsedKeywords = new HashMap<String, Integer>(); - protected void countKeywords(byte[] headerOrFooterBytes) + protected void countKeywords(byte[] rawDescriptorBytes) throws DescriptorParseException { try { BufferedReader br = new BufferedReader(new StringReader( - new String(headerOrFooterBytes))); + new String(rawDescriptorBytes))); String line; boolean skipCrypto = false; while ((line = br.readLine()) != null) { if (line.startsWith("-----BEGIN")) { skipCrypto = true; - } else if (line.equals("-----END")) { + } else if (line.startsWith("-----END")) { skipCrypto = false; } else if (!skipCrypto) { String keyword = line.split(" ", -1)[0]; @@ -299,11 +298,14 @@ public abstract class NetworkStatusImpl { protected void checkExactlyOnceKeywords(Set<String> keywords) throws DescriptorParseException { for (String keyword : keywords) { - if (!this.parsedKeywords.containsKey(keyword) || - this.parsedKeywords.get(keyword) != 1) { + int contained = 0; + if (this.parsedKeywords.containsKey(keyword)) { + contained = this.parsedKeywords.get(keyword); + } + if (contained != 1) { throw new DescriptorParseException("Keyword '" + keyword + "' is " - + "contained " + this.parsedKeywords.get(keyword) + " times, " - + "but must be contained exactly once."); + + "contained " + contained + " times, but must be contained " + + "exactly once."); } } } diff --git a/src/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java b/src/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java index a7a5328..5089210 100644 --- a/src/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java +++ b/src/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java @@ -7,258 +7,341 @@ import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.SortedMap; import java.util.SortedSet; -import java.util.TimeZone; import java.util.TreeMap; import java.util.TreeSet; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import org.torproject.descriptor.Descriptor; -import org.torproject.descriptor.NetworkStatusEntry; import org.torproject.descriptor.RelayNetworkStatusVote;
+/* TODO Find out if all keywords in the dir-source section are required. + * They are not all mentioned in dir-spec.txt. */ + /* Contains a network status vote. */ -/* TODO This class is sharing a lot of parsing code with the consensus - * class. Should there be an abstract super class for the two? */ -public class RelayNetworkStatusVoteImpl +public class RelayNetworkStatusVoteImpl extends NetworkStatusImpl implements RelayNetworkStatusVote {
protected static List<RelayNetworkStatusVote> parseVotes( - byte[] voteBytes) { + byte[] votesBytes) { List<RelayNetworkStatusVote> parsedVotes = new ArrayList<RelayNetworkStatusVote>(); - String startToken = "network-status-version 3"; - String splitToken = "\n" + startToken; - String ascii = new String(voteBytes); - int length = voteBytes.length, start = ascii.indexOf(startToken); - while (start < length) { - int end = ascii.indexOf(splitToken, start); - if (end < 0) { - end = length; - } else { - end += 1; + List<byte[]> splitVotesBytes = + NetworkStatusImpl.splitRawDescriptorBytes(votesBytes, + "network-status-version 3"); + try { + for (byte[] voteBytes : splitVotesBytes) { + RelayNetworkStatusVote parsedVote = + new RelayNetworkStatusVoteImpl(voteBytes); + parsedVotes.add(parsedVote); } - byte[] descBytes = new byte[end - start]; - System.arraycopy(voteBytes, start, descBytes, 0, end - start); - RelayNetworkStatusVote parsedVote = - new RelayNetworkStatusVoteImpl(descBytes); - parsedVotes.add(parsedVote); - start = end; + } catch (DescriptorParseException e) { + /* TODO Handle this error somehow. */ + System.err.println("Failed to parse vote. Skipping."); + e.printStackTrace(); } return parsedVotes; }
- protected RelayNetworkStatusVoteImpl(byte[] voteBytes) { - this.voteBytes = voteBytes; - this.parseVoteBytes(); - this.checkConsistency(); - /* TODO Find a way to handle parse and consistency-check problems. */ + protected RelayNetworkStatusVoteImpl(byte[] voteBytes) + throws DescriptorParseException { + super(voteBytes); + Set<String> exactlyOnceKeywords = new HashSet<String>(Arrays.asList(( + "vote-status,consensus-methods,published,valid-after,fresh-until," + + "valid-until,voting-delay,known-flags,dir-source," + + "dir-key-certificate-version,fingerprint,dir-key-published," + + "dir-key-expires,directory-footer").split(","))); + this.checkExactlyOnceKeywords(exactlyOnceKeywords); + Set<String> atMostOnceKeywords = new HashSet<String>(Arrays.asList(( + "client-versions,server-versions,params,contact,legacy-key"). + split(","))); + this.checkAtMostOnceKeywords(atMostOnceKeywords); + this.checkFirstKeyword("network-status-version"); }
- private void parseVoteBytes() { - String line = null; + protected void parseHeader(byte[] headerBytes) + throws DescriptorParseException { try { BufferedReader br = new BufferedReader(new StringReader( - new String(this.voteBytes))); - SimpleDateFormat dateTimeFormat = new SimpleDateFormat( - "yyyy-MM-dd HH:mm:ss"); - dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - StringBuilder dirSourceEntryLines = null, statusEntryLines = null; - boolean skipCrypto = false; + new String(headerBytes))); + String line; while ((line = br.readLine()) != null) { - if (line.startsWith("network-status-version ")) { - this.networkStatusVersion = Integer.parseInt(line.substring( - "network-status-version ".length())); - } else if (line.startsWith("vote-status ")) { - if (!line.equals("vote-status vote")) { - throw new RuntimeException("Line '" + line + "' indicates " - + "that this string is not a vote. Aborting parsing."); - } - } else if (line.startsWith("consensus-methods ")) { - for (String consensusMethodString : line.substring( - "consensus-methods ".length()).split(" ")) { - this.consensusMethods.add(Integer.parseInt( - consensusMethodString)); - } - } else if (line.startsWith("published ")) { - this.publishedMillis = dateTimeFormat.parse( - line.substring("published ".length())).getTime(); - } else if (line.startsWith("valid-after ")) { - this.validAfterMillis = dateTimeFormat.parse( - line.substring("valid-after ".length())).getTime(); - } else if (line.startsWith("fresh-until ")) { - this.freshUntilMillis = dateTimeFormat.parse( - line.substring("fresh-until ".length())).getTime(); - } else if (line.startsWith("valid-until ")) { - this.validUntilMillis = dateTimeFormat.parse( - line.substring("valid-until ".length())).getTime(); - } else if (line.startsWith("voting-delay ")) { - for (String votingDelayString : line.substring( - "voting-delay ".length()).split(" ")) { - this.votingDelay.add(Long.parseLong(votingDelayString)); - } - } else if (line.startsWith("client-versions ")) { - this.recommendedClientVersions = - Arrays.asList(line.split(" ")[1].split(",")); - } else if (line.startsWith("server-versions ")) { - this.recommendedServerVersions = - Arrays.asList(line.split(" ")[1].split(",")); - } else if (line.startsWith("known-flags ")) { - for (String flag : line.substring("known-flags ".length()). - split(" ")) { - this.knownFlags.add(flag); - } - } else if (line.startsWith("params ")) { - if (line.length() > "params ".length()) { - for (String param : - line.substring("params ".length()).split(" ")) { - String paramName = param.split("=")[0]; - int paramValue = Integer.parseInt(param.split("=")[1]); - this.consensusParams.put(paramName, paramValue); - } - } - } else if (line.startsWith("dir-source ")) { - String[] parts = line.split(" "); - this.nickname = parts[1]; - this.identity = parts[2]; - this.address = parts[4]; - this.dirPort = Integer.parseInt(parts[5]); - this.orPort = Integer.parseInt(parts[6]); - /* TODO Add code for parsing legacy dir sources. */ - } else if (line.startsWith("contact ")) { - this.contactLine = line.substring("contact ".length()); - } else if (line.startsWith("dir-key-certificate-version ")) { - this.dirKeyCertificateVersion = Integer.parseInt(line.substring( - "dir-key-certificate-version ".length())); - } else if (line.startsWith("fingerprint ")) { - /* Nothing new to learn here. We already know the fingerprint - * from the dir-source line. */ - } else if (line.startsWith("dir-key-published ")) { - this.dirKeyPublishedMillis = dateTimeFormat.parse( - line.substring("dir-key-published ".length())).getTime(); - } else if (line.startsWith("dir-key-expires ")) { - this.dirKeyExpiresMillis = dateTimeFormat.parse( - line.substring("dir-key-expires ".length())).getTime(); - } else if (line.equals("dir-identity-key") || - line.equals("dir-signing-key") || - line.equals("dir-key-crosscert") || - line.equals("dir-key-certification")) { - /* Ignore crypto parts for now. */ - } else if (line.startsWith("r ") || - line.equals("directory-footer")) { - if (statusEntryLines != null) { - try { - NetworkStatusEntryImpl statusEntry = - new NetworkStatusEntryImpl( - statusEntryLines.toString().getBytes()); - this.statusEntries.put(statusEntry.getFingerprint(), - statusEntry); - } catch (DescriptorParseException e) { - System.err.println("Could not parse status entry in vote. " - + "Skipping."); - } - statusEntryLines = null; - } - if (line.startsWith("r ")) { - statusEntryLines = new StringBuilder(); - statusEntryLines.append(line + "\n"); - } - } else if (line.startsWith("s ") || line.equals("s") || - line.startsWith("opt v ") || line.startsWith("w ") || - line.startsWith("p ") || line.startsWith("m ")) { - statusEntryLines.append(line + "\n"); - } else if (line.startsWith("directory-signature ")) { - String[] parts = line.split(" "); - String identity = parts[1]; - String signingKeyDigest = parts[2]; - this.directorySignatures.put(identity, signingKeyDigest); - } else if (line.startsWith("-----BEGIN")) { - skipCrypto = true; - } else if (line.startsWith("-----END")) { - skipCrypto = false; - } else if (!skipCrypto) { - throw new RuntimeException("Unrecognized line '" + line + "'."); + String[] parts = line.split(" "); + String keyword = parts[0]; + if (keyword.equals("network-status-version")) { + this.parseNetworkStatusVersionLine(line, parts); + } else if (keyword.equals("vote-status")) { + this.parseVoteStatusLine(line, parts); + } else if (keyword.equals("consensus-methods")) { + this.parseConsensusMethodsLine(line, parts); + } else if (keyword.equals("published")) { + this.parsePublishedLine(line, parts); + } else if (keyword.equals("valid-after")) { + this.parseValidAfterLine(line, parts); + } else if (keyword.equals("fresh-until")) { + this.parseFreshUntilLine(line, parts); + } else if (keyword.equals("valid-until")) { + this.parseValidUntilLine(line, parts); + } else if (keyword.equals("voting-delay")) { + this.parseVotingDelayLine(line, parts); + } else if (keyword.equals("client-versions")) { + this.parseClientVersionsLine(line, parts); + } else if (keyword.equals("server-versions")) { + this.parseServerVersionsLine(line, parts); + } else if (keyword.equals("known-flags")) { + this.parseKnownFlagsLine(line, parts); + } else if (keyword.equals("params")) { + this.parseParamsLine(line, parts); + } else { + /* TODO Is throwing an exception the right thing to do here? + * This is probably fine for development, but once the library + * is in production use, this seems annoying. */ + throw new DescriptorParseException("Unrecognized line '" + line + + "'."); } } } catch (IOException e) { throw new RuntimeException("Internal error: Ran into an " + "IOException while parsing a String in memory. Something's " + "really wrong.", e); - } catch (ParseException e) { - /* TODO Handle me correctly. */ - throw new RuntimeException("Parse error in line '" + line + "'."); + } + } + + private void parseNetworkStatusVersionLine(String line, String[] parts) + throws DescriptorParseException { + if (!line.equals("network-status-version 3")) { + throw new DescriptorParseException("Illegal network status version " + + "number in line '" + line + "'."); + } + this.networkStatusVersion = 3; + } + + private void parseVoteStatusLine(String line, String[] parts) + throws DescriptorParseException { + if (parts.length != 2 || !parts[1].equals("vote")) { + throw new DescriptorParseException("Line '" + line + "' indicates " + + "that this is not a vote."); + } + } + + private void parseConsensusMethodsLine(String line, String[] parts) + throws DescriptorParseException { + if (parts.length < 2) { + throw new DescriptorParseException("Illegal line '" + line + + "' in vote."); + } + this.consensusMethods = new ArrayList<Integer>(); + for (int i = 1; i < parts.length; i++) { + int consensusMethod = -1; + try { + consensusMethod = Integer.parseInt(parts[i]); + } catch (NumberFormatException e) { + /* We'll notice below that consensusMethod is still -1. */ + } + if (consensusMethod < 1) { + throw new DescriptorParseException("Illegal consensus method " + + "number in line '" + line + "'."); + } + this.consensusMethods.add(Integer.parseInt(parts[i])); + } + } + + private void parsePublishedLine(String line, String[] parts) + throws DescriptorParseException { + this.publishedMillis = ParseHelper.parseTimestampAtIndex(line, parts, + 1, 2); + } + + private void parseValidAfterLine(String line, String[] parts) + throws DescriptorParseException { + this.validAfterMillis = ParseHelper.parseTimestampAtIndex(line, parts, + 1, 2); + } + + private void parseFreshUntilLine(String line, String[] parts) + throws DescriptorParseException { + this.freshUntilMillis = ParseHelper.parseTimestampAtIndex(line, parts, + 1, 2); + } + + private void parseValidUntilLine(String line, String[] parts) + throws DescriptorParseException { + this.validUntilMillis = ParseHelper.parseTimestampAtIndex(line, parts, + 1, 2); + } + + private void parseVotingDelayLine(String line, String[] parts) + throws DescriptorParseException { + if (parts.length != 3) { + throw new DescriptorParseException("Wrong number of values in line " + + "'" + line + "'."); + } + try { + this.voteSeconds = Long.parseLong(parts[1]); + this.distSeconds = Long.parseLong(parts[2]); } catch (NumberFormatException e) { - /* TODO Handle me. In theory, we shouldn't catch runtime - * exceptions, but in this case it keeps the parsing code small. */ - } catch (ArrayIndexOutOfBoundsException e) { - /* TODO Handle me. In theory, we shouldn't catch runtime - * exceptions, but in this case it keeps the parsing code small. */ + throw new DescriptorParseException("Illegal values in line '" + line + + "'."); } }
- private byte[] voteBytes; - public byte[] getRawDescriptorBytes() { - return this.voteBytes; + private void parseClientVersionsLine(String line, String[] parts) + throws DescriptorParseException { + this.recommendedClientVersions = this.parseClientOrServerVersions( + line, parts); }
- private int networkStatusVersion; - public int getNetworkStatusVersion() { - return this.networkStatusVersion; + private void parseServerVersionsLine(String line, String[] parts) + throws DescriptorParseException { + this.recommendedServerVersions = this.parseClientOrServerVersions( + line, parts); }
- private List<Integer> consensusMethods = new ArrayList<Integer>(); - public List<Integer> getConsensusMethods() { - return this.consensusMethods; + private List<String> parseClientOrServerVersions(String line, + String[] parts) throws DescriptorParseException { + List<String> result = new ArrayList<String>(); + if (parts.length == 1) { + return result; + } else if (parts.length > 2) { + throw new DescriptorParseException("Illegal versions line '" + line + + "'."); + } + String[] versions = parts[1].split(",", -1); + for (int i = 0; i < versions.length; i++) { + String version = versions[i]; + if (version.length() < 1) { + throw new DescriptorParseException("Illegal versions line '" + + line + "'."); + } + result.add(version); + } + return result; }
- private long publishedMillis; - public long getPublishedMillis() { - return this.publishedMillis; + private void parseKnownFlagsLine(String line, String[] parts) + throws DescriptorParseException { + if (parts.length < 2) { + throw new DescriptorParseException("No known flags in line '" + line + + "'."); + } + this.knownFlags = new TreeSet<String>(); + for (int i = 1; i < parts.length; i++) { + this.knownFlags.add(parts[i]); + } }
- private long validAfterMillis; - public long getValidAfterMillis() { - return this.validAfterMillis; + private void parseParamsLine(String line, String[] parts) + throws DescriptorParseException { + this.consensusParams = ParseHelper.parseKeyValuePairs(line, parts, 1); }
- private long freshUntilMillis; - public long getFreshUntilMillis() { - return this.freshUntilMillis; + protected void parseDirSource(byte[] dirSourceBytes) + throws DescriptorParseException { + try { + BufferedReader br = new BufferedReader(new StringReader( + new String(dirSourceBytes))); + String line; + boolean skipCrypto = false; + while ((line = br.readLine()) != null) { + String[] parts = line.split(" "); + String keyword = parts[0]; + if (keyword.equals("dir-source")) { + this.parseDirSourceLine(line, parts); + } else if (keyword.equals("contact")) { + this.parseContactLine(line, parts); + } else if (keyword.equals("dir-key-certificate-version")) { + this.parseDirKeyCertificateVersionLine(line, parts); + } else if (keyword.equals("fingerprint")) { + /* Nothing new to learn here. We already know the fingerprint + * from the dir-source line. */ + } else if (keyword.equals("legacy-key")) { + this.parseLegacyKeyLine(line, parts); + } else if (keyword.equals("dir-key-published")) { + this.parseDirKeyPublished(line, parts); + } else if (keyword.equals("dir-key-expires")) { + this.parseDirKeyExpiresLine(line, parts); + } else if (keyword.equals("dir-identity-key") || + keyword.equals("dir-signing-key") || + keyword.equals("dir-key-crosscert") || + keyword.equals("dir-key-certification")) { + } else if (line.startsWith("-----BEGIN")) { + skipCrypto = true; + } else if (line.equals("-----END")) { + skipCrypto = false; + } else if (!skipCrypto) { + /* TODO Is throwing an exception the right thing to do here? + * This is probably fine for development, but once the library + * is in production use, this seems annoying. */ + throw new DescriptorParseException("Unrecognized line '" + line + + "'."); + } + } + } catch (IOException e) { + throw new RuntimeException("Internal error: Ran into an " + + "IOException while parsing a String in memory. Something's " + + "really wrong.", e); + } }
- private long validUntilMillis; - public long getValidUntilMillis() { - return this.validUntilMillis; + private void parseDirSourceLine(String line, String[] parts) + throws DescriptorParseException { + this.nickname = ParseHelper.parseNickname(line, parts[1]); + this.identity = ParseHelper.parseTwentyByteHexString(line, parts[2]); + this.address = ParseHelper.parseIpv4Address(line, parts[4]); + this.dirPort = ParseHelper.parsePort(line, parts[5]); + this.orPort = ParseHelper.parsePort(line, parts[6]); }
- private List<Long> votingDelay = new ArrayList<Long>(); - public List<Long> getVotingDelay() { - return new ArrayList<Long>(this.votingDelay); + private void parseContactLine(String line, String[] parts) + throws DescriptorParseException { + if (line.length() > "contact ".length()) { + this.contactLine = line.substring("contact ".length()); + } else { + this.contactLine = ""; + } }
- private List<String> recommendedClientVersions; - public List<String> getRecommendedClientVersions() { - return this.recommendedClientVersions == null ? null : - new ArrayList<String>(this.recommendedClientVersions); + private void parseDirKeyCertificateVersionLine(String line, + String[] parts) throws DescriptorParseException { + if (parts.length != 2) { + throw new DescriptorParseException("Illegal line '" + line + + "' in vote."); + } + try { + this.dirKeyCertificateVersion = Integer.parseInt(parts[1]); + } catch (NumberFormatException e) { + throw new DescriptorParseException("Illegal dir key certificate " + + "version in line '" + line + "'."); + } + if (this.dirKeyCertificateVersion < 1) { + throw new DescriptorParseException("Illegal dir key certificate " + + "version in line '" + line + "'."); + } }
- private List<String> recommendedServerVersions; - public List<String> getRecommendedServerVersions() { - return this.recommendedServerVersions == null ? null : - new ArrayList<String>(this.recommendedServerVersions); + private void parseLegacyKeyLine(String line, String[] parts) + throws DescriptorParseException { + if (parts.length != 2) { + throw new DescriptorParseException("Illegal line '" + line + "'."); + } + this.legacyKey = ParseHelper.parseTwentyByteHexString(line, parts[2]); }
- private SortedSet<String> knownFlags = new TreeSet<String>(); - public SortedSet<String> getKnownFlags() { - return new TreeSet<String>(this.knownFlags); + private void parseDirKeyPublished(String line, String[] parts) + throws DescriptorParseException { + this.dirKeyPublishedMillis = ParseHelper.parseTimestampAtIndex(line, + parts, 1, 2); }
- private SortedMap<String, Integer> consensusParams = - new TreeMap<String, Integer>(); - public SortedMap<String, Integer> getConsensusParams() { - return new TreeMap<String, Integer>(this.consensusParams); + private void parseDirKeyExpiresLine(String line, String[] parts) + throws DescriptorParseException { + this.dirKeyExpiresMillis = ParseHelper.parseTimestampAtIndex(line, + parts, 1, 2); + } + + protected void parseFooter(byte[] footerBytes) { + /* There is nothing in the footer that we'd want to parse. */ }
private String nickname; @@ -296,6 +379,11 @@ public class RelayNetworkStatusVoteImpl return this.dirKeyCertificateVersion; }
+ private String legacyKey; + public String getLegacyKey() { + return this.legacyKey; + } + private long dirKeyPublishedMillis; public long getDirKeyPublishedMillis() { return this.dirKeyPublishedMillis; @@ -311,54 +399,67 @@ public class RelayNetworkStatusVoteImpl return this.signingKeyDigest; }
- private SortedMap<String, NetworkStatusEntry> statusEntries = - new TreeMap<String, NetworkStatusEntry>(); - public SortedMap<String, NetworkStatusEntry> getStatusEntries() { - return new TreeMap<String, NetworkStatusEntry>(this.statusEntries); + private int networkStatusVersion; + public int getNetworkStatusVersion() { + return this.networkStatusVersion; } - public boolean containsStatusEntry(String fingerprint) { - return this.statusEntries.containsKey(fingerprint); + + private List<Integer> consensusMethods; + public List<Integer> getConsensusMethods() { + return new ArrayList<Integer>(this.consensusMethods); } - public NetworkStatusEntry getStatusEntry(String fingerprint) { - return this.statusEntries.get(fingerprint); + + private long publishedMillis; + public long getPublishedMillis() { + return this.publishedMillis; }
+ private long validAfterMillis; + public long getValidAfterMillis() { + return this.validAfterMillis; + }
- private SortedMap<String, String> directorySignatures = - new TreeMap<String, String>(); - public SortedMap<String, String> getDirectorySignatures() { - return new TreeMap<String, String>(this.directorySignatures); + private long freshUntilMillis; + public long getFreshUntilMillis() { + return this.freshUntilMillis; }
- private void checkConsistency() { - if (this.networkStatusVersion == 0) { - throw new RuntimeException("Consensus doesn't contain a " - + "'network-status-version' line."); - } - if (this.validAfterMillis == 0L) { - throw new RuntimeException("Consensus doesn't contain a " - + "'valid-after' line."); - } - if (this.freshUntilMillis == 0L) { - throw new RuntimeException("Consensus doesn't contain a " - + "'fresh-until' line."); - } - if (this.validUntilMillis == 0L) { - throw new RuntimeException("Consensus doesn't contain a " - + "'valid-until' line."); - } - if (this.votingDelay.isEmpty()) { - throw new RuntimeException("Consensus doesn't contain a " - + "'voting-delay' line."); - } - if (this.knownFlags.isEmpty()) { - throw new RuntimeException("Consensus doesn't contain a " - + "'known-flags' line."); - } - if (this.statusEntries.isEmpty()) { - throw new RuntimeException("Consensus doesn't contain any 'r' " - + "lines."); - } + private long validUntilMillis; + public long getValidUntilMillis() { + return this.validUntilMillis; + } + + private long voteSeconds; + public long getVoteSeconds() { + return this.voteSeconds; + } + + private long distSeconds; + public long getDistSeconds() { + return this.distSeconds; + } + + private List<String> recommendedClientVersions; + public List<String> getRecommendedClientVersions() { + return this.recommendedClientVersions == null ? null : + new ArrayList<String>(this.recommendedClientVersions); + } + + private List<String> recommendedServerVersions; + public List<String> getRecommendedServerVersions() { + return this.recommendedServerVersions == null ? null : + new ArrayList<String>(this.recommendedServerVersions); + } + + private SortedSet<String> knownFlags; + public SortedSet<String> getKnownFlags() { + return new TreeSet<String>(this.knownFlags); + } + + private SortedMap<String, Integer> consensusParams; + public SortedMap<String, Integer> getConsensusParams() { + return this.consensusParams == null ? null: + new TreeMap<String, Integer>(this.consensusParams); } }
diff --git a/test/org/torproject/descriptor/impl/RelayNetworkStatusVoteImplTest.java b/test/org/torproject/descriptor/impl/RelayNetworkStatusVoteImplTest.java new file mode 100644 index 0000000..8b62480 --- /dev/null +++ b/test/org/torproject/descriptor/impl/RelayNetworkStatusVoteImplTest.java @@ -0,0 +1,574 @@ +/* Copyright 2011 The Tor Project + * See LICENSE for licensing information */ +package org.torproject.descriptor.impl; + +import org.torproject.descriptor.RelayNetworkStatusVote; +import org.torproject.descriptor.impl.RelayNetworkStatusVoteImpl; + +import java.util.*; + +import org.junit.*; +import org.junit.rules.*; +import static org.junit.Assert.*; + +/* TODO Add tests (and possibly a DirSourceLineBuilder) to test the + * following methods: + * - String getNickname(); + * - String getIdentity(); + * - String getAddress(); + * - int getDirport(); + * - int getOrport(); + * - String getContactLine(); + * - int getDirKeyCertificateVersion(); + * - String getLegacyKey(); + * - long getDirKeyPublishedMillis(); + * - long getDirKeyExpiresMillis(); + * - String getSigningKeyDigest(); + */ + +/* Test parsing of network status votes. Some of the vote-parsing code is + * already tested in the consensus-parsing tests. The tests in this class + * focus on the differences between votes and consensuses that are mostly + * in the directory header. */ +public class RelayNetworkStatusVoteImplTest { + + /* Helper class to build a vote based on default data and modifications + * requested by test methods. */ + private static class VoteBuilder { + private String networkStatusVersionLine = "network-status-version 3"; + private static RelayNetworkStatusVote + createWithNetworkStatusVersionLine(String line) + throws DescriptorParseException { + VoteBuilder vb = new VoteBuilder(); + vb.networkStatusVersionLine = line; + return new RelayNetworkStatusVoteImpl(vb.buildVote()); + } + private String voteStatusLine = "vote-status vote"; + private static RelayNetworkStatusVote + createWithVoteStatusLine(String line) + throws DescriptorParseException { + VoteBuilder vb = new VoteBuilder(); + vb.voteStatusLine = line; + return new RelayNetworkStatusVoteImpl(vb.buildVote()); + } + private String consensusMethodsLine = + "consensus-methods 1 2 3 4 5 6 7 8 9 10 11"; + private static RelayNetworkStatusVote + createWithConsensusMethodsLine(String line) + throws DescriptorParseException { + VoteBuilder vb = new VoteBuilder(); + vb.consensusMethodsLine = line; + return new RelayNetworkStatusVoteImpl(vb.buildVote()); + } + private String publishedLine = "published 2011-11-30 08:50:01"; + private static RelayNetworkStatusVote + createWithPublishedLine(String line) + throws DescriptorParseException { + VoteBuilder vb = new VoteBuilder(); + vb.publishedLine = line; + return new RelayNetworkStatusVoteImpl(vb.buildVote()); + } + private String validAfterLine = "valid-after 2011-11-30 09:00:00"; + private static RelayNetworkStatusVote + createWithValidAfterLine(String line) + throws DescriptorParseException { + VoteBuilder vb = new VoteBuilder(); + vb.validAfterLine = line; + return new RelayNetworkStatusVoteImpl(vb.buildVote()); + } + private String freshUntilLine = "fresh-until 2011-11-30 10:00:00"; + private static RelayNetworkStatusVote + createWithFreshUntilLine(String line) + throws DescriptorParseException { + VoteBuilder vb = new VoteBuilder(); + vb.freshUntilLine = line; + return new RelayNetworkStatusVoteImpl(vb.buildVote()); + } + private String validUntilLine = "valid-until 2011-11-30 12:00:00"; + private static RelayNetworkStatusVote + createWithValidUntilLine(String line) + throws DescriptorParseException { + VoteBuilder vb = new VoteBuilder(); + vb.validUntilLine = line; + return new RelayNetworkStatusVoteImpl(vb.buildVote()); + } + private String votingDelayLine = "voting-delay 300 300"; + private static RelayNetworkStatusVote + createWithVotingDelayLine(String line) + throws DescriptorParseException { + VoteBuilder vb = new VoteBuilder(); + vb.votingDelayLine = line; + return new RelayNetworkStatusVoteImpl(vb.buildVote()); + } + private String clientVersionsLine = "client-versions 0.2.1.31," + + "0.2.2.34,0.2.3.6-alpha,0.2.3.7-alpha,0.2.3.8-alpha"; + private static RelayNetworkStatusVote + createWithClientVersionsLine(String line) + throws DescriptorParseException { + VoteBuilder vb = new VoteBuilder(); + vb.clientVersionsLine = line; + return new RelayNetworkStatusVoteImpl(vb.buildVote()); + } + private String serverVersionsLine = "server-versions 0.2.1.31," + + "0.2.2.34,0.2.3.6-alpha,0.2.3.7-alpha,0.2.3.8-alpha"; + private static RelayNetworkStatusVote + createWithServerVersionsLine(String line) + throws DescriptorParseException { + VoteBuilder vb = new VoteBuilder(); + vb.serverVersionsLine = line; + return new RelayNetworkStatusVoteImpl(vb.buildVote()); + } + private String knownFlagsLine = "known-flags Authority BadExit Exit " + + "Fast Guard HSDir Named Running Stable Unnamed V2Dir Valid"; + private static RelayNetworkStatusVote + createWithKnownFlagsLine(String line) + throws DescriptorParseException { + VoteBuilder vb = new VoteBuilder(); + vb.knownFlagsLine = line; + return new RelayNetworkStatusVoteImpl(vb.buildVote()); + } + private String paramsLine = "params " + + "CircuitPriorityHalflifeMsec=30000 bwauthbestratio=1 " + + "bwauthcircs=1 bwauthdescbw=0 bwauthkp=10000 bwauthpid=1 " + + "bwauthtd=5000 bwauthti=50000 bwauthtidecay=5000 cbtnummodes=3 " + + "cbtquantile=80 circwindow=1000 refuseunknownexits=1"; + private static RelayNetworkStatusVote + createWithParamsLine(String line) + throws DescriptorParseException { + VoteBuilder vb = new VoteBuilder(); + vb.paramsLine = line; + return new RelayNetworkStatusVoteImpl(vb.buildVote()); + } + private List<String> dirSources = new ArrayList<String>(); + private List<String> statusEntries = new ArrayList<String>(); + private String directoryFooterLine = "directory-footer"; + private static RelayNetworkStatusVote + createWithDirectoryFooterLine(String line) + throws DescriptorParseException { + VoteBuilder vb = new VoteBuilder(); + vb.directoryFooterLine = line; + return new RelayNetworkStatusVoteImpl(vb.buildVote()); + } + private List<String> directorySignatures = new ArrayList<String>(); + private VoteBuilder() { + this.dirSources.add("dir-source urras " + + "80550987E1D626E3EBA5E5E75A458DE0626D088C 208.83.223.34 " + + "208.83.223.34 443 80\n" + + "contact 4096R/E012B42D Jacob Appelbaum " + + "jacob@appelbaum.net\n" + + "dir-key-certificate-version 3\n" + + "fingerprint 80550987E1D626E3EBA5E5E75A458DE0626D088C\n" + + "dir-key-published 2011-04-27 05:34:37\n" + + "dir-key-expires 2012-04-27 05:34:37\n" + + "dir-identity-key\n" + + "-----BEGIN RSA PUBLIC KEY-----\n" + + "MIIBigKCAYEAtKpuLgVK25sfScjsxfVU1ljofrDygt9GP7bNJl/rghX42KUT" + + "975W\nrGp/fbhF7p+FcKCzNOhJFINQbRf/5E3lN8mzoamIU43QqQ9RRVf946" + + "88UsazVsAN\nNVT0v9J0cr387WePjenRuIE1MmiP0nmw/XdvbPTayqax7VYl" + + "cUMXGHl8DnWix1EN\nRwmeig+JBte0JS12oo2HG9zcSfjLJVjY6ZmvRrVycX" + + "iRxGc/JgNlSrV4cxUNykaB\nJ6pO6J499OZfQu7m1vAPTENrVJ4yEfRGRwFI" + + "Y+d/s8BkKcaiWtXAfTe31uBI6GEH\nmS3HNu1JVSuoaUiQIvVYDLMfBvMcNy" + + "Ax97UT1l6E0Tn6a7pgChrquGwXai1xGzk8\n58aXwdSFoFBSTCkyemopq5H2" + + "0p/nkPAO0pHL1kTvcaKz9CEj4XcKm+kOmzejYmIa\nkbWNcRpXPiUZ+xmwGt" + + "sq30xrzqiONmERkxqlmf7bVQPFvh3Kz6hGcmTBhTbHSe9h\nzDgmdaTNn3EH" + + "AgMBAAE=\n" + + "-----END RSA PUBLIC KEY-----\n" + + "dir-signing-key\n" + + "-----BEGIN RSA PUBLIC KEY-----\n" + + "MIGJAoGBAN05qyHFQlTqykMP8yLuD4G2UuYulD4Xs8iSX5uqF+WGsUA1E4zZ" + + "h48h\nDFj8+drFiCu3EqhMEmVG4ACtJK2uz6D1XohUsbPWTR6LSnWJ8q6/zf" + + "TSLumBGsN7\nPUXyMNjwRKL6UvrcbYk1d2mRBLO7SAP/sFW5fHhIBVeLIWrz" + + "Q19rAgMBAAE=\n" + + "-----END RSA PUBLIC KEY-----\n" + + "dir-key-crosscert\n" + + "-----BEGIN ID SIGNATURE-----\n" + + "rPBFn6IJ6TvAHj4pSwlg+RTn1fP89JGSVa08wuyJr5dAvZsdakQXvRjamT9o" + + "JUaZ\nnY5Rl/tRlGuSQ0BglTPPKoXdKERK0FUr9f0EKrQy7NDUgE2j9losiR" + + "uyKzhA3neZ\nK4yF8bhqAwM51u7fzAhIjNeRif9c04rhFJJCseco84w=\n" + + "-----END ID SIGNATURE-----\n" + + "dir-key-certification\n" + + "-----BEGIN SIGNATURE-----\n" + + "hPSh6FuohNF5ccjiMbkvr8cZJwGFuL11cNtwN9k0X3pUdFZVATIEkqBe7z+r" + + "E2PX\nPw+BGyC6wYAieoTVIhLpwKqd7DXLYjuhPZ28+7MQaDL01AqYeRp5PT" + + "01PxrFY0Um\nlVf95uqUitgvDT76Ne4ExWk6UvGlYB9OBgBySZz8VWe9znoM" + + "qb0uHn/p8IzqTApT\nAxRWXBHClntMeRqtGxaj8DcdJFn8yMxQiZG7MfDg2s" + + "q2ySPJyGlN+neoVDVhZiDI\n9LTNmw60gWlUp2erFeam8Mo1ZBC4DPNjQEm6" + + "QeHZFZMkhDuO6SwS/FL712A42+Co\nYtMaVot/p5FG2ZSBXbgl2XP5/z8ELn" + + "pmXqMbPAoWRo3BPNSJkIQQNog8Q5ZrK+av\nZDw5eGPltGKsXOkvuzIMM8nB" + + "eAnDPDgYvzrIFObEGbvY/P8mzVAZxp3Yz+sRtNel\nC1SWz/Fx+Saex5oI7D" + + "J3xtSD4XqKb/wYwZFT8IxDYq1t2tFXdHxd4QPRVcvc0zYC\n" + + "-----END SIGNATURE-----"); + this.statusEntries.add("r right2privassy3 " + + "ADQ6gCT3DiFHKPDFr3rODBUI8HM lJY5Vf7kXec+VdkGW2flEsfkFC8 " + + "2011-11-12 00:03:40 50.63.8.215 9023 0\n" + + "s Exit Fast Guard Running Stable Valid\n" + + "opt v Tor 0.2.1.29 (r8e9b25e6c7a2e70c)\n" + + "w Bandwidth=297 Measured=73\n" + + "p accept 80,1194,1220,1293,1500,1533,1677,1723,1863," + + "2082-2083,2086-2087,2095-2096,2102-2104,3128,3389,3690,4321," + + "4643,5050,5190,5222-5223,5228,5900,6660-6669,6679,6697,8000," + + "8008,8074,8080,8087-8088,8443,8888,9418,9999-10000,19294," + + "19638\n" + + "m 8,9,10,11 sha256=9ciEx9t0McXk9A06I7qwN7pxuNOdpCP64RV/6cx2Zkc"); + this.directorySignatures.add("directory-signature " + + "80550987E1D626E3EBA5E5E75A458DE0626D088C " + + "EEB9299D295C1C815E289FBF2F2BBEA5F52FDD19\n" + + "-----BEGIN SIGNATURE-----\n" + + "iHEU3Iidya5RIrjyYgv8tlU0R+rF56/3/MmaaZi0a67e7ZkISfQ4dghScHxn" + + "F3Yh\nqXVaaoP07r6Ta+s0g1Zijm3lms50Nk/4tV2p8Y63c3F4Q3DAnK40Oi" + + "kfOIwEj+Ny\n+zBRQssP3hPhTPOj/A7o3mZZwtL6x1sxpeu/nME1l5E=\n" + + "-----END SIGNATURE-----"); + } + private byte[] buildVote() { + StringBuilder sb = new StringBuilder(); + this.appendHeader(sb); + this.appendBody(sb); + this.appendFooter(sb); + return sb.toString().getBytes(); + } + private void appendHeader(StringBuilder sb) { + if (this.networkStatusVersionLine != null) { + sb.append(this.networkStatusVersionLine + "\n"); + } + if (this.voteStatusLine != null) { + sb.append(this.voteStatusLine + "\n"); + } + if (this.consensusMethodsLine != null) { + sb.append(this.consensusMethodsLine + "\n"); + } + if (this.publishedLine != null) { + sb.append(this.publishedLine + "\n"); + } + if (this.validAfterLine != null) { + sb.append(this.validAfterLine + "\n"); + } + if (this.freshUntilLine != null) { + sb.append(this.freshUntilLine + "\n"); + } + if (this.validUntilLine != null) { + sb.append(this.validUntilLine + "\n"); + } + if (this.votingDelayLine != null) { + sb.append(this.votingDelayLine + "\n"); + } + if (this.clientVersionsLine != null) { + sb.append(this.clientVersionsLine + "\n"); + } + if (this.serverVersionsLine != null) { + sb.append(this.serverVersionsLine + "\n"); + } + if (this.knownFlagsLine != null) { + sb.append(this.knownFlagsLine + "\n"); + } + if (this.paramsLine != null) { + sb.append(this.paramsLine + "\n"); + } + for (String dirSource : this.dirSources) { + sb.append(dirSource + "\n"); + } + } + private void appendBody(StringBuilder sb) { + for (String statusEntry : this.statusEntries) { + sb.append(statusEntry + "\n"); + } + } + private void appendFooter(StringBuilder sb) { + if (this.directoryFooterLine != null) { + sb.append(this.directoryFooterLine + "\n"); + } + for (String directorySignature : this.directorySignatures) { + sb.append(directorySignature + "\n"); + } + } + } + + @Test() + public void testSampleVote() throws DescriptorParseException { + VoteBuilder vb = new VoteBuilder(); + RelayNetworkStatusVote vote = + new RelayNetworkStatusVoteImpl(vb.buildVote()); + assertEquals(3, vote.getNetworkStatusVersion()); + List<Integer> consensusMethods = Arrays.asList( + new Integer[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}); + assertEquals(vote.getConsensusMethods(), consensusMethods); + assertEquals(1322643001000L, vote.getPublishedMillis()); + assertEquals(1322643600000L, vote.getValidAfterMillis()); + assertEquals(1322647200000L, vote.getFreshUntilMillis()); + assertEquals(1322654400000L, vote.getValidUntilMillis()); + assertEquals(300L, vote.getVoteSeconds()); + assertEquals(300L, vote.getDistSeconds()); + assertTrue(vote.getKnownFlags().contains("Running")); + assertEquals(30000, (int) vote.getConsensusParams().get( + "CircuitPriorityHalflifeMsec")); + assertEquals("Tor 0.2.1.29 (r8e9b25e6c7a2e70c)", + vote.getStatusEntry("00343A8024F70E214728F0C5AF7ACE0C1508F073"). + getVersion()); + } + + @Test(expected = DescriptorParseException.class) + public void testNetworkStatusVersionNoLine() + throws DescriptorParseException { + VoteBuilder.createWithNetworkStatusVersionLine(null); + } + + @Test(expected = DescriptorParseException.class) + public void testNetworkStatusVersionNewLine() + throws DescriptorParseException { + VoteBuilder.createWithNetworkStatusVersionLine( + "network-status-version 3\n"); + } + + @Test(expected = DescriptorParseException.class) + public void testNetworkStatusVersionNewLineSpace() + throws DescriptorParseException { + VoteBuilder.createWithNetworkStatusVersionLine( + "network-status-version 3\n "); + } + + @Test(expected = DescriptorParseException.class) + public void testNetworkStatusVersionPrefixLineAtChar() + throws DescriptorParseException { + VoteBuilder.createWithNetworkStatusVersionLine( + "@vote\nnetwork-status-version 3"); + } + + @Test(expected = DescriptorParseException.class) + public void testNetworkStatusVersionPrefixLine() + throws DescriptorParseException { + VoteBuilder.createWithNetworkStatusVersionLine( + "directory-footer\nnetwork-status-version 3"); + } + + @Test(expected = DescriptorParseException.class) + public void testNetworkStatusVersionPrefixLinePoundChar() + throws DescriptorParseException { + VoteBuilder.createWithNetworkStatusVersionLine( + "#vote\nnetwork-status-version 3"); + } + + @Test(expected = DescriptorParseException.class) + public void testNetworkStatusVersionNoSpace() + throws DescriptorParseException { + VoteBuilder.createWithNetworkStatusVersionLine( + "network-status-version"); + } + + @Test(expected = DescriptorParseException.class) + public void testNetworkStatusVersionOneSpace() + throws DescriptorParseException { + VoteBuilder.createWithNetworkStatusVersionLine( + "network-status-version "); + } + + @Test(expected = DescriptorParseException.class) + public void testNetworkStatusVersion42() + throws DescriptorParseException { + VoteBuilder.createWithNetworkStatusVersionLine( + "network-status-version 42"); + } + + @Test(expected = DescriptorParseException.class) + public void testNetworkStatusVersionFourtyTwo() + throws DescriptorParseException { + VoteBuilder.createWithNetworkStatusVersionLine( + "network-status-version FourtyTwo"); + } + + @Test(expected = DescriptorParseException.class) + public void testVoteStatusNoLine() throws DescriptorParseException { + VoteBuilder.createWithVoteStatusLine(null); + } + + @Test(expected = DescriptorParseException.class) + public void testNetworkStatusVersionSpaceBefore() + throws DescriptorParseException { + VoteBuilder.createWithNetworkStatusVersionLine( + " network-status-version 3"); + } + + @Test(expected = DescriptorParseException.class) + public void testVoteStatusSpaceBefore() throws DescriptorParseException { + VoteBuilder.createWithVoteStatusLine(" vote-status vote"); + } + + @Test(expected = DescriptorParseException.class) + public void testVoteStatusNoSpace() throws DescriptorParseException { + VoteBuilder.createWithVoteStatusLine("vote-status"); + } + + @Test(expected = DescriptorParseException.class) + public void testVoteStatusOneSpace() throws DescriptorParseException { + VoteBuilder.createWithVoteStatusLine("vote-status "); + } + + @Test() + public void testVoteStatusVoteOneSpace() + throws DescriptorParseException { + VoteBuilder.createWithVoteStatusLine("vote-status vote "); + } + + @Test(expected = DescriptorParseException.class) + public void testVoteStatusConsensus() throws DescriptorParseException { + VoteBuilder.createWithVoteStatusLine("vote-status consensus"); + } + + @Test(expected = DescriptorParseException.class) + public void testVoteStatusTheMagicVoteStatus() + throws DescriptorParseException { + VoteBuilder.createWithVoteStatusLine( + "vote-status TheMagicVoteStatus"); + } + + @Test(expected = DescriptorParseException.class) + public void testConsensusMethodNoLine() + throws DescriptorParseException { + VoteBuilder.createWithConsensusMethodsLine(null); + } + + @Test(expected = DescriptorParseException.class) + public void testConsensusMethodNoSpace() + throws DescriptorParseException { + VoteBuilder.createWithConsensusMethodsLine("consensus-methods"); + } + + @Test(expected = DescriptorParseException.class) + public void testConsensusMethodOneSpace() + throws DescriptorParseException { + VoteBuilder.createWithConsensusMethodsLine("consensus-methods "); + } + + @Test(expected = DescriptorParseException.class) + public void testConsensusMethodEleven() + throws DescriptorParseException { + VoteBuilder.createWithConsensusMethodsLine( + "consensus-methods eleven"); + } + + @Test(expected = DescriptorParseException.class) + public void testConsensusMethodMinusOne() + throws DescriptorParseException { + VoteBuilder.createWithConsensusMethodsLine("consensus-methods -1"); + } + + @Test(expected = DescriptorParseException.class) + public void testConsensusMethodNinePeriod() + throws DescriptorParseException { + VoteBuilder.createWithConsensusMethodsLine("consensus-methods " + + "999999999999999999999999999999999999999999999999999999999999"); + } + + @Test(expected = DescriptorParseException.class) + public void testConsensusMethodTwoLines() + throws DescriptorParseException { + VoteBuilder.createWithConsensusMethodsLine( + "consensus-method 1\nconsensus-method 1"); + } + + @Test(expected = DescriptorParseException.class) + public void testPublishedNoLine() throws DescriptorParseException { + VoteBuilder.createWithPublishedLine(null); + } + + @Test(expected = DescriptorParseException.class) + public void testValidAfterNoLine() throws DescriptorParseException { + VoteBuilder.createWithValidAfterLine(null); + } + + @Test(expected = DescriptorParseException.class) + public void testValidAfterNoSpace() throws DescriptorParseException { + VoteBuilder.createWithValidAfterLine("valid-after"); + } + + @Test(expected = DescriptorParseException.class) + public void testValidAfterOneSpace() throws DescriptorParseException { + VoteBuilder.createWithValidAfterLine("valid-after "); + } + + @Test(expected = DescriptorParseException.class) + public void testValidAfterLongAgo() throws DescriptorParseException { + VoteBuilder.createWithValidAfterLine("valid-after long ago"); + } + + @Test(expected = DescriptorParseException.class) + public void testValidAfterFeb30() throws DescriptorParseException { + VoteBuilder.createWithValidAfterLine( + "valid-after 2011-02-30 09:00:00"); + } + + @Test(expected = DescriptorParseException.class) + public void testFreshUntilNoLine() throws DescriptorParseException { + VoteBuilder.createWithFreshUntilLine(null); + } + + @Test(expected = DescriptorParseException.class) + public void testFreshUntilAroundTen() throws DescriptorParseException { + VoteBuilder.createWithFreshUntilLine( + "fresh-until 2011-11-30 around ten"); + } + + @Test(expected = DescriptorParseException.class) + public void testValidUntilTomorrowMorning() + throws DescriptorParseException { + VoteBuilder.createWithValidUntilLine( + "valid-until tomorrow morning"); + } + + @Test(expected = DescriptorParseException.class) + public void testVotingDelayNoLine() throws DescriptorParseException { + VoteBuilder.createWithVotingDelayLine(null); + } + + @Test(expected = DescriptorParseException.class) + public void testVotingDelayNoSpace() throws DescriptorParseException { + VoteBuilder.createWithVotingDelayLine("voting-delay"); + } + + @Test(expected = DescriptorParseException.class) + public void testVotingDelayOneSpace() throws DescriptorParseException { + VoteBuilder.createWithVotingDelayLine("voting-delay "); + } + + @Test(expected = DescriptorParseException.class) + public void testVotingDelayTriple() throws DescriptorParseException { + VoteBuilder.createWithVotingDelayLine( + "voting-delay 300 300 300"); + } + + @Test(expected = DescriptorParseException.class) + public void testVotingDelaySingle() throws DescriptorParseException { + VoteBuilder.createWithVotingDelayLine("voting-delay 300"); + } + + @Test(expected = DescriptorParseException.class) + public void testVotingDelayOneTwo() throws DescriptorParseException { + VoteBuilder.createWithVotingDelayLine("voting-delay one two"); + } + + @Test(expected = DescriptorParseException.class) + public void testClientVersionsComma() throws DescriptorParseException { + VoteBuilder.createWithClientVersionsLine("client-versions ,"); + } + + @Test(expected = DescriptorParseException.class) + public void testClientVersionsCommaVersion() + throws DescriptorParseException { + VoteBuilder.createWithClientVersionsLine( + "client-versions ,0.2.2.34"); + } + + @Test(expected = DescriptorParseException.class) + public void testKnownFlagsNoLine() throws DescriptorParseException { + VoteBuilder.createWithKnownFlagsLine(null); + } + + @Test(expected = DescriptorParseException.class) + public void testKnownFlagsNoSpace() throws DescriptorParseException { + VoteBuilder.createWithKnownFlagsLine("known-flags"); + } + + @Test(expected = DescriptorParseException.class) + public void testKnownFlagsOneSpace() throws DescriptorParseException { + VoteBuilder.createWithKnownFlagsLine("known-flags "); + } +} +
tor-commits@lists.torproject.org