[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

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



commit 72679be355dfcde7513040b336d6c1824ea3d853
Author: Damian Johnson <atagar@xxxxxxxxxxxxxx>
Date:   Mon May 1 16:56:54 2017 -0700

    NetworkStatusDocument creation
---
 stem/descriptor/__init__.py                        |   4 +-
 stem/descriptor/networkstatus.py                   | 149 +++++++++++
 test/mocking.py                                    | 296 ---------------------
 .../networkstatus/directory_authority.py           |  43 +--
 test/unit/descriptor/networkstatus/document_v2.py  |  12 +-
 test/unit/descriptor/networkstatus/document_v3.py  | 145 +++++-----
 .../descriptor/networkstatus/key_certificate.py    |  47 ++--
 test/unit/tutorial.py                              |  10 +-
 test/unit/tutorial_examples.py                     |  10 +-
 9 files changed, 283 insertions(+), 433 deletions(-)

diff --git a/stem/descriptor/__init__.py b/stem/descriptor/__init__.py
index c414a4c..1826b36 100644
--- a/stem/descriptor/__init__.py
+++ b/stem/descriptor/__init__.py
@@ -383,7 +383,9 @@ def _descriptor_content(attr = None, exclude = (), header_template = (), footer_
 
       value = attr.pop(keyword, value)
 
-      if not value:
+      if value is None:
+        continue
+      elif value == '':
         content.append(keyword)
       elif value.startswith('\n'):
         # some values like crypto follow the line instead
diff --git a/stem/descriptor/networkstatus.py b/stem/descriptor/networkstatus.py
index 2b00ebc..ff9f105 100644
--- a/stem/descriptor/networkstatus.py
+++ b/stem/descriptor/networkstatus.py
@@ -63,9 +63,11 @@ import stem.util.tor_tools
 import stem.version
 
 from stem.descriptor import (
+  CRYPTO_BLOB,
   PGP_BLOCK_END,
   Descriptor,
   DocumentHandler,
+  _descriptor_content,
   _descriptor_components,
   _read_until_keywords,
   _value,
@@ -206,6 +208,57 @@ PARAM_RANGE = {
   'AuthDirNumSRVAgreements': (1, MAX_PARAM),
 }
 
+AUTHORITY_HEADER = (
+  ('dir-source', 'turtles 27B6B5996C426270A5C95488AA5BCEB6BCC86956 no.place.com 76.73.17.194 9030 9090'),
+  ('contact', 'Mike Perry <email>'),
+)
+
+KEY_CERTIFICATE_HEADER = (
+  ('dir-key-certificate-version', '3'),
+  ('fingerprint', '27B6B5996C426270A5C95488AA5BCEB6BCC86956'),
+  ('dir-key-published', '2011-11-28 21:51:04'),
+  ('dir-key-expires', '2012-11-28 21:51:04'),
+  ('dir-identity-key', '\n-----BEGIN RSA PUBLIC KEY-----%s-----END RSA PUBLIC KEY-----' % CRYPTO_BLOB),
+  ('dir-signing-key', '\n-----BEGIN RSA PUBLIC KEY-----%s-----END RSA PUBLIC KEY-----' % CRYPTO_BLOB),
+)
+
+KEY_CERTIFICATE_FOOTER = (
+  ('dir-key-certification', '\n-----BEGIN SIGNATURE-----%s-----END SIGNATURE-----' % CRYPTO_BLOB),
+)
+
+NETWORK_STATUS_DOCUMENT_HEADER_V2 = (
+  ('network-status-version', '2'),
+  ('dir-source', '18.244.0.114 18.244.0.114 80'),
+  ('fingerprint', '719BE45DE224B607C53707D0E2143E2D423E74CF'),
+  ('contact', 'arma at mit dot edu'),
+  ('published', '2005-12-16 00:13:46'),
+  ('dir-signing-key', '\n-----BEGIN RSA PUBLIC KEY-----%s-----END RSA PUBLIC KEY-----' % CRYPTO_BLOB),
+)
+
+NETWORK_STATUS_DOCUMENT_FOOTER_V2 = (
+  ('directory-signature', 'moria2\n-----BEGIN SIGNATURE-----%s-----END SIGNATURE-----' % CRYPTO_BLOB),
+)
+
+NETWORK_STATUS_DOCUMENT_HEADER = (
+  ('network-status-version', '3'),
+  ('vote-status', 'consensus'),
+  ('consensus-methods', None),
+  ('consensus-method', None),
+  ('published', None),
+  ('valid-after', '2012-09-02 22:00:00'),
+  ('fresh-until', '2012-09-02 22:00:00'),
+  ('valid-until', '2012-09-02 22:00:00'),
+  ('voting-delay', '300 300'),
+  ('client-versions', None),
+  ('server-versions', None),
+  ('package', None),
+  ('known-flags', 'Authority BadExit Exit Fast Guard HSDir Named Running Stable Unnamed V2Dir Valid'),
+  ('params', None),
+)
+
+VOTE_HEADER_DEFAULTS = {'consensus-methods': '1 9', 'published': '2012-09-02 22:00:00'}
+CONSENSUS_HEADER_DEFAULTS = {'consensus-method': '9'}
+
 
 class PackageVersion(collections.namedtuple('PackageVersion', ['name', 'version', 'url', 'digests'])):
   """
@@ -449,6 +502,10 @@ class NetworkStatusDocumentV2(NetworkStatusDocument):
     'directory-signature': _parse_directory_signature_line,
   }
 
+  @classmethod
+  def content(cls, attr = None, exclude = ()):
+    return _descriptor_content(attr, exclude, NETWORK_STATUS_DOCUMENT_HEADER_V2, NETWORK_STATUS_DOCUMENT_FOOTER_V2)
+
   def __init__(self, raw_content, validate = False):
     super(NetworkStatusDocumentV2, self).__init__(raw_content, lazy_load = not validate)
 
@@ -893,6 +950,60 @@ class NetworkStatusDocumentV3(NetworkStatusDocument):
     'directory-signature': _parse_footer_directory_signature_line,
   }
 
+  @classmethod
+  def content(cls, attr = None, exclude = (), authorities = None, routers = None):
+    attr = {} if attr is None else dict(attr)
+
+    is_vote = attr.get('vote-status') == 'vote'
+    extra_defaults = VOTE_HEADER_DEFAULTS if is_vote else CONSENSUS_HEADER_DEFAULTS
+
+    if is_vote and authorities is None:
+      authorities = [DirectoryAuthority.create(is_vote = is_vote)]
+
+    for k, v in extra_defaults.items():
+      if exclude and k in exclude:
+        continue  # explicitly excluding this field
+      elif k not in attr:
+        attr[k] = v
+
+    desc_content = _descriptor_content(attr, exclude, NETWORK_STATUS_DOCUMENT_HEADER, NETWORK_STATUS_DOCUMENT_FOOTER)
+
+    # inject the authorities and/or routers between the header and footer
+
+    if authorities:
+      if b'directory-footer' in desc_content:
+        footer_div = desc_content.find(b'\ndirectory-footer') + 1
+      elif b'directory-signature' in desc_content:
+        footer_div = desc_content.find(b'\ndirectory-signature') + 1
+      else:
+        if routers:
+          desc_content += b'\n'
+
+        footer_div = len(desc_content) + 1
+
+      authority_content = stem.util.str_tools._to_bytes('\n'.join([str(a) for a in authorities]) + '\n')
+      desc_content = desc_content[:footer_div] + authority_content + desc_content[footer_div:]
+
+    if routers:
+      if b'directory-footer' in desc_content:
+        footer_div = desc_content.find(b'\ndirectory-footer') + 1
+      elif b'directory-signature' in desc_content:
+        footer_div = desc_content.find(b'\ndirectory-signature') + 1
+      else:
+        if routers:
+          desc_content += b'\n'
+
+        footer_div = len(desc_content) + 1
+
+      router_content = stem.util.str_tools._to_bytes('\n'.join([str(r) for r in routers]) + '\n')
+      desc_content = desc_content[:footer_div] + router_content + desc_content[footer_div:]
+
+    return desc_content
+
+  @classmethod
+  def create(cls, attr = None, exclude = (), validate = True, authorities = None, routers = None):
+    return cls(cls.content(attr, exclude, authorities, routers), validate = validate)
+
   def __init__(self, raw_content, validate = False, default_params = True):
     """
     Parse a v3 network status document.
@@ -1270,6 +1381,26 @@ class DirectoryAuthority(Descriptor):
     'shared-rand-current-value': _parse_shared_rand_current_value,
   }
 
+  @classmethod
+  def content(cls, attr = None, exclude = (), is_vote = False):
+    attr = {} if attr is None else dict(attr)
+
+    # include mandatory 'vote-digest' if a consensus
+
+    if not is_vote and not ('vote-digest' in attr or (exclude and 'vote-digest' in exclude)):
+      attr['vote-digest'] = '0B6D1E9A300B895AA2D0B427F92917B6995C3C1C'
+
+    content = _descriptor_content(attr, exclude, AUTHORITY_HEADER)
+
+    if is_vote:
+      content += b'\n' + KeyCertificate.content()
+
+    return content
+
+  @classmethod
+  def create(cls, attr = None, exclude = (), validate = True, is_vote = False):
+    return cls(cls.content(attr, exclude, is_vote), validate = validate, is_vote = is_vote)
+
   def __init__(self, raw_content, validate = False, is_vote = False):
     """
     Parse a directory authority entry in a v3 network status document.
@@ -1444,6 +1575,10 @@ class KeyCertificate(Descriptor):
     'dir-key-certification': _parse_dir_key_certification_line,
   }
 
+  @classmethod
+  def content(cls, attr = None, exclude = ()):
+    return _descriptor_content(attr, exclude, KEY_CERTIFICATE_HEADER, KEY_CERTIFICATE_FOOTER)
+
   def __init__(self, raw_content, validate = False):
     super(KeyCertificate, self).__init__(raw_content, lazy_load = not validate)
     entries = _descriptor_components(raw_content, validate)
@@ -1583,3 +1718,17 @@ class BridgeNetworkStatusDocument(NetworkStatusDocument):
     )
 
     self.routers = dict((desc.fingerprint, desc) for desc in router_iter)
+
+
+DOC_SIG = DocumentSignature(
+  'sha1',
+  '14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4',
+  'BF112F1C6D5543CFD0A32215ACABD4197B5279AD',
+  '-----BEGIN SIGNATURE-----%s-----END SIGNATURE-----' % CRYPTO_BLOB,
+)
+
+NETWORK_STATUS_DOCUMENT_FOOTER = (
+  ('directory-footer', ''),
+  ('bandwidth-weights', None),
+  ('directory-signature', '%s %s\n%s' % (DOC_SIG.identity, DOC_SIG.key_digest, DOC_SIG.signature)),
+)
diff --git a/test/mocking.py b/test/mocking.py
index c88784a..6369598 100644
--- a/test/mocking.py
+++ b/test/mocking.py
@@ -12,12 +12,6 @@ Helper functions for creating mock objects.
   Instance Constructors
     get_message                     - stem.response.ControlMessage
     get_protocolinfo_response       - stem.response.protocolinfo.ProtocolInfoResponse
-
-    stem.descriptor.networkstatus
-      get_directory_authority        - DirectoryAuthority
-      get_key_certificate            - KeyCertificate
-      get_network_status_document_v2 - NetworkStatusDocumentV2
-      get_network_status_document_v3 - NetworkStatusDocumentV3
 """
 
 import hashlib
@@ -35,78 +29,6 @@ import stem.prereq
 import stem.response
 import stem.util.str_tools
 
-try:
-  # added in python 2.7
-  from collections import OrderedDict
-except ImportError:
-  from stem.util.ordereddict import OrderedDict
-
-CRYPTO_BLOB = """
-MIGJAoGBAJv5IIWQ+WDWYUdyA/0L8qbIkEVH/cwryZWoIaPAzINfrw1WfNZGtBmg
-skFtXhOHHqTRN4GPPrZsAIUOQGzQtGb66IQgT4tO/pj+P6QmSCCdTfhvGfgTCsC+
-WPi4Fl2qryzTb3QO5r5x7T8OsG2IBUET1bLQzmtbC560SYR49IvVAgMBAAE=
-"""
-
-DOC_SIG = stem.descriptor.networkstatus.DocumentSignature(
-  'sha1',
-  '14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4',
-  'BF112F1C6D5543CFD0A32215ACABD4197B5279AD',
-  '-----BEGIN SIGNATURE-----%s-----END SIGNATURE-----' % CRYPTO_BLOB)
-
-AUTHORITY_HEADER = (
-  ('dir-source', 'turtles 27B6B5996C426270A5C95488AA5BCEB6BCC86956 no.place.com 76.73.17.194 9030 9090'),
-  ('contact', 'Mike Perry <email>'),
-)
-
-KEY_CERTIFICATE_HEADER = (
-  ('dir-key-certificate-version', '3'),
-  ('fingerprint', '27B6B5996C426270A5C95488AA5BCEB6BCC86956'),
-  ('dir-key-published', '2011-11-28 21:51:04'),
-  ('dir-key-expires', '2012-11-28 21:51:04'),
-  ('dir-identity-key', '\n-----BEGIN RSA PUBLIC KEY-----%s-----END RSA PUBLIC KEY-----' % CRYPTO_BLOB),
-  ('dir-signing-key', '\n-----BEGIN RSA PUBLIC KEY-----%s-----END RSA PUBLIC KEY-----' % CRYPTO_BLOB),
-)
-
-KEY_CERTIFICATE_FOOTER = (
-  ('dir-key-certification', '\n-----BEGIN SIGNATURE-----%s-----END SIGNATURE-----' % CRYPTO_BLOB),
-)
-
-NETWORK_STATUS_DOCUMENT_HEADER_V2 = (
-  ('network-status-version', '2'),
-  ('dir-source', '18.244.0.114 18.244.0.114 80'),
-  ('fingerprint', '719BE45DE224B607C53707D0E2143E2D423E74CF'),
-  ('contact', 'arma at mit dot edu'),
-  ('published', '2005-12-16 00:13:46'),
-  ('dir-signing-key', '\n-----BEGIN RSA PUBLIC KEY-----%s-----END RSA PUBLIC KEY-----' % CRYPTO_BLOB),
-)
-
-NETWORK_STATUS_DOCUMENT_FOOTER_V2 = (
-  ('directory-signature', 'moria2\n-----BEGIN SIGNATURE-----%s-----END SIGNATURE-----' % CRYPTO_BLOB),
-)
-
-NETWORK_STATUS_DOCUMENT_HEADER = (
-  ('network-status-version', '3'),
-  ('vote-status', 'consensus'),
-  ('consensus-methods', None),
-  ('consensus-method', None),
-  ('published', None),
-  ('valid-after', '2012-09-02 22:00:00'),
-  ('fresh-until', '2012-09-02 22:00:00'),
-  ('valid-until', '2012-09-02 22:00:00'),
-  ('voting-delay', '300 300'),
-  ('client-versions', None),
-  ('server-versions', None),
-  ('package', None),
-  ('known-flags', 'Authority BadExit Exit Fast Guard HSDir Named Running Stable Unnamed V2Dir Valid'),
-  ('params', None),
-)
-
-NETWORK_STATUS_DOCUMENT_FOOTER = (
-  ('directory-footer', ''),
-  ('bandwidth-weights', None),
-  ('directory-signature', '%s %s\n%s' % (DOC_SIG.identity, DOC_SIG.key_digest, DOC_SIG.signature)),
-)
-
 
 def get_all_combinations(attr, include_empty = False):
   """
@@ -194,221 +116,3 @@ def get_protocolinfo_response(**attributes):
     setattr(protocolinfo_response, attr, attributes[attr])
 
   return protocolinfo_response
-
-
-def _get_descriptor_content(attr = None, exclude = (), header_template = (), footer_template = ()):
-  """
-  Constructs a minimal descriptor with the given attributes. The content we
-  provide back is of the form...
-
-  * header_template (with matching attr filled in)
-  * unused attr entries
-  * footer_template (with matching attr filled in)
-
-  So for instance...
-
-  ::
-
-    get_descriptor_content(
-      attr = {'nickname': 'caerSidi', 'contact': 'atagar'},
-      header_template = (
-        ('nickname', 'foobar'),
-        ('fingerprint', '12345'),
-      ),
-    )
-
-  ... would result in...
-
-  ::
-
-    nickname caerSidi
-    fingerprint 12345
-    contact atagar
-
-  :param dict attr: keyword/value mappings to be included in the descriptor
-  :param list exclude: mandatory keywords to exclude from the descriptor
-  :param tuple header_template: key/value pairs for mandatory fields before unrecognized content
-  :param tuple footer_template: key/value pairs for mandatory fields after unrecognized content
-
-  :returns: str with the requested descriptor content
-  """
-
-  header_content, footer_content = [], []
-  attr = {} if attr is None else dict(attr)
-
-  attr = OrderedDict(attr)  # shallow copy since we're destructive
-
-  for content, template in ((header_content, header_template),
-                            (footer_content, footer_template)):
-    for keyword, value in template:
-      if keyword in exclude:
-        continue
-      elif keyword in attr:
-        value = attr[keyword]
-        del attr[keyword]
-
-      if value is None:
-        continue
-      elif value == '':
-        content.append(keyword)
-      elif keyword == 'onion-key' or keyword == 'signing-key' or keyword == 'router-signature':
-        content.append('%s%s' % (keyword, value))
-      else:
-        content.append('%s %s' % (keyword, value))
-
-  remainder = []
-
-  for k, v in attr.items():
-    if v:
-      remainder.append('%s %s' % (k, v))
-    else:
-      remainder.append(k)
-
-  return stem.util.str_tools._to_bytes('\n'.join(header_content + remainder + footer_content))
-
-
-def get_directory_authority(attr = None, exclude = (), is_vote = False, content = False):
-  """
-  Provides the descriptor content for...
-  stem.descriptor.networkstatus.DirectoryAuthority
-
-  :param dict attr: keyword/value mappings to be included in the descriptor
-  :param list exclude: mandatory keywords to exclude from the descriptor
-  :param bool is_vote: True if this is for a vote, False if it's for a consensus
-  :param bool content: provides the str content of the descriptor rather than the class if True
-
-  :returns: DirectoryAuthority for the requested descriptor content
-  """
-
-  attr = {} if attr is None else dict(attr)
-
-  if not is_vote:
-    # entries from a consensus also have a mandatory 'vote-digest' field
-    if not ('vote-digest' in attr or (exclude and 'vote-digest' in exclude)):
-      attr['vote-digest'] = '0B6D1E9A300B895AA2D0B427F92917B6995C3C1C'
-
-  desc_content = _get_descriptor_content(attr, exclude, AUTHORITY_HEADER)
-
-  if is_vote:
-    desc_content += b'\n' + get_key_certificate(content = True)
-
-  if content:
-    return desc_content
-  else:
-    return stem.descriptor.networkstatus.DirectoryAuthority(desc_content, validate = True, is_vote = is_vote)
-
-
-def get_key_certificate(attr = None, exclude = (), content = False):
-  """
-  Provides the descriptor content for...
-  stem.descriptor.networkstatus.KeyCertificate
-
-  :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: KeyCertificate for the requested descriptor content
-  """
-
-  desc_content = _get_descriptor_content(attr, exclude, KEY_CERTIFICATE_HEADER, KEY_CERTIFICATE_FOOTER)
-
-  if content:
-    return desc_content
-  else:
-    return stem.descriptor.networkstatus.KeyCertificate(desc_content, validate = True)
-
-
-def get_network_status_document_v2(attr = None, exclude = (), content = False):
-  """
-  Provides the descriptor content for...
-  stem.descriptor.networkstatus.NetworkStatusDocumentV2
-
-  :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: NetworkStatusDocumentV2 for the requested descriptor content
-  """
-
-  desc_content = _get_descriptor_content(attr, exclude, NETWORK_STATUS_DOCUMENT_HEADER_V2, NETWORK_STATUS_DOCUMENT_FOOTER_V2)
-
-  if content:
-    return desc_content
-  else:
-    return stem.descriptor.networkstatus.NetworkStatusDocumentV2(desc_content, validate = True)
-
-
-def get_network_status_document_v3(attr = None, exclude = (), authorities = None, routers = None, content = False):
-  """
-  Provides the descriptor content for...
-  stem.descriptor.networkstatus.NetworkStatusDocumentV3
-
-  :param dict attr: keyword/value mappings to be included in the descriptor
-  :param list exclude: mandatory keywords to exclude from the descriptor
-  :param list authorities: directory authorities to include in the document
-  :param list routers: router status entries to include in the document
-  :param bool content: provides the str content of the descriptor rather than the class if True
-
-  :returns: NetworkStatusDocumentV3 for the requested descriptor content
-  """
-
-  attr = {} if attr is None else dict(attr)
-
-  # add defaults only found in a vote, consensus, or microdescriptor
-
-  if attr.get('vote-status') == 'vote':
-    extra_defaults = {
-      'consensus-methods': '1 9',
-      'published': '2012-09-02 22:00:00',
-    }
-
-    # votes need an authority to be valid
-
-    if authorities is None:
-      authorities = [get_directory_authority(is_vote = True)]
-  else:
-    extra_defaults = {
-      'consensus-method': '9',
-    }
-
-  for k, v in extra_defaults.items():
-    if exclude and k in exclude:
-      continue  # explicitly excluding this field
-    elif k not in attr:
-      attr[k] = v
-
-  desc_content = _get_descriptor_content(attr, exclude, NETWORK_STATUS_DOCUMENT_HEADER, NETWORK_STATUS_DOCUMENT_FOOTER)
-
-  # inject the authorities and/or routers between the header and footer
-  if authorities:
-    if b'directory-footer' in desc_content:
-      footer_div = desc_content.find(b'\ndirectory-footer') + 1
-    elif b'directory-signature' in desc_content:
-      footer_div = desc_content.find(b'\ndirectory-signature') + 1
-    else:
-      if routers:
-        desc_content += b'\n'
-
-      footer_div = len(desc_content) + 1
-
-    authority_content = stem.util.str_tools._to_bytes('\n'.join([str(a) for a in authorities]) + '\n')
-    desc_content = desc_content[:footer_div] + authority_content + desc_content[footer_div:]
-
-  if routers:
-    if b'directory-footer' in desc_content:
-      footer_div = desc_content.find(b'\ndirectory-footer') + 1
-    elif b'directory-signature' in desc_content:
-      footer_div = desc_content.find(b'\ndirectory-signature') + 1
-    else:
-      if routers:
-        desc_content += b'\n'
-
-      footer_div = len(desc_content) + 1
-
-    router_content = stem.util.str_tools._to_bytes('\n'.join([str(r) for r in routers]) + '\n')
-    desc_content = desc_content[:footer_div] + router_content + desc_content[footer_div:]
-
-  if content:
-    return desc_content
-  else:
-    return stem.descriptor.networkstatus.NetworkStatusDocumentV3(desc_content, validate = True)
diff --git a/test/unit/descriptor/networkstatus/directory_authority.py b/test/unit/descriptor/networkstatus/directory_authority.py
index c1dc319..a80cb44 100644
--- a/test/unit/descriptor/networkstatus/directory_authority.py
+++ b/test/unit/descriptor/networkstatus/directory_authority.py
@@ -4,8 +4,11 @@ Unit tests for the DirectoryAuthority of stem.descriptor.networkstatus.
 
 import unittest
 
-from stem.descriptor.networkstatus import DirectoryAuthority
-from test.mocking import get_directory_authority, get_key_certificate, AUTHORITY_HEADER
+from stem.descriptor.networkstatus import (
+  AUTHORITY_HEADER,
+  DirectoryAuthority,
+  KeyCertificate,
+)
 
 
 class TestDirectoryAuthority(unittest.TestCase):
@@ -14,7 +17,7 @@ class TestDirectoryAuthority(unittest.TestCase):
     Parses a minimal directory authority for a consensus.
     """
 
-    authority = get_directory_authority()
+    authority = DirectoryAuthority.create()
 
     self.assertEqual('turtles', authority.nickname)
     self.assertEqual('27B6B5996C426270A5C95488AA5BCEB6BCC86956', authority.fingerprint)
@@ -34,7 +37,7 @@ class TestDirectoryAuthority(unittest.TestCase):
     Parses a minimal directory authority for a vote.
     """
 
-    authority = get_directory_authority(is_vote = True)
+    authority = DirectoryAuthority.create(is_vote = True)
 
     self.assertEqual('turtles', authority.nickname)
     self.assertEqual('27B6B5996C426270A5C95488AA5BCEB6BCC86956', authority.fingerprint)
@@ -46,7 +49,7 @@ class TestDirectoryAuthority(unittest.TestCase):
     self.assertEqual('Mike Perry <email>', authority.contact)
     self.assertEqual(None, authority.vote_digest)
     self.assertEqual(None, authority.legacy_dir_key)
-    self.assertEqual(get_key_certificate(), authority.key_certificate)
+    self.assertEqual(KeyCertificate.create(), authority.key_certificate)
     self.assertEqual([], authority.get_unrecognized_lines())
 
   def test_unrecognized_line(self):
@@ -54,7 +57,7 @@ class TestDirectoryAuthority(unittest.TestCase):
     Includes unrecognized content in the descriptor.
     """
 
-    authority = get_directory_authority({'pepperjack': 'is oh so tasty!'})
+    authority = DirectoryAuthority.create({'pepperjack': 'is oh so tasty!'})
     self.assertEqual(['pepperjack is oh so tasty!'], authority.get_unrecognized_lines())
 
   def test_legacy_authority(self):
@@ -83,7 +86,7 @@ class TestDirectoryAuthority(unittest.TestCase):
     Includes a non-mandatory field before the 'dir-source' line.
     """
 
-    content = b'ho-hum 567\n' + get_directory_authority(content = True)
+    content = b'ho-hum 567\n' + DirectoryAuthority.content()
     self.assertRaises(ValueError, DirectoryAuthority, content, True)
 
     authority = DirectoryAuthority(content, False)
@@ -96,7 +99,7 @@ class TestDirectoryAuthority(unittest.TestCase):
     """
 
     for excluded_field in ('dir-source', 'contact'):
-      content = get_directory_authority(exclude = (excluded_field,), content = True)
+      content = DirectoryAuthority.content(exclude = (excluded_field,))
       self.assertRaises(ValueError, DirectoryAuthority, content, True)
 
       authority = DirectoryAuthority(content, False)
@@ -111,7 +114,7 @@ class TestDirectoryAuthority(unittest.TestCase):
     Includes blank lines, which should be ignored.
     """
 
-    authority = get_directory_authority({'dir-source': AUTHORITY_HEADER[0][1] + '\n\n\n'})
+    authority = DirectoryAuthority.create({'dir-source': AUTHORITY_HEADER[0][1] + '\n\n\n'})
     self.assertEqual('Mike Perry <email>', authority.contact)
 
   def test_duplicate_lines(self):
@@ -119,7 +122,7 @@ class TestDirectoryAuthority(unittest.TestCase):
     Duplicates linesin the entry.
     """
 
-    lines = get_directory_authority(content = True).split(b'\n')
+    lines = DirectoryAuthority.content().split(b'\n')
 
     for index, duplicate_line in enumerate(lines):
       content = b'\n'.join(lines[:index] + [duplicate_line] + lines[index:])
@@ -135,7 +138,7 @@ class TestDirectoryAuthority(unittest.TestCase):
 
     for missing_value in AUTHORITY_HEADER[0][1].split(' '):
       dir_source = AUTHORITY_HEADER[0][1].replace(missing_value, '').replace('  ', ' ')
-      content = get_directory_authority({'dir-source': dir_source}, content = True)
+      content = DirectoryAuthority.content({'dir-source': dir_source})
       self.assertRaises(ValueError, DirectoryAuthority, content, True)
 
       authority = DirectoryAuthority(content, False)
@@ -160,7 +163,7 @@ class TestDirectoryAuthority(unittest.TestCase):
 
     for value in test_values:
       dir_source = AUTHORITY_HEADER[0][1].replace('27B6B5996C426270A5C95488AA5BCEB6BCC86956', value)
-      content = get_directory_authority({'dir-source': dir_source}, content = True)
+      content = DirectoryAuthority.content({'dir-source': dir_source})
       self.assertRaises(ValueError, DirectoryAuthority, content, True)
 
       authority = DirectoryAuthority(content, False)
@@ -182,7 +185,7 @@ class TestDirectoryAuthority(unittest.TestCase):
 
     for value in test_values:
       dir_source = AUTHORITY_HEADER[0][1].replace('76.73.17.194', value)
-      content = get_directory_authority({'dir-source': dir_source}, content = True)
+      content = DirectoryAuthority.content({'dir-source': dir_source})
       self.assertRaises(ValueError, DirectoryAuthority, content, True)
 
       authority = DirectoryAuthority(content, False)
@@ -214,7 +217,7 @@ class TestDirectoryAuthority(unittest.TestCase):
           if include_dir_port:
             dir_source = dir_source.replace('9030', value)
 
-          content = get_directory_authority({'dir-source': dir_source}, content = True)
+          content = DirectoryAuthority.content({'dir-source': dir_source})
           self.assertRaises(ValueError, DirectoryAuthority, content, True)
 
           authority = DirectoryAuthority(content, False)
@@ -228,11 +231,11 @@ class TestDirectoryAuthority(unittest.TestCase):
     """
 
     test_value = '65968CCB6BECB5AA88459C5A072624C6995B6B72'
-    authority = get_directory_authority({'legacy-dir-key': test_value}, is_vote = True)
+    authority = DirectoryAuthority.create({'legacy-dir-key': test_value}, is_vote = True)
     self.assertEqual(test_value, authority.legacy_dir_key)
 
     # check that we'll fail if legacy-dir-key appears in a consensus
-    content = get_directory_authority({'legacy-dir-key': test_value}, content = True)
+    content = DirectoryAuthority.content({'legacy-dir-key': test_value})
     self.assertRaises(ValueError, DirectoryAuthority, content, True)
 
     test_values = (
@@ -242,7 +245,7 @@ class TestDirectoryAuthority(unittest.TestCase):
     )
 
     for value in test_values:
-      content = get_directory_authority({'legacy-dir-key': value}, content = True)
+      content = DirectoryAuthority.content({'legacy-dir-key': value})
       self.assertRaises(ValueError, DirectoryAuthority, content, True)
 
       authority = DirectoryAuthority(content, False)
@@ -253,17 +256,17 @@ class TestDirectoryAuthority(unittest.TestCase):
     Includes or exclude a key certificate from the directory entry.
     """
 
-    key_cert = get_key_certificate(content = True)
+    key_cert = KeyCertificate.content()
 
     # include a key cert with a consensus
-    content = get_directory_authority(content = True) + b'\n' + key_cert
+    content = DirectoryAuthority.content() + b'\n' + key_cert
     self.assertRaises(ValueError, DirectoryAuthority, content, True)
 
     authority = DirectoryAuthority(content, False)
     self.assertEqual('turtles', authority.nickname)
 
     # exclude  key cert from a vote
-    content = get_directory_authority(content = True, is_vote = True).replace(b'\n' + key_cert, b'')
+    content = DirectoryAuthority.content(is_vote = True).replace(b'\n' + key_cert, b'')
     self.assertRaises(ValueError, DirectoryAuthority, content, True, True)
 
     authority = DirectoryAuthority(content, False, True)
diff --git a/test/unit/descriptor/networkstatus/document_v2.py b/test/unit/descriptor/networkstatus/document_v2.py
index 54cbccc..7b6fdb1 100644
--- a/test/unit/descriptor/networkstatus/document_v2.py
+++ b/test/unit/descriptor/networkstatus/document_v2.py
@@ -5,9 +5,11 @@ Unit tests for the NetworkStatusDocumentV2 of stem.descriptor.networkstatus.
 import datetime
 import unittest
 
-import stem.descriptor
-
-from test.mocking import get_network_status_document_v2, NETWORK_STATUS_DOCUMENT_HEADER_V2, NETWORK_STATUS_DOCUMENT_FOOTER_V2
+from stem.descriptor.networkstatus import (
+  NETWORK_STATUS_DOCUMENT_HEADER_V2,
+  NETWORK_STATUS_DOCUMENT_FOOTER_V2,
+  NetworkStatusDocumentV2,
+)
 
 from test.unit.descriptor import get_resource
 
@@ -32,7 +34,7 @@ TpQQk3nNQF8z6UIvdlvP+DnJV4izWVkQEZgUZgIVM0E=
 
     with open(get_resource('cached-consensus-v2'), 'rb') as descriptor_file:
       descriptor_file.readline()  # strip header
-      document = stem.descriptor.networkstatus.NetworkStatusDocumentV2(descriptor_file.read())
+      document = NetworkStatusDocumentV2(descriptor_file.read())
 
       self.assertEqual(2, document.version)
       self.assertEqual('18.244.0.114', document.hostname)
@@ -93,7 +95,7 @@ TpQQk3nNQF8z6UIvdlvP+DnJV4izWVkQEZgUZgIVM0E=
     Parses a minimal v2 network status document.
     """
 
-    document = get_network_status_document_v2()
+    document = NetworkStatusDocumentV2.create()
 
     self.assertEqual({}, document.routers)
     self.assertEqual(2, document.version)
diff --git a/test/unit/descriptor/networkstatus/document_v3.py b/test/unit/descriptor/networkstatus/document_v3.py
index d6ea34e..4bfdc9e 100644
--- a/test/unit/descriptor/networkstatus/document_v3.py
+++ b/test/unit/descriptor/networkstatus/document_v3.py
@@ -16,6 +16,8 @@ from stem.util import str_type
 from stem.descriptor.networkstatus import (
   HEADER_STATUS_DOCUMENT_FIELDS,
   FOOTER_STATUS_DOCUMENT_FIELDS,
+  NETWORK_STATUS_DOCUMENT_FOOTER,
+  DOC_SIG,
   DEFAULT_PARAMS,
   PackageVersion,
   DirectoryAuthority,
@@ -28,13 +30,6 @@ from stem.descriptor.router_status_entry import (
   RouterStatusEntryMicroV3,
 )
 
-from test.mocking import (
-  get_directory_authority,
-  get_network_status_document_v3,
-  DOC_SIG,
-  NETWORK_STATUS_DOCUMENT_FOOTER,
-)
-
 from test.unit.descriptor import get_resource
 
 try:
@@ -309,7 +304,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     Parses a minimal network status document.
     """
 
-    document = get_network_status_document_v3()
+    document = NetworkStatusDocumentV3.create()
 
     expected_known_flags = [
       Flag.AUTHORITY, Flag.BADEXIT, Flag.EXIT,
@@ -356,7 +351,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     Parses a minimal network status document.
     """
 
-    document = get_network_status_document_v3({'vote-status': 'vote'})
+    document = NetworkStatusDocumentV3.create({'vote-status': 'vote'})
 
     expected_known_flags = [
       Flag.AUTHORITY, Flag.BADEXIT, Flag.EXIT,
@@ -400,7 +395,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
 
     entry1 = RouterStatusEntryV3.create({'s': 'Fast'})
     entry2 = RouterStatusEntryV3.create({'s': 'Valid'})
-    content = get_network_status_document_v3(routers = (entry1, entry2), content = True)
+    content = NetworkStatusDocumentV3.content(routers = (entry1, entry2))
 
     # first example: parsing via the NetworkStatusDocumentV3 constructor
 
@@ -432,7 +427,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
       's': 'Valid',
     })
 
-    content = get_network_status_document_v3(routers = (entry1, entry2), content = True)
+    content = NetworkStatusDocumentV3.content(routers = (entry1, entry2))
 
     descriptors = list(stem.descriptor.parse_file(io.BytesIO(content), 'network-status-consensus-3 1.0', document_handler = stem.descriptor.DocumentHandler.DOCUMENT))
     self.assertEqual(1, len(descriptors))
@@ -451,12 +446,12 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
 
     entry1 = RouterStatusEntryV3.create({'s': 'Fast'})
     entry2 = RouterStatusEntryV3.create({'s': 'Valid'})
-    content = get_network_status_document_v3(routers = (entry1, entry2), content = True)
+    content = NetworkStatusDocumentV3.content(routers = (entry1, entry2))
 
     # the document that the entries refer to should actually be the minimal
     # descriptor (ie, without the entries)
 
-    expected_document = get_network_status_document_v3()
+    expected_document = NetworkStatusDocumentV3.create()
 
     descriptor_file = io.BytesIO(content)
     entries = list(_parse_file(descriptor_file))
@@ -477,7 +472,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
       for entries in (HEADER_STATUS_DOCUMENT_FIELDS, FOOTER_STATUS_DOCUMENT_FIELDS):
         for field, in_votes, in_consensus, is_mandatory in entries:
           if is_mandatory and field != 'vote-status' and ((is_consensus and in_consensus) or (is_vote and in_votes)):
-            content = get_network_status_document_v3(attr, exclude = (field,), content = True)
+            content = NetworkStatusDocumentV3.content(attr, exclude = (field,))
             self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
             NetworkStatusDocumentV3(content, False)  # constructs without validation
 
@@ -486,7 +481,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     Includes unrecognized content in the document.
     """
 
-    document = get_network_status_document_v3({'pepperjack': 'is oh so tasty!'})
+    document = NetworkStatusDocumentV3.create({'pepperjack': 'is oh so tasty!'})
     self.assertEqual(['pepperjack is oh so tasty!'], document.get_unrecognized_lines())
 
   def test_duplicate_fields(self):
@@ -497,7 +492,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
 
     for is_consensus in (True, False):
       attr = {'vote-status': 'consensus'} if is_consensus else {'vote-status': 'vote'}
-      lines = get_network_status_document_v3(attr, content = True).split(b'\n')
+      lines = NetworkStatusDocumentV3.content(attr).split(b'\n')
 
       for index, line in enumerate(lines):
         if not is_consensus and lines[index].startswith(b'dir-source'):
@@ -525,17 +520,17 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     different document version with the v3 parser.
     """
 
-    document = get_network_status_document_v3({'network-status-version': '3'})
+    document = NetworkStatusDocumentV3.create({'network-status-version': '3'})
     self.assertEqual(3, document.version)
     self.assertEqual(None, document.version_flavor)
     self.assertEqual(False, document.is_microdescriptor)
 
-    document = get_network_status_document_v3({'network-status-version': '3 microdesc'})
+    document = NetworkStatusDocumentV3.create({'network-status-version': '3 microdesc'})
     self.assertEqual(3, document.version)
     self.assertEqual('microdesc', document.version_flavor)
     self.assertEqual(True, document.is_microdescriptor)
 
-    content = get_network_status_document_v3({'network-status-version': '4'}, content = True)
+    content = NetworkStatusDocumentV3.content({'network-status-version': '4'})
     self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
 
     document = NetworkStatusDocumentV3(content, False)
@@ -548,11 +543,11 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     Parses the vote-status field.
     """
 
-    document = get_network_status_document_v3({'vote-status': 'vote'})
+    document = NetworkStatusDocumentV3.create({'vote-status': 'vote'})
     self.assertEqual(False, document.is_consensus)
     self.assertEqual(True, document.is_vote)
 
-    content = get_network_status_document_v3({'vote-status': 'consensus'}, content = True)
+    content = NetworkStatusDocumentV3.content({'vote-status': 'consensus'})
     document = NetworkStatusDocumentV3(content)
     self.assertEqual(True, document.is_consensus)
     self.assertEqual(False, document.is_vote)
@@ -564,7 +559,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     )
 
     for test_value in test_values:
-      content = get_network_status_document_v3({'vote-status': test_value}, content = True)
+      content = NetworkStatusDocumentV3.content({'vote-status': test_value})
       self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
 
       document = NetworkStatusDocumentV3(content, False)
@@ -576,11 +571,11 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     Parses the consensus-methods field.
     """
 
-    document = get_network_status_document_v3({'vote-status': 'vote', 'consensus-methods': '12 3 1 780'})
+    document = NetworkStatusDocumentV3.create({'vote-status': 'vote', 'consensus-methods': '12 3 1 780'})
     self.assertEqual([12, 3, 1, 780], document.consensus_methods)
 
     # check that we default to including consensus-method 1
-    content = get_network_status_document_v3({'vote-status': 'vote'}, ('consensus-methods',), content = True)
+    content = NetworkStatusDocumentV3.content({'vote-status': 'vote'}, ('consensus-methods',))
     document = NetworkStatusDocumentV3(content, False)
     self.assertEqual([1], document.consensus_methods)
     self.assertEqual(None, document.consensus_method)
@@ -594,7 +589,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     )
 
     for test_value in test_values:
-      content = get_network_status_document_v3({'vote-status': 'vote', 'consensus-methods': test_value}, content = True)
+      content = NetworkStatusDocumentV3.content({'vote-status': 'vote', 'consensus-methods': test_value})
       self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
 
       expected_value = [2, 3, 4] if test_value == '2 3 4' else [1]
@@ -607,11 +602,11 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     Parses the consensus-method field.
     """
 
-    document = get_network_status_document_v3({'consensus-method': '12'})
+    document = NetworkStatusDocumentV3.create({'consensus-method': '12'})
     self.assertEqual(12, document.consensus_method)
 
     # check that we default to being consensus-method 1
-    content = get_network_status_document_v3(exclude = ('consensus-method',), content = True)
+    content = NetworkStatusDocumentV3.content(exclude = ('consensus-method',))
     document = NetworkStatusDocumentV3(content, False)
     self.assertEqual(1, document.consensus_method)
     self.assertEqual([], document.consensus_methods)
@@ -625,7 +620,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     )
 
     for test_value in test_values:
-      content = get_network_status_document_v3({'consensus-method': test_value}, content = True)
+      content = NetworkStatusDocumentV3.content({'consensus-method': test_value})
       self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
 
       document = NetworkStatusDocumentV3(content, False)
@@ -640,7 +635,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     expected = datetime.datetime(2012, 9, 2, 22, 0, 0)
     test_value = '2012-09-02 22:00:00'
 
-    document = get_network_status_document_v3({
+    document = NetworkStatusDocumentV3.create({
       'vote-status': 'vote',
       'published': test_value,
       'valid-after': test_value,
@@ -662,7 +657,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     )
 
     for test_value in test_values:
-      content = get_network_status_document_v3({'vote-status': 'vote', 'published': test_value}, content = True)
+      content = NetworkStatusDocumentV3.content({'vote-status': 'vote', 'published': test_value})
       self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
 
       document = NetworkStatusDocumentV3(content, False)
@@ -673,7 +668,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     Parses the voting-delay field.
     """
 
-    document = get_network_status_document_v3({'voting-delay': '12 345'})
+    document = NetworkStatusDocumentV3.create({'voting-delay': '12 345'})
     self.assertEqual(12, document.vote_delay)
     self.assertEqual(345, document.dist_delay)
 
@@ -686,7 +681,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     )
 
     for test_value in test_values:
-      content = get_network_status_document_v3({'voting-delay': test_value}, content = True)
+      content = NetworkStatusDocumentV3.content({'voting-delay': test_value})
       self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
 
       document = NetworkStatusDocumentV3(content, False)
@@ -702,7 +697,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     expected = [stem.version.Version('1.2.3.4'), stem.version.Version('56.789.12.34-alpha')]
     test_value = '1.2.3.4,56.789.12.34-alpha'
 
-    document = get_network_status_document_v3({'client-versions': test_value, 'server-versions': test_value})
+    document = NetworkStatusDocumentV3.create({'client-versions': test_value, 'server-versions': test_value})
     self.assertEqual(expected, document.client_versions)
     self.assertEqual(expected, document.server_versions)
 
@@ -717,7 +712,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
       attr = field.replace('-', '_')
 
       for test_value in test_values:
-        content = get_network_status_document_v3({field: test_value}, content = True)
+        content = NetworkStatusDocumentV3.content({field: test_value})
         self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
 
         document = NetworkStatusDocumentV3(content, False)
@@ -740,7 +735,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     )
 
     for test_value, expected_value in test_values:
-      document = get_network_status_document_v3({'package': '\npackage '.join(test_value)})
+      document = NetworkStatusDocumentV3.create({'package': '\npackage '.join(test_value)})
       self.assertEqual(expected_value, document.packages)
 
     test_values = (
@@ -754,7 +749,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     )
 
     for test_value in test_values:
-      content = get_network_status_document_v3({'package': test_value}, content = True)
+      content = NetworkStatusDocumentV3.content({'package': test_value})
       self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
 
       document = NetworkStatusDocumentV3(content, False)
@@ -777,7 +772,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     )
 
     for test_value, expected_value in test_values:
-      document = get_network_status_document_v3({'known-flags': test_value})
+      document = NetworkStatusDocumentV3.create({'known-flags': test_value})
       self.assertEqual(expected_value, document.known_flags)
 
   def test_flag_thresholds(self):
@@ -793,7 +788,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     )
 
     for test_value, expected_value in test_values:
-      document = get_network_status_document_v3({'vote-status': 'vote', 'flag-thresholds': test_value})
+      document = NetworkStatusDocumentV3.create({'vote-status': 'vote', 'flag-thresholds': test_value})
       self.assertEqual(expected_value, document.flag_thresholds)
 
     # parses a full entry found in an actual vote
@@ -811,7 +806,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
       str_type('enough-mtbf'): 1,
     }
 
-    document = get_network_status_document_v3({'vote-status': 'vote', 'flag-thresholds': full_line})
+    document = NetworkStatusDocumentV3.create({'vote-status': 'vote', 'flag-thresholds': full_line})
     self.assertEqual(expected_value, document.flag_thresholds)
 
     test_values = (
@@ -822,7 +817,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     )
 
     for test_value in test_values:
-      content = get_network_status_document_v3({'vote-status': 'vote', 'flag-thresholds': test_value}, content = True)
+      content = NetworkStatusDocumentV3.content({'vote-status': 'vote', 'flag-thresholds': test_value})
       self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
 
       document = NetworkStatusDocumentV3(content, False)
@@ -833,7 +828,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     Parses the parameters attributes.
     """
 
-    document = get_network_status_document_v3(OrderedDict([
+    document = NetworkStatusDocumentV3.create(OrderedDict([
       ('vote-status', 'vote'),
       ('recommended-client-protocols', 'HSDir=1 HSIntro=3'),
       ('recommended-relay-protocols', 'Cons=1 Desc=1'),
@@ -851,17 +846,17 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     General testing for the 'params' line, exercising the happy cases.
     """
 
-    document = get_network_status_document_v3({'params': 'CircuitPriorityHalflifeMsec=30000 bwauthpid=1 unrecognized=-122'})
+    document = NetworkStatusDocumentV3.create({'params': 'CircuitPriorityHalflifeMsec=30000 bwauthpid=1 unrecognized=-122'})
     self.assertEqual(30000, document.params['CircuitPriorityHalflifeMsec'])
     self.assertEqual(1, document.params['bwauthpid'])
     self.assertEqual(-122, document.params['unrecognized'])
 
     # empty params line
-    content = get_network_status_document_v3({'params': ''}, content = True)
+    content = NetworkStatusDocumentV3.content({'params': ''})
     document = NetworkStatusDocumentV3(content, default_params = True)
     self.assertEqual(DEFAULT_PARAMS, document.params)
 
-    content = get_network_status_document_v3({'params': ''}, content = True)
+    content = NetworkStatusDocumentV3.content({'params': ''})
     document = NetworkStatusDocumentV3(content, default_params = False)
     self.assertEqual({}, document.params)
 
@@ -878,7 +873,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     )
 
     for test_value in test_values:
-      content = get_network_status_document_v3({'params': test_value}, content = True)
+      content = NetworkStatusDocumentV3.content({'params': test_value})
       self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
 
       document = NetworkStatusDocumentV3(content, False)
@@ -907,7 +902,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     )
 
     for test_value, expected_value, is_ok in test_values:
-      content = get_network_status_document_v3({'params': test_value}, content = True)
+      content = NetworkStatusDocumentV3.content({'params': test_value})
 
       if is_ok:
         document = NetworkStatusDocumentV3(content, default_params = False)
@@ -922,7 +917,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     Check that the 'params' line is rejected if out of order.
     """
 
-    content = get_network_status_document_v3({'params': 'unrecognized=-122 bwauthpid=1'}, content = True)
+    content = NetworkStatusDocumentV3.content({'params': 'unrecognized=-122 bwauthpid=1'})
     self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
 
     document = NetworkStatusDocumentV3(content, False, default_params = False)
@@ -934,7 +929,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     introduced.
     """
 
-    content = get_network_status_document_v3({'consensus-method': '8'}, content = True)
+    content = NetworkStatusDocumentV3.content({'consensus-method': '8'})
     self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
 
     document = NetworkStatusDocumentV3(content, False)
@@ -943,7 +938,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
 
     # excludes a footer from a version that shouldn't have it
 
-    document = get_network_status_document_v3({'consensus-method': '8'}, ('directory-footer', 'directory-signature'))
+    document = NetworkStatusDocumentV3.create({'consensus-method': '8'}, ('directory-footer', 'directory-signature'))
     self.assertEqual([], document.signatures)
     self.assertEqual([], document.get_unrecognized_lines())
 
@@ -952,13 +947,13 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     #
     # https://trac.torproject.org/7932
 
-    document = get_network_status_document_v3(
+    document = NetworkStatusDocumentV3.create(
       {
         'vote-status': 'vote',
         'consensus-methods': '1 8',
       },
       exclude = ('directory-footer',),
-      authorities = (get_directory_authority(is_vote = True),)
+      authorities = (DirectoryAuthority.create(is_vote = True),)
     )
 
     self.assertEqual([DOC_SIG], document.signatures)
@@ -969,7 +964,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     Tries to parse a descriptor with content on the 'directory-footer' line.
     """
 
-    content = get_network_status_document_v3({'directory-footer': 'blarg'}, content = True)
+    content = NetworkStatusDocumentV3.content({'directory-footer': 'blarg'})
     self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
 
     document = NetworkStatusDocumentV3(content, False)
@@ -989,7 +984,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
       weight_entries.append('%s=%i' % (key, index - 5))
       expected[key] = index - 5
 
-    document = get_network_status_document_v3({'bandwidth-weights': ' '.join(weight_entries)})
+    document = NetworkStatusDocumentV3.create({'bandwidth-weights': ' '.join(weight_entries)})
     self.assertEqual(expected, document.bandwidth_weights)
 
   def test_bandwidth_wights_malformed(self):
@@ -1008,7 +1003,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
 
     for test_value in test_values:
       weight_entry = base_weight_entry.replace('Wbe=5', test_value)
-      content = get_network_status_document_v3({'bandwidth-weights': weight_entry}, content = True)
+      content = NetworkStatusDocumentV3.content({'bandwidth-weights': weight_entry})
 
       self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
       document = NetworkStatusDocumentV3(content, False)
@@ -1021,7 +1016,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
 
     weight_entry = ' '.join(['%s=5' % e for e in reversed(BANDWIDTH_WEIGHT_ENTRIES)])
 
-    content = get_network_status_document_v3({'bandwidth-weights': weight_entry}, content = True)
+    content = NetworkStatusDocumentV3.content({'bandwidth-weights': weight_entry})
     self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
 
     document = NetworkStatusDocumentV3(content, False)
@@ -1035,7 +1030,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     weight_entry = ' '.join(['%s=5' % e for e in BANDWIDTH_WEIGHT_ENTRIES])
     expected = dict([(e, 5) for e in BANDWIDTH_WEIGHT_ENTRIES])
 
-    content = get_network_status_document_v3({'vote-status': 'vote', 'bandwidth-weights': weight_entry}, content = True)
+    content = NetworkStatusDocumentV3.content({'vote-status': 'vote', 'bandwidth-weights': weight_entry})
     self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
 
     document = NetworkStatusDocumentV3(content, False)
@@ -1049,7 +1044,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
 
     # including the signature method field should work
 
-    document = get_network_status_document_v3({
+    document = NetworkStatusDocumentV3.create({
       'network-status-version': '3 microdesc',
       'directory-signature': 'sha256 ' + NETWORK_STATUS_DOCUMENT_FOOTER[2][1],
     })
@@ -1058,7 +1053,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
 
     # excluding the method should default to sha1
 
-    document = get_network_status_document_v3({
+    document = NetworkStatusDocumentV3.create({
       'network-status-version': '3 microdesc',
     })
 
@@ -1080,7 +1075,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
         attrs = [DOC_SIG.identity, DOC_SIG.key_digest, DOC_SIG.signature]
         attrs[test_attr] = test_value
 
-        content = get_network_status_document_v3({'directory-signature': '%s %s\n%s' % tuple(attrs)}, content = True)
+        content = NetworkStatusDocumentV3.content({'directory-signature': '%s %s\n%s' % tuple(attrs)})
         self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
         NetworkStatusDocumentV3(content, False)  # checks that it's still parsable without validation
 
@@ -1097,7 +1092,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
       's': 'Valid',
     })
 
-    document = get_network_status_document_v3(routers = (entry1, entry2))
+    document = NetworkStatusDocumentV3.create(routers = (entry1, entry2))
 
     self.assertTrue(entry1 in document.routers.values())
     self.assertTrue(entry2 in document.routers.values())
@@ -1105,7 +1100,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     # try with an invalid RouterStatusEntry
 
     entry3 = RouterStatusEntryV3(RouterStatusEntryV3.content({'r': 'ugabuga'}), False)
-    content = get_network_status_document_v3(routers = (entry3,), content = True)
+    content = NetworkStatusDocumentV3.content(routers = (entry3,))
 
     self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
     document = NetworkStatusDocumentV3(content, False)
@@ -1113,7 +1108,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
 
     # try including with a microdescriptor consensus
 
-    content = get_network_status_document_v3({'network-status-version': '3 microdesc'}, routers = (entry1,), content = True)
+    content = NetworkStatusDocumentV3.content({'network-status-version': '3 microdesc'}, routers = (entry1,))
     self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
 
     document = NetworkStatusDocumentV3(content, False)
@@ -1131,7 +1126,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
       's': 'Valid',
     })
 
-    document = get_network_status_document_v3({'network-status-version': '3 microdesc'}, routers = (entry1, entry2))
+    document = NetworkStatusDocumentV3.create({'network-status-version': '3 microdesc'}, routers = (entry1, entry2))
 
     self.assertTrue(entry1 in document.routers.values())
     self.assertTrue(entry2 in document.routers.values())
@@ -1140,7 +1135,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
 
     entry3 = RouterStatusEntryMicroV3(RouterStatusEntryMicroV3.content({'r': 'ugabuga'}), False)
 
-    content = get_network_status_document_v3({'network-status-version': '3 microdesc'}, routers = (entry3,), content = True)
+    content = NetworkStatusDocumentV3.content({'network-status-version': '3 microdesc'}, routers = (entry3,))
     self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
 
     document = NetworkStatusDocumentV3(content, False)
@@ -1148,7 +1143,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
 
     # try including microdescriptor entry in a normal consensus
 
-    content = get_network_status_document_v3(routers = (entry1,), content = True)
+    content = NetworkStatusDocumentV3.content(routers = (entry1,))
     self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
 
     document = NetworkStatusDocumentV3(content, False)
@@ -1161,11 +1156,11 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
 
     for is_document_vote in (False, True):
       for is_authorities_vote in (False, True):
-        authority1 = get_directory_authority({'contact': 'doctor jekyll'}, is_vote = is_authorities_vote)
-        authority2 = get_directory_authority({'contact': 'mister hyde'}, is_vote = is_authorities_vote)
+        authority1 = DirectoryAuthority.create({'contact': 'doctor jekyll'}, is_vote = is_authorities_vote)
+        authority2 = DirectoryAuthority.create({'contact': 'mister hyde'}, is_vote = is_authorities_vote)
 
         vote_status = 'vote' if is_document_vote else 'consensus'
-        content = get_network_status_document_v3({'vote-status': vote_status}, authorities = (authority1, authority2), content = True)
+        content = NetworkStatusDocumentV3.content({'vote-status': vote_status}, authorities = (authority1, authority2))
 
         if is_document_vote == is_authorities_vote:
           if is_document_vote:
@@ -1191,7 +1186,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     COMMITMENT_1 = '1 sha3-256 4CAEC248004A0DC6CE86EBD5F608C9B05500C70C AAAAAFd4/kAaklgYr4ijHZjXXy/B354jQfL31BFhhE46nuOHSPITyw== AAAAAFd4/kCpZeis3yJyr//rz8hXCeeAhHa4k3lAcAiMJd1vEMTPuw=='
     COMMITMENT_2 = '1 sha3-256 598536A9DD4E6C0F18B4AD4B88C7875A0A29BA31 AAAAAFd4/kC7S920awC5/HF5RfX4fKZtYqjm6qMh9G91AcjZm13DQQ=='
 
-    authority = get_directory_authority(OrderedDict([
+    authority = DirectoryAuthority.create(OrderedDict([
       ('shared-rand-participate', ''),
       ('shared-rand-commit', '%s\nshared-rand-commit %s' % (COMMITMENT_1, COMMITMENT_2)),
       ('shared-rand-previous-value', '8 hAQLxyt0U3gu7QR2owixRCbIltcyPrz3B0YBfUshOkE='),
@@ -1237,7 +1232,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     ]
 
     for attr, expected_exception in test_values:
-      content = get_directory_authority(attr, content = True)
+      content = DirectoryAuthority.content(attr)
       self.assertRaisesRegexp(ValueError, re.escape(expected_exception), DirectoryAuthority, content, True)
 
       authority = DirectoryAuthority(content, False)
@@ -1254,11 +1249,11 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
 
     legacy_content = 'dir-source gabelmoo-legacy 81349FC1F2DBA2C2C11B45CB9706637D480AB913 131.188.40.189 131.188.40.189 80 443'
 
-    authority1 = get_directory_authority({'contact': 'doctor jekyll'}, is_vote = False)
+    authority1 = DirectoryAuthority.create({'contact': 'doctor jekyll'}, is_vote = False)
     authority2 = DirectoryAuthority(legacy_content, validate = True, is_vote = False)
-    authority3 = get_directory_authority({'contact': 'mister hyde'}, is_vote = False)
+    authority3 = DirectoryAuthority.create({'contact': 'mister hyde'}, is_vote = False)
 
-    document = get_network_status_document_v3({'vote-status': 'consensus'}, authorities = (authority1, authority2, authority3))
+    document = NetworkStatusDocumentV3.create({'vote-status': 'consensus'}, authorities = (authority1, authority2, authority3))
 
     self.assertEqual((authority1, authority2, authority3), document.directory_authorities)
 
@@ -1270,11 +1265,11 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
     """
 
     # make the dir-key-published field of the certiciate be malformed
-    authority_content = get_directory_authority(is_vote = True, content = True)
+    authority_content = DirectoryAuthority.content(is_vote = True)
     authority_content = authority_content.replace(b'dir-key-published 2011', b'dir-key-published 2011a')
     authority = DirectoryAuthority(authority_content, False, True)
 
-    content = get_network_status_document_v3({'vote-status': 'vote'}, authorities = (authority,), content = True)
+    content = NetworkStatusDocumentV3.content({'vote-status': 'vote'}, authorities = (authority,))
     self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
 
     document = NetworkStatusDocumentV3(content, validate = False)
diff --git a/test/unit/descriptor/networkstatus/key_certificate.py b/test/unit/descriptor/networkstatus/key_certificate.py
index bbcaaa0..a56c74a 100644
--- a/test/unit/descriptor/networkstatus/key_certificate.py
+++ b/test/unit/descriptor/networkstatus/key_certificate.py
@@ -5,13 +5,12 @@ Unit tests for the KeyCertificate of stem.descriptor.networkstatus.
 import datetime
 import unittest
 
-from stem.descriptor.networkstatus import KeyCertificate
+import stem.descriptor
 
-from test.mocking import (
-  get_key_certificate,
-  CRYPTO_BLOB,
+from stem.descriptor.networkstatus import (
   KEY_CERTIFICATE_HEADER,
   KEY_CERTIFICATE_FOOTER,
+  KeyCertificate,
 )
 
 
@@ -21,18 +20,18 @@ class TestKeyCertificate(unittest.TestCase):
     Parses a minimal key certificate.
     """
 
-    certificate = get_key_certificate()
+    certificate = KeyCertificate.create()
 
     self.assertEqual(3, certificate.version)
     self.assertEqual(None, certificate.address)
     self.assertEqual(None, certificate.dir_port)
     self.assertEqual('27B6B5996C426270A5C95488AA5BCEB6BCC86956', certificate.fingerprint)
-    self.assertTrue(CRYPTO_BLOB in certificate.identity_key)
+    self.assertTrue(stem.descriptor.CRYPTO_BLOB in certificate.identity_key)
     self.assertEqual(datetime.datetime(2011, 11, 28, 21, 51, 4), certificate.published)
     self.assertEqual(datetime.datetime(2012, 11, 28, 21, 51, 4), certificate.expires)
-    self.assertTrue(CRYPTO_BLOB in certificate.signing_key)
+    self.assertTrue(stem.descriptor.CRYPTO_BLOB in certificate.signing_key)
     self.assertEqual(None, certificate.crosscert)
-    self.assertTrue(CRYPTO_BLOB in certificate.certification)
+    self.assertTrue(stem.descriptor.CRYPTO_BLOB in certificate.certification)
     self.assertEqual([], certificate.get_unrecognized_lines())
 
   def test_unrecognized_line(self):
@@ -40,7 +39,7 @@ class TestKeyCertificate(unittest.TestCase):
     Includes unrecognized content in the descriptor.
     """
 
-    certificate = get_key_certificate({'pepperjack': 'is oh so tasty!'})
+    certificate = KeyCertificate.create({'pepperjack': 'is oh so tasty!'})
     self.assertEqual(['pepperjack is oh so tasty!'], certificate.get_unrecognized_lines())
 
   def test_first_and_last_lines(self):
@@ -49,7 +48,7 @@ class TestKeyCertificate(unittest.TestCase):
     line or after the 'dir-key-certification' line.
     """
 
-    content = get_key_certificate(content = True)
+    content = KeyCertificate.content()
 
     for cert_text in (b'dir-address 127.0.0.1:80\n' + content,
                       content + b'\ndir-address 127.0.0.1:80'):
@@ -67,7 +66,7 @@ class TestKeyCertificate(unittest.TestCase):
     mandatory_fields = [entry[0] for entry in KEY_CERTIFICATE_HEADER + KEY_CERTIFICATE_FOOTER]
 
     for excluded_field in mandatory_fields:
-      content = get_key_certificate(exclude = (excluded_field,), content = True)
+      content = KeyCertificate.content(exclude = (excluded_field,))
       self.assertRaises(ValueError, KeyCertificate, content, True)
 
       certificate = KeyCertificate(content, False)
@@ -82,7 +81,7 @@ class TestKeyCertificate(unittest.TestCase):
     Includes blank lines, which should be ignored.
     """
 
-    certificate = get_key_certificate({'dir-key-published': '2011-11-28 21:51:04\n\n\n'})
+    certificate = KeyCertificate.create({'dir-key-published': '2011-11-28 21:51:04\n\n\n'})
     self.assertEqual(datetime.datetime(2011, 11, 28, 21, 51, 4), certificate.published)
 
   def test_version(self):
@@ -91,14 +90,14 @@ class TestKeyCertificate(unittest.TestCase):
     different certificate version with the v3 parser.
     """
 
-    certificate = get_key_certificate({'dir-key-certificate-version': '3'})
+    certificate = KeyCertificate.create({'dir-key-certificate-version': '3'})
     self.assertEqual(3, certificate.version)
 
-    content = get_key_certificate({'dir-key-certificate-version': '4'}, content = True)
+    content = KeyCertificate.content({'dir-key-certificate-version': '4'})
     self.assertRaises(ValueError, KeyCertificate, content, True)
     self.assertEqual(4, KeyCertificate(content, False).version)
 
-    content = get_key_certificate({'dir-key-certificate-version': 'boo'}, content = True)
+    content = KeyCertificate.content({'dir-key-certificate-version': 'boo'})
     self.assertRaises(ValueError, KeyCertificate, content, True)
     self.assertEqual(None, KeyCertificate(content, False).version)
 
@@ -107,7 +106,7 @@ class TestKeyCertificate(unittest.TestCase):
     Parses the dir-address field.
     """
 
-    certificate = get_key_certificate({'dir-address': '127.0.0.1:80'})
+    certificate = KeyCertificate.create({'dir-address': '127.0.0.1:80'})
     self.assertEqual('127.0.0.1', certificate.address)
     self.assertEqual(80, certificate.dir_port)
 
@@ -123,7 +122,7 @@ class TestKeyCertificate(unittest.TestCase):
     )
 
     for test_value in test_values:
-      content = get_key_certificate({'dir-address': test_value}, content = True)
+      content = KeyCertificate.content({'dir-address': test_value})
       self.assertRaises(ValueError, KeyCertificate, content, True)
 
       certificate = KeyCertificate(content, False)
@@ -143,7 +142,7 @@ class TestKeyCertificate(unittest.TestCase):
     )
 
     for test_value in test_values:
-      content = get_key_certificate({'fingerprint': test_value}, content = True)
+      content = KeyCertificate.content({'fingerprint': test_value})
       self.assertRaises(ValueError, KeyCertificate, content, True)
 
       certificate = KeyCertificate(content, False)
@@ -165,7 +164,7 @@ class TestKeyCertificate(unittest.TestCase):
 
     for field, attr in (('dir-key-published', 'published'), ('dir-key-expires', 'expires')):
       for test_value in test_values:
-        content = get_key_certificate({field: test_value}, content = True)
+        content = KeyCertificate.content({field: test_value})
         self.assertRaises(ValueError, KeyCertificate, content, True)
 
         certificate = KeyCertificate(content, False)
@@ -179,16 +178,16 @@ class TestKeyCertificate(unittest.TestCase):
 
     # the only non-mandatory field that we haven't exercised yet is dir-key-crosscert
 
-    certificate = get_key_certificate({'dir-key-crosscert': '\n-----BEGIN ID SIGNATURE-----%s-----END ID SIGNATURE-----' % CRYPTO_BLOB})
-    self.assertTrue(CRYPTO_BLOB in certificate.crosscert)
+    certificate = KeyCertificate.create({'dir-key-crosscert': '\n-----BEGIN ID SIGNATURE-----%s-----END ID SIGNATURE-----' % stem.descriptor.CRYPTO_BLOB})
+    self.assertTrue(stem.descriptor.CRYPTO_BLOB in certificate.crosscert)
 
-    test_value = '\n-----BEGIN ID SIGNATURE-----%s-----END UGABUGA SIGNATURE-----' % CRYPTO_BLOB
+    test_value = '\n-----BEGIN ID SIGNATURE-----%s-----END UGABUGA SIGNATURE-----' % stem.descriptor.CRYPTO_BLOB
 
     for field, attr in (('dir-identity-key', 'identity_key'),
                         ('dir-signing-key', 'signing_key'),
                         ('dir-key-crosscert', 'crosscert'),
                         ('dir-key-certification', 'certification')):
-      content = get_key_certificate({field: test_value}, content = True)
+      content = KeyCertificate.content({field: test_value})
       self.assertRaises(ValueError, KeyCertificate, content, True)
 
       certificate = KeyCertificate(content, False)
@@ -199,5 +198,5 @@ class TestKeyCertificate(unittest.TestCase):
     Checks that we validate the type of crypto content we receive.
     """
 
-    content = get_key_certificate({'dir-identity-key': '\n-----BEGIN MD5SUM-----%s-----END MD5SUM-----' % CRYPTO_BLOB}, content = True)
+    content = KeyCertificate.content({'dir-identity-key': '\n-----BEGIN MD5SUM-----%s-----END MD5SUM-----' % stem.descriptor.CRYPTO_BLOB})
     self.assertRaises(ValueError, KeyCertificate, content, True)
diff --git a/test/unit/tutorial.py b/test/unit/tutorial.py
index 48d0abb..cdfb014 100644
--- a/test/unit/tutorial.py
+++ b/test/unit/tutorial.py
@@ -9,9 +9,9 @@ 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 stem.descriptor.networkstatus import NetworkStatusDocumentV3
+from stem.descriptor.server_descriptor import RelayDescriptor
 from test.unit import exec_documentation_example
 
 try:
@@ -151,11 +151,7 @@ class TestTutorial(unittest.TestCase):
       for desc in parse_file(open('/home/atagar/.tor/cached-consensus')):
         print('found relay %s (%s)' % (desc.nickname, desc.fingerprint))
 
-    test_file = io.BytesIO(mocking.get_network_status_document_v3(
-      routers = [RouterStatusEntryV3.create()],
-      content = True,
-    ))
-
+    test_file = io.BytesIO(NetworkStatusDocumentV3.content(routers = [RouterStatusEntryV3.create()]))
     test_file.name = '/home/atagar/.tor/cached-consensus'
     open_mock.return_value = test_file
 
diff --git a/test/unit/tutorial_examples.py b/test/unit/tutorial_examples.py
index b3ac813..c979f07 100644
--- a/test/unit/tutorial_examples.py
+++ b/test/unit/tutorial_examples.py
@@ -17,12 +17,12 @@ import stem.prereq
 
 from stem.control import Controller
 from stem.util import str_type
+from stem.descriptor.networkstatus import NetworkStatusDocumentV3
 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 stem.descriptor.server_descriptor import RelayDescriptor
 
 from test import mocking
-from test.mocking import get_network_status_document_v3
 from test.unit import exec_documentation_example
 
 try:
@@ -274,8 +274,8 @@ class TestTutorialExamples(unittest.TestCase):
     ]
 
     query_mock().run.side_effect = [
-      [get_network_status_document_v3(routers = (entry[0], entry[1], entry[2], entry[3], entry[4]))],
-      [get_network_status_document_v3(routers = (entry[5], entry[6], entry[7], entry[8], entry[9]))],
+      [NetworkStatusDocumentV3.create(routers = (entry[0], entry[1], entry[2], entry[3], entry[4]))],
+      [NetworkStatusDocumentV3.create(routers = (entry[5], entry[6], entry[7], entry[8], entry[9]))],
     ]
 
     exec_documentation_example('compare_flags.py')
@@ -332,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 = (RouterStatusEntryV3.create(),))
+    network_status = NetworkStatusDocumentV3.create(routers = (RouterStatusEntryV3.create(),))
     query_mock().run.return_value = [network_status]
     parse_file_mock.return_value = itertools.cycle([network_status])
 



_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits