[tor-commits] [stem/master] RouterStatusEntry creation

atagar at torproject.org atagar at torproject.org
Tue May 2 19:57:29 UTC 2017


commit 5245c052ba5cd9cd80d45f7bbda4eade2425d8ba
Author: Damian Johnson <atagar at torproject.org>
Date:   Mon May 1 14:08:18 2017 -0700

    RouterStatusEntry creation
---
 stem/descriptor/router_status_entry.py            |  28 +++++
 test/mocking.py                                   |  80 ---------------
 test/unit/descriptor/networkstatus/document_v3.py |  26 +++--
 test/unit/descriptor/router_status_entry.py       | 118 +++++++++-------------
 test/unit/response/events.py                      |   7 +-
 test/unit/tutorial.py                             |   7 +-
 test/unit/tutorial_examples.py                    |  18 ++--
 7 files changed, 101 insertions(+), 183 deletions(-)

diff --git a/stem/descriptor/router_status_entry.py b/stem/descriptor/router_status_entry.py
index 129f6f7..973f833 100644
--- a/stem/descriptor/router_status_entry.py
+++ b/stem/descriptor/router_status_entry.py
@@ -29,6 +29,7 @@ import stem.util.str_tools
 from stem.descriptor import (
   KEYWORD_LINE,
   Descriptor,
+  _descriptor_content,
   _value,
   _values,
   _descriptor_components,
@@ -36,6 +37,21 @@ from stem.descriptor import (
   _read_until_keywords,
 )
 
+ROUTER_STATUS_ENTRY_V2_HEADER = (
+  ('r', 'caerSidi p1aag7VwarGxqctS7/fS0y5FU+s oQZFLYe9e4A7bOkWKR7TaNxb0JE 2012-08-06 11:19:31 71.35.150.29 9001 0'),
+)
+
+ROUTER_STATUS_ENTRY_V3_HEADER = (
+  ('r', 'caerSidi p1aag7VwarGxqctS7/fS0y5FU+s oQZFLYe9e4A7bOkWKR7TaNxb0JE 2012-08-06 11:19:31 71.35.150.29 9001 0'),
+  ('s', 'Fast Named Running Stable Valid'),
+)
+
+ROUTER_STATUS_ENTRY_MICRO_V3_HEADER = (
+  ('r', 'Konata ARIJF2zbqirB9IwsW0mQznccWww 2012-09-24 13:40:40 69.64.48.168 9001 9030'),
+  ('m', 'aiUklwBrua82obG5AsTX+iEpkjQA2+AQHxZ7GwMfY70'),
+  ('s', 'Fast Guard HSDir Named Running Stable V2Dir Valid'),
+)
+
 _parse_pr_line = _parse_protocol_line('pr', 'protocols')
 
 
@@ -511,6 +527,10 @@ class RouterStatusEntryV2(RouterStatusEntry):
     'digest': (None, _parse_r_line),
   })
 
+  @classmethod
+  def content(cls, attr = None, exclude = ()):
+    return _descriptor_content(attr, exclude, ROUTER_STATUS_ENTRY_V2_HEADER)
+
   def _name(self, is_plural = False):
     return 'Router status entries (v2)' if is_plural else 'Router status entry (v2)'
 
@@ -604,6 +624,10 @@ class RouterStatusEntryV3(RouterStatusEntry):
     'm': _parse_m_line,
   })
 
+  @classmethod
+  def content(cls, attr = None, exclude = ()):
+    return _descriptor_content(attr, exclude, ROUTER_STATUS_ENTRY_V3_HEADER)
+
   def _name(self, is_plural = False):
     return 'Router status entries (v3)' if is_plural else 'Router status entry (v3)'
 
@@ -673,6 +697,10 @@ class RouterStatusEntryMicroV3(RouterStatusEntry):
     'pr': _parse_pr_line,
   })
 
+  @classmethod
+  def content(cls, attr = None, exclude = ()):
+    return _descriptor_content(attr, exclude, ROUTER_STATUS_ENTRY_MICRO_V3_HEADER)
+
   def _name(self, is_plural = False):
     return 'Router status entries (micro v3)' if is_plural else 'Router status entry (micro v3)'
 
diff --git a/test/mocking.py b/test/mocking.py
index 09d3631..c88784a 100644
--- a/test/mocking.py
+++ b/test/mocking.py
@@ -18,11 +18,6 @@ Helper functions for creating mock objects.
       get_key_certificate            - KeyCertificate
       get_network_status_document_v2 - NetworkStatusDocumentV2
       get_network_status_document_v3 - NetworkStatusDocumentV3
-
-    stem.descriptor.router_status_entry
-      get_router_status_entry_v2       - RouterStatusEntryV2
-      get_router_status_entry_v3       - RouterStatusEntryV3
-      get_router_status_entry_micro_v3 - RouterStatusEntryMicroV3
 """
 
 import hashlib
@@ -58,21 +53,6 @@ DOC_SIG = stem.descriptor.networkstatus.DocumentSignature(
   'BF112F1C6D5543CFD0A32215ACABD4197B5279AD',
   '-----BEGIN SIGNATURE-----%s-----END SIGNATURE-----' % CRYPTO_BLOB)
 
-ROUTER_STATUS_ENTRY_V2_HEADER = (
-  ('r', 'caerSidi p1aag7VwarGxqctS7/fS0y5FU+s oQZFLYe9e4A7bOkWKR7TaNxb0JE 2012-08-06 11:19:31 71.35.150.29 9001 0'),
-)
-
-ROUTER_STATUS_ENTRY_V3_HEADER = (
-  ('r', 'caerSidi p1aag7VwarGxqctS7/fS0y5FU+s oQZFLYe9e4A7bOkWKR7TaNxb0JE 2012-08-06 11:19:31 71.35.150.29 9001 0'),
-  ('s', 'Fast Named Running Stable Valid'),
-)
-
-ROUTER_STATUS_ENTRY_MICRO_V3_HEADER = (
-  ('r', 'Konata ARIJF2zbqirB9IwsW0mQznccWww 2012-09-24 13:40:40 69.64.48.168 9001 9030'),
-  ('m', 'aiUklwBrua82obG5AsTX+iEpkjQA2+AQHxZ7GwMfY70'),
-  ('s', 'Fast Guard HSDir Named Running Stable V2Dir Valid'),
-)
-
 AUTHORITY_HEADER = (
   ('dir-source', 'turtles 27B6B5996C426270A5C95488AA5BCEB6BCC86956 no.place.com 76.73.17.194 9030 9090'),
   ('contact', 'Mike Perry <email>'),
@@ -287,66 +267,6 @@ def _get_descriptor_content(attr = None, exclude = (), header_template = (), foo
   return stem.util.str_tools._to_bytes('\n'.join(header_content + remainder + footer_content))
 
 
-def get_router_status_entry_v2(attr = None, exclude = (), content = False):
-  """
-  Provides the descriptor content for...
-  stem.descriptor.router_status_entry.RouterStatusEntryV2
-
-  :param dict attr: keyword/value mappings to be included in the descriptor
-  :param list exclude: mandatory keywords to exclude from the descriptor
-  :param bool content: provides the str content of the descriptor rather than the class if True
-
-  :returns: RouterStatusEntryV2 for the requested descriptor content
-  """
-
-  desc_content = _get_descriptor_content(attr, exclude, ROUTER_STATUS_ENTRY_V2_HEADER)
-
-  if content:
-    return desc_content
-  else:
-    return stem.descriptor.router_status_entry.RouterStatusEntryV2(desc_content, validate = True)
-
-
-def get_router_status_entry_v3(attr = None, exclude = (), content = False):
-  """
-  Provides the descriptor content for...
-  stem.descriptor.router_status_entry.RouterStatusEntryV3
-
-  :param dict attr: keyword/value mappings to be included in the descriptor
-  :param list exclude: mandatory keywords to exclude from the descriptor
-  :param bool content: provides the str content of the descriptor rather than the class if True
-
-  :returns: RouterStatusEntryV3 for the requested descriptor content
-  """
-
-  desc_content = _get_descriptor_content(attr, exclude, ROUTER_STATUS_ENTRY_V3_HEADER)
-
-  if content:
-    return desc_content
-  else:
-    return stem.descriptor.router_status_entry.RouterStatusEntryV3(desc_content, validate = True)
-
-
-def get_router_status_entry_micro_v3(attr = None, exclude = (), content = False):
-  """
-  Provides the descriptor content for...
-  stem.descriptor.router_status_entry.RouterStatusEntryMicroV3
-
-  :param dict attr: keyword/value mappings to be included in the descriptor
-  :param list exclude: mandatory keywords to exclude from the descriptor
-  :param bool content: provides the str content of the descriptor rather than the class if True
-
-  :returns: RouterStatusEntryMicroV3 for the requested descriptor content
-  """
-
-  desc_content = _get_descriptor_content(attr, exclude, ROUTER_STATUS_ENTRY_MICRO_V3_HEADER)
-
-  if content:
-    return desc_content
-  else:
-    return stem.descriptor.router_status_entry.RouterStatusEntryMicroV3(desc_content, validate = True)
-
-
 def get_directory_authority(attr = None, exclude = (), is_vote = False, content = False):
   """
   Provides the descriptor content for...
diff --git a/test/unit/descriptor/networkstatus/document_v3.py b/test/unit/descriptor/networkstatus/document_v3.py
index 6a2e784..d6ea34e 100644
--- a/test/unit/descriptor/networkstatus/document_v3.py
+++ b/test/unit/descriptor/networkstatus/document_v3.py
@@ -29,8 +29,6 @@ from stem.descriptor.router_status_entry import (
 )
 
 from test.mocking import (
-  get_router_status_entry_v3,
-  get_router_status_entry_micro_v3,
   get_directory_authority,
   get_network_status_document_v3,
   DOC_SIG,
@@ -400,8 +398,8 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
 
     # makes a consensus with a couple routers, both with the same nickname
 
-    entry1 = get_router_status_entry_v3({'s': 'Fast'})
-    entry2 = get_router_status_entry_v3({'s': 'Valid'})
+    entry1 = RouterStatusEntryV3.create({'s': 'Fast'})
+    entry2 = RouterStatusEntryV3.create({'s': 'Valid'})
     content = get_network_status_document_v3(routers = (entry1, entry2), content = True)
 
     # first example: parsing via the NetworkStatusDocumentV3 constructor
@@ -428,8 +426,8 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     # Simple sanity check that they provide the right type, and that the
     # document includes or excludes the router status entries as appropriate.
 
-    entry1 = get_router_status_entry_v3({'s': 'Fast'})
-    entry2 = get_router_status_entry_v3({
+    entry1 = RouterStatusEntryV3.create({'s': 'Fast'})
+    entry2 = RouterStatusEntryV3.create({
       'r': 'Nightfae AWt0XNId/OU2xX5xs5hVtDc5Mes 6873oEfM7fFIbxYtwllw9GPDwkA 2013-02-20 11:12:27 85.177.66.233 9001 9030',
       's': 'Valid',
     })
@@ -451,8 +449,8 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     Try parsing a document via the _parse_file() function.
     """
 
-    entry1 = get_router_status_entry_v3({'s': 'Fast'})
-    entry2 = get_router_status_entry_v3({'s': 'Valid'})
+    entry1 = RouterStatusEntryV3.create({'s': 'Fast'})
+    entry2 = RouterStatusEntryV3.create({'s': 'Valid'})
     content = get_network_status_document_v3(routers = (entry1, entry2), content = True)
 
     # the document that the entries refer to should actually be the minimal
@@ -1093,8 +1091,8 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     document.
     """
 
-    entry1 = get_router_status_entry_v3({'s': 'Fast'})
-    entry2 = get_router_status_entry_v3({
+    entry1 = RouterStatusEntryV3.create({'s': 'Fast'})
+    entry2 = RouterStatusEntryV3.create({
       'r': 'Nightfae AWt0XNId/OU2xX5xs5hVtDc5Mes 6873oEfM7fFIbxYtwllw9GPDwkA 2013-02-20 11:12:27 85.177.66.233 9001 9030',
       's': 'Valid',
     })
@@ -1106,7 +1104,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
 
     # try with an invalid RouterStatusEntry
 
-    entry3 = RouterStatusEntryV3(get_router_status_entry_v3({'r': 'ugabuga'}, content = True), False)
+    entry3 = RouterStatusEntryV3(RouterStatusEntryV3.content({'r': 'ugabuga'}), False)
     content = get_network_status_document_v3(routers = (entry3,), content = True)
 
     self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
@@ -1127,8 +1125,8 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     document.
     """
 
-    entry1 = get_router_status_entry_micro_v3({'s': 'Fast'})
-    entry2 = get_router_status_entry_micro_v3({
+    entry1 = RouterStatusEntryMicroV3.create({'s': 'Fast'})
+    entry2 = RouterStatusEntryMicroV3.create({
       'r': 'tornodeviennasil AcWxDFxrHetHYS5m6/MVt8ZN6AM 2013-03-13 22:09:13 78.142.142.246 443 80',
       's': 'Valid',
     })
@@ -1140,7 +1138,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
 
     # try with an invalid RouterStatusEntry
 
-    entry3 = RouterStatusEntryMicroV3(get_router_status_entry_micro_v3({'r': 'ugabuga'}, content = True), False)
+    entry3 = RouterStatusEntryMicroV3(RouterStatusEntryMicroV3.content({'r': 'ugabuga'}), False)
 
     content = get_network_status_document_v3({'network-status-version': '3 microdesc'}, routers = (entry3,), content = True)
     self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
diff --git a/test/unit/descriptor/router_status_entry.py b/test/unit/descriptor/router_status_entry.py
index 43bcaee..37d763e 100644
--- a/test/unit/descriptor/router_status_entry.py
+++ b/test/unit/descriptor/router_status_entry.py
@@ -3,22 +3,27 @@ Unit tests for stem.descriptor.router_status_entry.
 """
 
 import datetime
+import functools
 import unittest
 
 import stem.descriptor
 
 from stem import Flag
-from stem.descriptor.router_status_entry import RouterStatusEntryV3, _base64_to_hex
 from stem.exit_policy import MicroExitPolicy
 from stem.version import Version
 
-from test.unit.descriptor import get_resource
+from test.unit.descriptor import (
+  get_resource,
+  base_expect_invalid_attr,
+  base_expect_invalid_attr_for_text,
+)
 
-from test.mocking import (
-  get_router_status_entry_v2,
-  get_router_status_entry_v3,
-  get_router_status_entry_micro_v3,
+from stem.descriptor.router_status_entry import (
   ROUTER_STATUS_ENTRY_V3_HEADER,
+  RouterStatusEntryV2,
+  RouterStatusEntryV3,
+  RouterStatusEntryMicroV3,
+  _base64_to_hex,
 )
 
 ENTRY_WITHOUT_ED25519 = """\
@@ -47,6 +52,9 @@ m 18,19,20 sha256=AkZH3gIvz3wunsroqh5izBJizdYuR7kn2oVbsvqgML8
 m 21 sha256=AVp41YVxKEJCaoEf0+77Cdvyw5YgpyDXdob0+LSv/pE
 """
 
+expect_invalid_attr = functools.partial(base_expect_invalid_attr, RouterStatusEntryV3, 'nickname', 'caerSidi')
+expect_invalid_attr_for_text = functools.partial(base_expect_invalid_attr_for_text, RouterStatusEntryV3, 'nickname', 'caerSidi')
+
 
 def vote_document():
   class Stub(object):
@@ -86,7 +94,7 @@ class TestRouterStatusEntry(unittest.TestCase):
     Parses a minimal v2 router status entry.
     """
 
-    entry = get_router_status_entry_v2()
+    entry = RouterStatusEntryV2.create()
 
     self.assertEqual(None, entry.document)
     self.assertEqual('caerSidi', entry.nickname)
@@ -106,7 +114,7 @@ class TestRouterStatusEntry(unittest.TestCase):
     Parses a minimal v3 router status entry.
     """
 
-    entry = get_router_status_entry_v3()
+    entry = RouterStatusEntryV3.create()
 
     expected_flags = set([Flag.FAST, Flag.NAMED, Flag.RUNNING, Flag.STABLE, Flag.VALID])
     self.assertEqual(None, entry.document)
@@ -135,7 +143,7 @@ class TestRouterStatusEntry(unittest.TestCase):
     Parses a minimal microdescriptor v3 router status entry.
     """
 
-    entry = get_router_status_entry_micro_v3()
+    entry = RouterStatusEntryMicroV3.create()
 
     expected_flags = set([Flag.FAST, Flag.GUARD, Flag.HSDIR, Flag.NAMED, Flag.RUNNING, Flag.STABLE, Flag.V2DIR, Flag.VALID])
     self.assertEqual(None, entry.document)
@@ -222,21 +230,16 @@ class TestRouterStatusEntry(unittest.TestCase):
     Parses a router status entry that's missing fields.
     """
 
-    content = get_router_status_entry_v3(exclude = ('r', 's'), content = True)
-    self._expect_invalid_attr(content, 'address')
-
-    content = get_router_status_entry_v3(exclude = ('r',), content = True)
-    self._expect_invalid_attr(content, 'address')
-
-    content = get_router_status_entry_v3(exclude = ('s',), content = True)
-    self._expect_invalid_attr(content, 'flags')
+    expect_invalid_attr_for_text(self, RouterStatusEntryV3.content(exclude = ('r', 's')), 'address')
+    expect_invalid_attr_for_text(self, RouterStatusEntryV3.content(exclude = ('r',)), 'address')
+    expect_invalid_attr_for_text(self, RouterStatusEntryV3.content(exclude = ('s',)), 'flags')
 
   def test_unrecognized_lines(self):
     """
     Parses a router status entry with new keywords.
     """
 
-    entry = get_router_status_entry_v3({'z': 'New tor feature: sparkly unicorns!'})
+    entry = RouterStatusEntryV3.create({'z': 'New tor feature: sparkly unicorns!'})
     self.assertEqual(['z New tor feature: sparkly unicorns!'], entry.get_unrecognized_lines())
 
   def test_proceeding_line(self):
@@ -244,7 +247,7 @@ class TestRouterStatusEntry(unittest.TestCase):
     Includes content prior to the 'r' line.
     """
 
-    content = b'z some stuff\n' + get_router_status_entry_v3(content = True)
+    content = b'z some stuff\n' + RouterStatusEntryV3.content()
     self.assertRaises(ValueError, RouterStatusEntryV3, content, True)
     self.assertEqual(['z some stuff'], RouterStatusEntryV3(content, False).get_unrecognized_lines())
 
@@ -253,7 +256,7 @@ class TestRouterStatusEntry(unittest.TestCase):
     Includes blank lines, which should be ignored.
     """
 
-    content = get_router_status_entry_v3(content = True) + b'\n\nv Tor 0.2.2.35\n\n'
+    content = RouterStatusEntryV3.content() + b'\n\nv Tor 0.2.2.35\n\n'
     entry = RouterStatusEntryV3(content)
     self.assertEqual('Tor 0.2.2.35', entry.version_line)
 
@@ -262,7 +265,7 @@ class TestRouterStatusEntry(unittest.TestCase):
     Duplicates linesin the entry.
     """
 
-    lines = get_router_status_entry_v3(content = True).split(b'\n')
+    lines = RouterStatusEntryV3.content().split(b'\n')
 
     for index, duplicate_line in enumerate(lines):
       content = b'\n'.join(lines[:index] + [duplicate_line] + lines[index:])
@@ -291,9 +294,7 @@ class TestRouterStatusEntry(unittest.TestCase):
       test_components = [comp[1] for comp in components]
       test_components.remove(value)
       r_line = ' '.join(test_components)
-
-      content = get_router_status_entry_v3({'r': r_line}, content = True)
-      self._expect_invalid_attr(content, attr)
+      expect_invalid_attr(self, {'r': r_line}, attr)
 
   def test_malformed_nickname(self):
     """
@@ -308,7 +309,6 @@ class TestRouterStatusEntry(unittest.TestCase):
 
     for value in test_values:
       r_line = ROUTER_STATUS_ENTRY_V3_HEADER[0][1].replace('caerSidi', value)
-      content = get_router_status_entry_v3({'r': r_line}, content = True)
 
       # TODO: Initial whitespace is consumed as part of the keyword/value
       # divider. This is a bug in the case of V3 router status entries, but
@@ -323,7 +323,7 @@ class TestRouterStatusEntry(unittest.TestCase):
       if value == '':
         value = None
 
-      self._expect_invalid_attr(content, 'nickname')
+      expect_invalid_attr(self, {'r': r_line}, 'nickname')
 
   def test_malformed_fingerprint(self):
     """
@@ -338,8 +338,7 @@ class TestRouterStatusEntry(unittest.TestCase):
 
     for value in test_values:
       r_line = ROUTER_STATUS_ENTRY_V3_HEADER[0][1].replace('p1aag7VwarGxqctS7/fS0y5FU+s', value)
-      content = get_router_status_entry_v3({'r': r_line}, content = True)
-      self._expect_invalid_attr(content, 'fingerprint')
+      expect_invalid_attr(self, {'r': r_line}, 'fingerprint')
 
   def test_malformed_published_date(self):
     """
@@ -364,8 +363,7 @@ class TestRouterStatusEntry(unittest.TestCase):
 
     for value in test_values:
       r_line = ROUTER_STATUS_ENTRY_V3_HEADER[0][1].replace('2012-08-06 11:19:31', value)
-      content = get_router_status_entry_v3({'r': r_line}, content = True)
-      self._expect_invalid_attr(content, 'published')
+      expect_invalid_attr(self, {'r': r_line}, 'published')
 
   def test_malformed_address(self):
     """
@@ -382,8 +380,7 @@ class TestRouterStatusEntry(unittest.TestCase):
 
     for value in test_values:
       r_line = ROUTER_STATUS_ENTRY_V3_HEADER[0][1].replace('71.35.150.29', value)
-      content = get_router_status_entry_v3({'r': r_line}, content = True)
-      self._expect_invalid_attr(content, 'address')
+      expect_invalid_attr(self, {'r': r_line}, 'address')
 
   def test_malformed_port(self):
     """
@@ -412,9 +409,7 @@ class TestRouterStatusEntry(unittest.TestCase):
             r_line = r_line[:-1] + value
 
           attr = 'or_port' if include_or_port else 'dir_port'
-
-          content = get_router_status_entry_v3({'r': r_line}, content = True)
-          self._expect_invalid_attr(content, attr)
+          expect_invalid_attr(self, {'r': r_line}, attr)
 
   def test_ipv6_addresses(self):
     """
@@ -427,12 +422,12 @@ class TestRouterStatusEntry(unittest.TestCase):
     }
 
     for a_line, expected in test_values.items():
-      entry = get_router_status_entry_v3({'a': a_line})
+      entry = RouterStatusEntryV3.create({'a': a_line})
       self.assertEqual(expected, entry.or_addresses)
 
     # includes multiple 'a' lines
 
-    content = get_router_status_entry_v3(content = True)
+    content = RouterStatusEntryV3.content()
     content += b'\na [2607:fcd0:daaa:101::602c:bd62]:443'
     content += b'\na [1148:fcd0:daaa:101::602c:bd62]:80'
 
@@ -452,8 +447,7 @@ class TestRouterStatusEntry(unittest.TestCase):
     )
 
     for a_line in test_values:
-      content = get_router_status_entry_v3({'a': a_line}, content = True)
-      self._expect_invalid_attr(content, expected_value = {})
+      expect_invalid_attr(self, {'a': a_line}, expected_value = {})
 
   def test_flags(self):
     """
@@ -468,7 +462,7 @@ class TestRouterStatusEntry(unittest.TestCase):
     }
 
     for s_line, expected in test_values.items():
-      entry = get_router_status_entry_v3({'s': s_line})
+      entry = RouterStatusEntryV3.create({'s': s_line})
       self.assertEqual(expected, entry.flags)
 
     # tries some invalid inputs
@@ -479,11 +473,10 @@ class TestRouterStatusEntry(unittest.TestCase):
     }
 
     for s_line, expected in test_values.items():
-      content = get_router_status_entry_v3({'s': s_line}, content = True)
-      self._expect_invalid_attr(content, 'flags', expected)
+      expect_invalid_attr(self, {'s': s_line}, 'flags', expected)
 
   def test_protocols(self):
-    desc = get_router_status_entry_v3({'pr': 'Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 Link=1-4 LinkAuth=1 Microdesc=1 Relay=1-2'})
+    desc = RouterStatusEntryV3.create({'pr': 'Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 Link=1-4 LinkAuth=1 Microdesc=1 Relay=1-2'})
     self.assertEqual(10, len(desc.protocols))
 
   def test_versions(self):
@@ -499,13 +492,12 @@ class TestRouterStatusEntry(unittest.TestCase):
     }
 
     for v_line, expected in test_values.items():
-      entry = get_router_status_entry_v3({'v': v_line})
+      entry = RouterStatusEntryV3.create({'v': v_line})
       self.assertEqual(expected, entry.version)
       self.assertEqual(v_line, entry.version_line)
 
     # tries an invalid input
-    content = get_router_status_entry_v3({'v': 'Tor ugabuga'}, content = True)
-    self._expect_invalid_attr(content, 'version')
+    expect_invalid_attr(self, {'v': 'Tor ugabuga'}, 'version')
 
   def test_bandwidth(self):
     """
@@ -521,7 +513,7 @@ class TestRouterStatusEntry(unittest.TestCase):
     }
 
     for w_line, expected in test_values.items():
-      entry = get_router_status_entry_v3({'w': w_line})
+      entry = RouterStatusEntryV3.create({'w': w_line})
       self.assertEqual(expected[0], entry.bandwidth)
       self.assertEqual(expected[1], entry.measured)
       self.assertEqual(expected[2], entry.is_unmeasured)
@@ -547,8 +539,7 @@ class TestRouterStatusEntry(unittest.TestCase):
     )
 
     for w_line in test_values:
-      content = get_router_status_entry_v3({'w': w_line}, content = True)
-      self._expect_invalid_attr(content)
+      expect_invalid_attr(self, {'w': w_line})
 
   def test_exit_policy(self):
     """
@@ -561,7 +552,7 @@ class TestRouterStatusEntry(unittest.TestCase):
     }
 
     for p_line, expected in test_values.items():
-      entry = get_router_status_entry_v3({'p': p_line})
+      entry = RouterStatusEntryV3.create({'p': p_line})
       self.assertEqual(expected, entry.exit_policy)
 
     # tries some invalid inputs
@@ -573,8 +564,7 @@ class TestRouterStatusEntry(unittest.TestCase):
     )
 
     for p_line in test_values:
-      content = get_router_status_entry_v3({'p': p_line}, content = True)
-      self._expect_invalid_attr(content, 'exit_policy')
+      expect_invalid_attr(self, {'p': p_line}, 'exit_policy')
 
   def test_microdescriptor_hashes(self):
     """
@@ -591,13 +581,13 @@ class TestRouterStatusEntry(unittest.TestCase):
     }
 
     for m_line, expected in test_values.items():
-      content = get_router_status_entry_v3({'m': m_line}, content = True)
+      content = RouterStatusEntryV3.content({'m': m_line})
       entry = RouterStatusEntryV3(content, document = vote_document())
       self.assertEqual(expected, entry.microdescriptor_hashes)
 
     # try with multiple 'm' lines
 
-    content = get_router_status_entry_v3(content = True)
+    content = RouterStatusEntryV3.content()
     content += b'\nm 11,12 sha256=g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs'
     content += b'\nm 31,32 sha512=g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs'
 
@@ -610,8 +600,7 @@ class TestRouterStatusEntry(unittest.TestCase):
     self.assertEqual(expected, entry.microdescriptor_hashes)
 
     # try without a document
-    content = get_router_status_entry_v3({'m': '8,9,10,11,12'}, content = True)
-    self._expect_invalid_attr(content, 'microdescriptor_hashes', expected_value = [])
+    expect_invalid_attr(self, {'m': '8,9,10,11,12'}, 'microdescriptor_hashes', expected_value = [])
 
     # tries some invalid inputs
     test_values = (
@@ -621,7 +610,7 @@ class TestRouterStatusEntry(unittest.TestCase):
     )
 
     for m_line in test_values:
-      content = get_router_status_entry_v3({'m': m_line}, content = True)
+      content = RouterStatusEntryV3.content({'m': m_line})
       self.assertRaises(ValueError, RouterStatusEntryV3, content, True, vote_document())
 
   def test_with_carriage_returns(self):
@@ -638,18 +627,3 @@ class TestRouterStatusEntry(unittest.TestCase):
 
       router = next(descriptors)
       self.assertEqual([Flag.FAST, Flag.RUNNING, Flag.STABLE, Flag.VALID], router.flags)
-
-  def _expect_invalid_attr(self, content, attr = None, expected_value = None):
-    """
-    Asserts that construction will fail due to content having a malformed
-    attribute. If an attr is provided then we check that it matches an expected
-    value when we're constructed without validation.
-    """
-
-    self.assertRaises(ValueError, RouterStatusEntryV3, content, True)
-    entry = RouterStatusEntryV3(content, False)
-
-    if attr:
-      self.assertEqual(expected_value, getattr(entry, attr))
-    else:
-      self.assertEqual('caerSidi', entry.nickname)
diff --git a/test/unit/response/events.py b/test/unit/response/events.py
index 8a95156..6023db6 100644
--- a/test/unit/response/events.py
+++ b/test/unit/response/events.py
@@ -11,6 +11,7 @@ import stem.response.events
 import stem.util.log
 
 from stem import *  # enums and exceptions
+from stem.descriptor.router_status_entry import RouterStatusEntryV3
 from test import mocking
 
 try:
@@ -934,12 +935,12 @@ class TestEvents(unittest.TestCase):
   def test_new_consensus_event(self):
     expected_desc = []
 
-    expected_desc.append(mocking.get_router_status_entry_v3({
+    expected_desc.append(RouterStatusEntryV3.create({
       'r': 'Beaver /96bKo4soysolMgKn5Hex2nyFSY pAJH9dSBp/CG6sPhhVY/5bLaVPM 2012-12-02 22:02:45 77.223.43.54 9001 0',
       's': 'Fast Named Running Stable Valid',
     }))
 
-    expected_desc.append(mocking.get_router_status_entry_v3({
+    expected_desc.append(RouterStatusEntryV3.create({
       'r': 'Unnamed /+fJRWjmIGNAL2C5rRZHq3R91tA 7AnpZjfdBpYzXnMNm+w1bTsFF6Y 2012-12-02 17:51:10 91.121.184.87 9001 0',
       's': 'Fast Guard Running Stable Valid',
     }))
@@ -950,7 +951,7 @@ class TestEvents(unittest.TestCase):
     self.assertEqual(expected_desc, event.desc)
 
   def test_ns_event(self):
-    expected_desc = mocking.get_router_status_entry_v3({
+    expected_desc = RouterStatusEntryV3.create({
       'r': 'whnetz dbBxYcJriTTrcxsuy4PUZcMRwCA VStM7KAIH/mXXoGDUpoGB1OXufg 2012-12-02 21:03:56 141.70.120.13 9001 9030',
       's': 'Fast HSDir Named Stable V2Dir Valid',
     })
diff --git a/test/unit/tutorial.py b/test/unit/tutorial.py
index a404b42..48d0abb 100644
--- a/test/unit/tutorial.py
+++ b/test/unit/tutorial.py
@@ -10,6 +10,7 @@ import stem.descriptor.remote
 from stem.control import Controller
 from stem.descriptor.reader import DescriptorReader
 from stem.descriptor.server_descriptor import RelayDescriptor
+from stem.descriptor.router_status_entry import RouterStatusEntryV2, RouterStatusEntryV3
 from test import mocking
 from test.unit import exec_documentation_example
 
@@ -127,7 +128,7 @@ class TestTutorial(unittest.TestCase):
   @patch('sys.stdout', new_callable = StringIO)
   @patch('stem.descriptor.remote.DescriptorDownloader')
   def test_mirror_mirror_on_the_wall_1(self, downloader_mock, stdout_mock):
-    downloader_mock().get_consensus().run.return_value = [mocking.get_router_status_entry_v2()]
+    downloader_mock().get_consensus().run.return_value = [RouterStatusEntryV2.create()]
 
     exec_documentation_example('current_descriptors.py')
     self.assertEqual('found relay caerSidi (A7569A83B5706AB1B1A9CB52EFF7D2D32E4553EB)\n', stdout_mock.getvalue())
@@ -136,7 +137,7 @@ class TestTutorial(unittest.TestCase):
   @patch('stem.control.Controller.from_port', spec = Controller)
   def test_mirror_mirror_on_the_wall_2(self, from_port_mock, stdout_mock):
     controller = from_port_mock().__enter__()
-    controller.get_network_statuses.return_value = [mocking.get_router_status_entry_v2()]
+    controller.get_network_statuses.return_value = [RouterStatusEntryV2.create()]
 
     exec_documentation_example('descriptor_from_tor_control_socket.py')
     self.assertEqual('found relay caerSidi (A7569A83B5706AB1B1A9CB52EFF7D2D32E4553EB)\n', stdout_mock.getvalue())
@@ -151,7 +152,7 @@ class TestTutorial(unittest.TestCase):
         print('found relay %s (%s)' % (desc.nickname, desc.fingerprint))
 
     test_file = io.BytesIO(mocking.get_network_status_document_v3(
-      routers = [mocking.get_router_status_entry_v3()],
+      routers = [RouterStatusEntryV3.create()],
       content = True,
     ))
 
diff --git a/test/unit/tutorial_examples.py b/test/unit/tutorial_examples.py
index 267fd3d..b3ac813 100644
--- a/test/unit/tutorial_examples.py
+++ b/test/unit/tutorial_examples.py
@@ -19,16 +19,12 @@ from stem.control import Controller
 from stem.util import str_type
 from stem.descriptor.remote import DIRECTORY_AUTHORITIES
 from stem.descriptor.server_descriptor import RelayDescriptor
+from stem.descriptor.router_status_entry import ROUTER_STATUS_ENTRY_V3_HEADER, RouterStatusEntryV3
 
 from test import mocking
+from test.mocking import get_network_status_document_v3
 from test.unit import exec_documentation_example
 
-from test.mocking import (
-  get_router_status_entry_v3,
-  ROUTER_STATUS_ENTRY_V3_HEADER,
-  get_network_status_document_v3,
-)
-
 try:
   # added in python 3.3
   from unittest.mock import Mock, patch
@@ -130,9 +126,9 @@ def _get_router_status(address = None, port = None, nickname = None, fingerprint
     r_line = r_line.replace('p1aag7VwarGxqctS7/fS0y5FU+s', fingerprint_base64)
 
   if s_line:
-    return get_router_status_entry_v3({'r': r_line, 's': s_line})
+    return RouterStatusEntryV3.create({'r': r_line, 's': s_line})
   else:
-    return get_router_status_entry_v3({'r': r_line})
+    return RouterStatusEntryV3.create({'r': r_line})
 
 
 class TestTutorialExamples(unittest.TestCase):
@@ -299,8 +295,8 @@ class TestTutorialExamples(unittest.TestCase):
     directory_values[0].address = '131.188.40.189'
     get_authorities_mock().values.return_value = directory_values
 
-    entry_with_measurement = get_router_status_entry_v3({'w': 'Bandwidth=1 Measured=1'})
-    entry_without_measurement = get_router_status_entry_v3()
+    entry_with_measurement = RouterStatusEntryV3.create({'w': 'Bandwidth=1 Measured=1'})
+    entry_without_measurement = RouterStatusEntryV3.create()
 
     query1 = Mock()
     query1.download_url = 'http://131.188.40.189:80/tor/status-vote/current/authority'
@@ -336,7 +332,7 @@ class TestTutorialExamples(unittest.TestCase):
       for fingerprint, relay in consensus.routers.items():
         print('%s: %s' % (fingerprint, relay.nickname))
 
-    network_status = get_network_status_document_v3(routers = (get_router_status_entry_v3(),))
+    network_status = get_network_status_document_v3(routers = (RouterStatusEntryV3.create(),))
     query_mock().run.return_value = [network_status]
     parse_file_mock.return_value = itertools.cycle([network_status])
 





More information about the tor-commits mailing list