[tor-commits] [stem/master] Unit tests for parse_file() and router entries
atagar at torproject.org
atagar at torproject.org
Sat Oct 13 18:35:45 UTC 2012
commit 72c561b9adb7e3963aa14da98b8d9bc77df533dd
Author: Damian Johnson <atagar at torproject.org>
Date: Sat Sep 22 17:57:49 2012 -0700
Unit tests for parse_file() and router entries
On reflection the reason that the prior changes passed the unit tests so easily
was because the parse_file() function and inclusion of router status entries
was completely untested by my unit tests. The RouterStatusEntry class itself it
tested, but not its inclusion in a document. Integ tests would certainly cover
this, but I want the unit tests to exercise everything too.
Adding the missing tests and some fixes for issues that they revealed.
---
stem/descriptor/networkstatus.py | 16 ++++++-
test/unit/descriptor/networkstatus/document.py | 57 ++++++++++++++++++++++-
2 files changed, 68 insertions(+), 5 deletions(-)
diff --git a/stem/descriptor/networkstatus.py b/stem/descriptor/networkstatus.py
index 8774b95..2514a62 100644
--- a/stem/descriptor/networkstatus.py
+++ b/stem/descriptor/networkstatus.py
@@ -140,7 +140,7 @@ def parse_file(document_file, validate = True, is_microdescriptor = False):
routers_end = document_file.tell()
footer = document_file.readlines()
- document_content = header + footer
+ document_content = "".join(header + footer)
if not is_microdescriptor:
document = NetworkStatusDocument(document_content, validate)
@@ -200,7 +200,7 @@ def _get_entries(document_file, validate, entry_class, entry_keyword, start_posi
document_file.seek(start_position)
while document_file.tell() < end_position:
desc_content = "".join(_read_until_keywords(entry_keyword, document_file, ignore_first = True, end_position = end_position))
- yield router_type(desc_content, validate, *extra_args)
+ yield entry_class(desc_content, validate, *extra_args)
class NetworkStatusDocument(stem.descriptor.Descriptor):
"""
@@ -296,6 +296,12 @@ class NetworkStatusDocument(stem.descriptor.Descriptor):
def get_unrecognized_lines(self):
return list(self._unrecognized_lines)
+
+ def __cmp__(self, other):
+ if not isinstance(other, NetworkStatusDocument):
+ return 1
+
+ return str(self) > str(other)
class _DocumentHeader(object):
def __init__(self, document_file, validate, default_params):
@@ -994,6 +1000,12 @@ class RouterStatusEntry(stem.descriptor.Descriptor):
"""
return list(self._unrecognized_lines)
+
+ def __cmp__(self, other):
+ if not isinstance(other, RouterStatusEntry):
+ return 1
+
+ return str(self) > str(other)
class MicrodescriptorConsensus(NetworkStatusDocument):
"""
diff --git a/test/unit/descriptor/networkstatus/document.py b/test/unit/descriptor/networkstatus/document.py
index ad79dde..7570e8c 100644
--- a/test/unit/descriptor/networkstatus/document.py
+++ b/test/unit/descriptor/networkstatus/document.py
@@ -4,10 +4,12 @@ Unit tests for the NetworkStatusDocument of stem.descriptor.networkstatus.
import datetime
import unittest
+import StringIO
import stem.version
from stem.descriptor import Flag
-from stem.descriptor.networkstatus import HEADER_STATUS_DOCUMENT_FIELDS, FOOTER_STATUS_DOCUMENT_FIELDS, DEFAULT_PARAMS, BANDWIDTH_WEIGHT_ENTRIES, NetworkStatusDocument, DocumentSignature
+from stem.descriptor.networkstatus import HEADER_STATUS_DOCUMENT_FIELDS, FOOTER_STATUS_DOCUMENT_FIELDS, DEFAULT_PARAMS, BANDWIDTH_WEIGHT_ENTRIES, RouterStatusEntry, NetworkStatusDocument, DocumentSignature, parse_file
+from test.unit.descriptor.networkstatus.entry import get_router_status_entry
sig_block = """\
-----BEGIN SIGNATURE-----
@@ -33,7 +35,6 @@ NETWORK_STATUS_DOCUMENT_ATTR = {
"directory-signature": "%s %s\n%s" % (SIG.identity, SIG.key_digest, SIG.signature),
}
-
def get_network_status_document(attr = None, exclude = None, routers = None):
"""
Constructs a minimal network status document with the given attributes. This
@@ -89,7 +90,13 @@ def get_network_status_document(attr = None, exclude = None, routers = None):
if attr_value: attr_value = " %s" % attr_value
remainder.append(attr_keyword + attr_value)
- return "\n".join(header_content + remainder + routers + footer_content)
+ # join the routers into a single block, then split it into lines
+ if routers:
+ router_lines = ("\n".join([str(r) for r in routers])).split("\n")
+ else:
+ router_lines = []
+
+ return "\n".join(header_content + remainder + router_lines + footer_content)
class TestNetworkStatusDocument(unittest.TestCase):
def test_minimal_consensus(self):
@@ -156,6 +163,27 @@ class TestNetworkStatusDocument(unittest.TestCase):
self.assertEqual([SIG], document.signatures)
self.assertEqual([], document.get_unrecognized_lines())
+ def test_parse_file(self):
+ """
+ Try parsing a document via the parse_file() function.
+ """
+
+ entry1 = RouterStatusEntry(get_router_status_entry({'s': "Fast"}))
+ entry2 = RouterStatusEntry(get_router_status_entry({'s': "Valid"}))
+ content = get_network_status_document(routers = (entry1, entry2))
+
+ # the document that the entries refer to should actually be the minimal
+ # descriptor (ie, without the entries)
+
+ expected_document = NetworkStatusDocument(get_network_status_document())
+
+ descriptor_file = StringIO.StringIO(content)
+ entries = list(parse_file(descriptor_file))
+
+ self.assertEquals(entry1, entries[0])
+ self.assertEquals(entry2, entries[1])
+ self.assertEquals(expected_document, entries[0].document)
+
def test_missing_fields(self):
"""
Excludes mandatory fields from both a vote and consensus document.
@@ -680,4 +708,27 @@ class TestNetworkStatusDocument(unittest.TestCase):
content = get_network_status_document({"directory-signature": "%s %s\n%s" % tuple(attrs)})
self.assertRaises(ValueError, NetworkStatusDocument, content)
NetworkStatusDocument(content, False) # checks that it's still parseable without validation
+
+ def test_with_router_status_entries(self):
+ """
+ Includes a router status entry within the document. This isn't to test the
+ RouterStatusEntry parsing but rather the inclusion of it within the
+ document.
+ """
+
+ entry1 = RouterStatusEntry(get_router_status_entry({'s': "Fast"}))
+ entry2 = RouterStatusEntry(get_router_status_entry({'s': "Valid"}))
+ content = get_network_status_document(routers = (entry1, entry2))
+
+ document = NetworkStatusDocument(content)
+ self.assertEquals((entry1, entry2), document.routers)
+
+ # try with an invalid RouterStatusEntry
+
+ entry3 = RouterStatusEntry(get_router_status_entry({'r': "ugabuga"}), False)
+ content = get_network_status_document(routers = (entry3,))
+
+ self.assertRaises(ValueError, NetworkStatusDocument, content)
+ document = NetworkStatusDocument(content, False)
+ self.assertEquals((entry3,), document.routers)
More information about the tor-commits
mailing list