[tor-commits] [bridgedb/master] Deprecate the bridgedb.parse.networkstatus module.

isis at torproject.org isis at torproject.org
Sat Mar 21 02:03:00 UTC 2015


commit 399552ae06b56c7f703303e9d0c638253657d1bb
Author: Isis Lovecruft <isis at torproject.org>
Date:   Wed Feb 11 21:58:51 2015 +0000

    Deprecate the bridgedb.parse.networkstatus module.
    
     * MOVE bridgedb.parse.networkstatus to
       bridgedb.test.deprecated_networkstatus and wrap all callables within
       with @twisted.python.deprecate.deprecated.
     * REMOVE the import of bridgedb.parse.networkstatus in bridgedb.Bridges
       module.
     * CHANGE legacy_Tests.py to import deprecated_networkstatus to continue
       to check for regressions in other parts of the codebase.
     * REMOVE bridgedb.test.test_parse_networkstatus.py.
---
 lib/bridgedb/Bridges.py                       |    1 -
 lib/bridgedb/parse/networkstatus.py           |  263 ----------------
 lib/bridgedb/test/deprecated_networkstatus.py |  275 ++++++++++++++++
 lib/bridgedb/test/legacy_Tests.py             |    2 +-
 lib/bridgedb/test/test_parse_networkstatus.py |  414 -------------------------
 5 files changed, 276 insertions(+), 679 deletions(-)

diff --git a/lib/bridgedb/Bridges.py b/lib/bridgedb/Bridges.py
index 31b7cf6..bdb911a 100644
--- a/lib/bridgedb/Bridges.py
+++ b/lib/bridgedb/Bridges.py
@@ -25,7 +25,6 @@ import bridgedb.Bucket
 from bridgedb.bridges import Bridge
 from bridgedb.crypto import getHMACFunc
 from bridgedb.parse import addr
-from bridgedb.parse import networkstatus
 from bridgedb.parse.fingerprint import toHex
 from bridgedb.parse.fingerprint import fromHex
 from bridgedb.parse.fingerprint import isValidFingerprint
diff --git a/lib/bridgedb/parse/networkstatus.py b/lib/bridgedb/parse/networkstatus.py
deleted file mode 100644
index 8140fe0..0000000
--- a/lib/bridgedb/parse/networkstatus.py
+++ /dev/null
@@ -1,263 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# This file is part of BridgeDB, a Tor bridge distribution system.
-#
-# :authors: Isis Lovecruft 0xA3ADB67A2CDB8B35 <isis at torproject.org>
-#           please also see AUTHORS file
-# :copyright: (c) 2013 Isis Lovecruft
-#             (c) 2007-2014, The Tor Project, Inc.
-#             (c) 2007-2014, all entities within the AUTHORS file
-# :license: 3-clause BSD, see included LICENSE for information
-
-"""Parsers for bridge networkstatus descriptors.
-
-.. py:module:: bridgedb.parse.networkstatus
-   :synopsis: Parsers for ``@type bridge-network-status`` descriptors_.
-.. _descriptors: https://metrics.torproject.org/formats.html#descriptortypes
-
-
-bridgedb.parse.networkstatus
-============================
-::
-
-  networkstatus
-   |_ isValidRouterNickname - Determine if a nickname is according to spec
-   |_ parseRLine - Parse an 'r'-line from a networkstatus document
-   |_ parseALine - Parse an 'a'-line from a networkstatus document
-    \_ parseSLine - Parse an 's'-line from a networkstatus document
-..
-"""
-
-import binascii
-import logging
-import string
-import time
-import warnings
-
-from twisted.python.log import showwarning
-
-from bridgedb.parse import addr
-from bridgedb.parse import parseUnpaddedBase64
-from bridgedb.parse import InvalidBase64
-from bridgedb.parse.nickname import InvalidRouterNickname
-from bridgedb.parse.nickname import isValidRouterNickname
-
-
-class NetworkstatusParsingError(Exception):
-    """Unable to parse networkstatus document line."""
-
-class InvalidNetworkstatusRouterIdentity(ValueError):
-    """The ID field of a networkstatus document 'r'-line is invalid."""
-
-
-def parseRLine(line):
-    """Parse an 'r'-line from a networkstatus document.
-
-    From torspec.git/dir-spec.txt, commit 36761c7d553d L1499-1512:
-      | "r" SP nickname SP identity SP digest SP publication SP IP SP ORPort
-      |     SP DirPort NL
-      |
-      |     [At start, exactly once.]
-      |
-      |     "Nickname" is the OR's nickname.  "Identity" is a hash of its
-      |     identity key, encoded in base64, with trailing equals sign(s)
-      |     removed.  "Digest" is a hash of its most recent descriptor as
-      |     signed (that is, not including the signature), encoded in base64.
-      |     "Publication" is the
-      |     publication time of its most recent descriptor, in the form
-      |     YYYY-MM-DD HH:MM:SS, in UTC.  "IP" is its current IP address;
-      |     ORPort is its current OR port, "DirPort" is its current directory
-      |     port, or "0" for "none".
-
-    :param string line: An 'r'-line from an bridge-network-status descriptor.
-    :returns:
-        A 7-tuple of::
-            (nickname, identityDigest, descriptorDigest, timestamp,
-             orAddress, orPort, dirport)
-        where each value is set according to the data parsed from the
-        **line**, or ``None`` if nothing suitable could be parsed.
-    """
-    (nickname, ID, descDigest, timestamp,
-     ORaddr, ORport, dirport) = (None for x in xrange(7))
-
-    try:
-        if not line.startswith('r '):
-            raise NetworkstatusParsingError(
-                "Networkstatus parser received non 'r'-line: %r" % line)
-
-        line = line[2:] # Chop off the 'r '
-        fields = line.split()
-
-        if len(fields) != 8:
-            raise NetworkstatusParsingError(
-                "Wrong number of fields in networkstatus 'r'-line: %r" % line)
-
-        nickname, ID = fields[:2]
-
-        try:
-            ID = parseUnpaddedBase64(ID)
-        except InvalidBase64 as error:
-            raise InvalidNetworkstatusRouterIdentity(error)
-
-        # Check the nickname validity after parsing the ID, otherwise, if the
-        # nickname is invalid, we end up with the nickname being ``None`` and
-        # the ID being unparsed, unpadded (meaning it is technically invalid)
-        # base64.
-        isValidRouterNickname(nickname)
-
-    except NetworkstatusParsingError as error:
-        logging.error(error)
-        nickname, ID = None, None
-    except InvalidRouterNickname as error:
-        logging.error(error)
-        # Assume that we mostly care about obtaining the OR's ID, then it
-        # should be okay to set the nickname to ``None``, if it was invalid.
-        nickname = None
-    except InvalidNetworkstatusRouterIdentity as error:
-        logging.error(error)
-        ID = None
-    else:
-        try:
-            descDigest = parseUnpaddedBase64(fields[2])
-            timestamp = time.mktime(time.strptime(" ".join(fields[3:5]),
-                                                  "%Y-%m-%d %H:%M:%S"))
-            ORaddr = fields[5]
-            ORport = int(fields[6])
-            dirport = fields[7]
-        except InvalidBase64 as error:
-            logging.error(error)
-            descDigest = None
-        except (AttributeError, ValueError, IndexError) as error:
-            logging.error(error)
-            timestamp = None
-    finally:
-        return (nickname, ID, descDigest, timestamp, ORaddr, ORport, dirport)
-
-def parseALine(line, fingerprint=None):
-    """Parse an 'a'-line of a bridge networkstatus document.
-
-    From torspec.git/dir-spec.txt, commit 36761c7d553d L1499-1512:
-      |
-      | "a" SP address ":" port NL
-      |
-      |    [Any number.]
-      |
-      |    Present only if the OR has at least one IPv6 address.
-      |
-      |    Address and portlist are as for "or-address" as specified in
-      |    2.1.
-      |
-      |    (Only included when the vote or consensus is generated with
-      |    consensus-method 14 or later.)
-
-    :param string line: An 'a'-line from an bridge-network-status descriptor.
-    :type fingerprint: string or None
-    :param fingerprint: A string which identifies which OR the descriptor
-        we're parsing came from (since the 'a'-line doesn't tell us, this can
-        help make the log messages clearer).
-    :raises: :exc:`NetworkstatusParsingError`
-    :rtype: tuple
-    :returns: A 2-tuple of a string respresenting the IP address and a
-        :class:`bridgedb.parse.addr.PortList`.
-    """
-    ip = None
-    portlist = None
-
-    if line.startswith('a '):
-        line = line[2:] # Chop off the 'a '
-    else:
-        logging.warn("Networkstatus parser received non 'a'-line for %r:"\
-                     "  %r" % (fingerprint or 'Unknown', line))
-
-    try:
-        ip, portlist = line.rsplit(':', 1)
-    except ValueError as error:
-        logging.error("Bad separator in networkstatus 'a'-line: %r" % line)
-        return (None, None)
-
-    if ip.startswith('[') and ip.endswith(']'):
-        ip = ip.strip('[]')
-
-    try:
-        if not addr.isIPAddress(ip):
-            raise NetworkstatusParsingError(
-                "Got invalid IP Address in networkstatus 'a'-line for %r: %r"
-                % (fingerprint or 'Unknown', line))
-
-        if addr.isIPv4(ip):
-            warnings.warn(FutureWarning(
-                "Got IPv4 address in networkstatus 'a'-line! "\
-                "Networkstatus document format may have changed!"))
-    except NetworkstatusParsingError as error:
-        logging.error(error)
-        ip, portlist = None, None
-
-    try:
-        portlist = addr.PortList(portlist)
-        if not portlist:
-            raise NetworkstatusParsingError(
-                "Got invalid portlist in 'a'-line for %r!\n  Line: %r"
-                % (fingerprint or 'Unknown', line))
-    except (addr.InvalidPort, NetworkstatusParsingError) as error:
-        logging.error(error)
-        portlist = None
-    else:
-        logging.debug("Parsed networkstatus ORAddress line for %r:"\
-                      "\n  Address: %s  \tPorts: %s"
-                      % (fingerprint or 'Unknown', ip, portlist))
-    finally:
-        return (ip, portlist)
-
-def parseSLine(line):
-    """Parse an 's'-line from a bridge networkstatus document.
-
-    The 's'-line contains all flags assigned to a bridge. The flags which may
-    be assigned to a bridge are as follows:
-
-    From torspec.git/dir-spec.txt, commit 36761c7d553d L1526-1554:
-      |
-      | "s" SP Flags NL
-      |
-      |    [Exactly once.]
-      |
-      |    A series of space-separated status flags, in lexical order (as ASCII
-      |    byte strings).  Currently documented flags are:
-      |
-      |      "BadDirectory" if the router is believed to be useless as a
-      |         directory cache (because its directory port isn't working,
-      |         its bandwidth is always throttled, or for some similar
-      |         reason).
-      |      "Fast" if the router is suitable for high-bandwidth circuits.
-      |      "Guard" if the router is suitable for use as an entry guard.
-      |      "HSDir" if the router is considered a v2 hidden service directory.
-      |      "Named" if the router's identity-nickname mapping is canonical,
-      |         and this authority binds names.
-      |      "Stable" if the router is suitable for long-lived circuits.
-      |      "Running" if the router is currently usable.
-      |      "Valid" if the router has been 'validated'.
-      |      "V2Dir" if the router implements the v2 directory protocol.
-
-    :param string line: An 's'-line from an bridge-network-status descriptor.
-    :rtype: tuple
-    :returns: A 2-tuple of booleans, the first is True if the bridge has the
-        "Running" flag, and the second is True if it has the "Stable" flag.
-    """
-    line = line[2:]
-
-    flags = [x.capitalize() for x in line.split()]
-    fast    = 'Fast' in flags
-    running = 'Running' in flags
-    stable  = 'Stable' in flags
-    guard   = 'Guard' in flags
-    valid   = 'Valid' in flags
-
-    if (fast or running or stable or guard or valid):
-        logging.debug("Parsed Flags: %s%s%s%s%s"
-                      % ('Fast ' if fast else '',
-                         'Running ' if running else '',
-                         'Stable ' if stable else '',
-                         'Guard ' if guard else '',
-                         'Valid ' if valid else ''))
-
-    # Right now, we only care about 'Running' and 'Stable'
-    return running, stable
diff --git a/lib/bridgedb/test/deprecated_networkstatus.py b/lib/bridgedb/test/deprecated_networkstatus.py
new file mode 100644
index 0000000..7e3b0a4
--- /dev/null
+++ b/lib/bridgedb/test/deprecated_networkstatus.py
@@ -0,0 +1,275 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of BridgeDB, a Tor bridge distribution system.
+#
+# :authors: Isis Lovecruft 0xA3ADB67A2CDB8B35 <isis at torproject.org>
+#           please also see AUTHORS file
+# :copyright: (c) 2013 Isis Lovecruft
+#             (c) 2007-2014, The Tor Project, Inc.
+#             (c) 2007-2014, all entities within the AUTHORS file
+# :license: 3-clause BSD, see included LICENSE for information
+
+"""Parsers for bridge networkstatus descriptors.
+
+THIS ENTIRE MODULE WAS DEPRECATED (AS PART OF #9380_) AND WAS REPLACED WITH
+THE CORRESPONDING FUNCTIONS IN :mod:`bridgedb.parse.descriptors`.
+
+.. #9380: https://bugs.torproject.org/9380
+
+.. py:module:: bridgedb.parse.networkstatus
+   :synopsis: Parsers for ``@type bridge-network-status`` descriptors_.
+.. _descriptors: https://metrics.torproject.org/formats.html#descriptortypes
+
+
+bridgedb.parse.networkstatus
+============================
+::
+
+  networkstatus
+   |_ isValidRouterNickname - Determine if a nickname is according to spec
+   |_ parseRLine - Parse an 'r'-line from a networkstatus document
+   |_ parseALine - Parse an 'a'-line from a networkstatus document
+    \_ parseSLine - Parse an 's'-line from a networkstatus document
+..
+"""
+
+import binascii
+import logging
+import string
+import time
+import warnings
+
+from twisted.python import deprecate
+from twisted.python.log import showwarning
+from twisted.python.versions import Version
+
+from bridgedb.parse import addr
+from bridgedb.parse import parseUnpaddedBase64
+from bridgedb.parse import InvalidBase64
+from bridgedb.parse.nickname import InvalidRouterNickname
+from bridgedb.parse.nickname import isValidRouterNickname
+
+
+ at deprecate.deprecated(Version('bridgedb', 0, 2, 5))
+class NetworkstatusParsingError(Exception):
+    """Unable to parse networkstatus document line."""
+
+ at deprecate.deprecated(Version('bridgedb', 0, 2, 5))
+class InvalidNetworkstatusRouterIdentity(ValueError):
+    """The ID field of a networkstatus document 'r'-line is invalid."""
+
+
+ at deprecate.deprecated(Version('bridgedb', 0, 2, 5))
+def parseRLine(line):
+    """Parse an 'r'-line from a networkstatus document.
+
+    From torspec.git/dir-spec.txt, commit 36761c7d553d L1499-1512:
+      | "r" SP nickname SP identity SP digest SP publication SP IP SP ORPort
+      |     SP DirPort NL
+      |
+      |     [At start, exactly once.]
+      |
+      |     "Nickname" is the OR's nickname.  "Identity" is a hash of its
+      |     identity key, encoded in base64, with trailing equals sign(s)
+      |     removed.  "Digest" is a hash of its most recent descriptor as
+      |     signed (that is, not including the signature), encoded in base64.
+      |     "Publication" is the
+      |     publication time of its most recent descriptor, in the form
+      |     YYYY-MM-DD HH:MM:SS, in UTC.  "IP" is its current IP address;
+      |     ORPort is its current OR port, "DirPort" is its current directory
+      |     port, or "0" for "none".
+
+    :param string line: An 'r'-line from an bridge-network-status descriptor.
+    :returns:
+        A 7-tuple of::
+            (nickname, identityDigest, descriptorDigest, timestamp,
+             orAddress, orPort, dirport)
+        where each value is set according to the data parsed from the
+        **line**, or ``None`` if nothing suitable could be parsed.
+    """
+    (nickname, ID, descDigest, timestamp,
+     ORaddr, ORport, dirport) = (None for x in xrange(7))
+
+    try:
+        if not line.startswith('r '):
+            raise NetworkstatusParsingError(
+                "Networkstatus parser received non 'r'-line: %r" % line)
+
+        line = line[2:] # Chop off the 'r '
+        fields = line.split()
+
+        if len(fields) != 8:
+            raise NetworkstatusParsingError(
+                "Wrong number of fields in networkstatus 'r'-line: %r" % line)
+
+        nickname, ID = fields[:2]
+
+        try:
+            ID = parseUnpaddedBase64(ID)
+        except InvalidBase64 as error:
+            raise InvalidNetworkstatusRouterIdentity(error)
+
+        # Check the nickname validity after parsing the ID, otherwise, if the
+        # nickname is invalid, we end up with the nickname being ``None`` and
+        # the ID being unparsed, unpadded (meaning it is technically invalid)
+        # base64.
+        isValidRouterNickname(nickname)
+
+    except NetworkstatusParsingError as error:
+        logging.error(error)
+        nickname, ID = None, None
+    except InvalidRouterNickname as error:
+        logging.error(error)
+        # Assume that we mostly care about obtaining the OR's ID, then it
+        # should be okay to set the nickname to ``None``, if it was invalid.
+        nickname = None
+    except InvalidNetworkstatusRouterIdentity as error:
+        logging.error(error)
+        ID = None
+    else:
+        try:
+            descDigest = parseUnpaddedBase64(fields[2])
+            timestamp = time.mktime(time.strptime(" ".join(fields[3:5]),
+                                                  "%Y-%m-%d %H:%M:%S"))
+            ORaddr = fields[5]
+            ORport = int(fields[6])
+            dirport = fields[7]
+        except InvalidBase64 as error:
+            logging.error(error)
+            descDigest = None
+        except (AttributeError, ValueError, IndexError) as error:
+            logging.error(error)
+            timestamp = None
+    finally:
+        return (nickname, ID, descDigest, timestamp, ORaddr, ORport, dirport)
+
+ at deprecate.deprecated(Version('bridgedb', 0, 2, 5))
+def parseALine(line, fingerprint=None):
+    """Parse an 'a'-line of a bridge networkstatus document.
+
+    From torspec.git/dir-spec.txt, commit 36761c7d553d L1499-1512:
+      |
+      | "a" SP address ":" port NL
+      |
+      |    [Any number.]
+      |
+      |    Present only if the OR has at least one IPv6 address.
+      |
+      |    Address and portlist are as for "or-address" as specified in
+      |    2.1.
+      |
+      |    (Only included when the vote or consensus is generated with
+      |    consensus-method 14 or later.)
+
+    :param string line: An 'a'-line from an bridge-network-status descriptor.
+    :type fingerprint: string or None
+    :param fingerprint: A string which identifies which OR the descriptor
+        we're parsing came from (since the 'a'-line doesn't tell us, this can
+        help make the log messages clearer).
+    :raises: :exc:`NetworkstatusParsingError`
+    :rtype: tuple
+    :returns: A 2-tuple of a string respresenting the IP address and a
+        :class:`bridgedb.parse.addr.PortList`.
+    """
+    ip = None
+    portlist = None
+
+    if line.startswith('a '):
+        line = line[2:] # Chop off the 'a '
+    else:
+        logging.warn("Networkstatus parser received non 'a'-line for %r:"\
+                     "  %r" % (fingerprint or 'Unknown', line))
+
+    try:
+        ip, portlist = line.rsplit(':', 1)
+    except ValueError as error:
+        logging.error("Bad separator in networkstatus 'a'-line: %r" % line)
+        return (None, None)
+
+    if ip.startswith('[') and ip.endswith(']'):
+        ip = ip.strip('[]')
+
+    try:
+        if not addr.isIPAddress(ip):
+            raise NetworkstatusParsingError(
+                "Got invalid IP Address in networkstatus 'a'-line for %r: %r"
+                % (fingerprint or 'Unknown', line))
+
+        if addr.isIPv4(ip):
+            warnings.warn(FutureWarning(
+                "Got IPv4 address in networkstatus 'a'-line! "\
+                "Networkstatus document format may have changed!"))
+    except NetworkstatusParsingError as error:
+        logging.error(error)
+        ip, portlist = None, None
+
+    try:
+        portlist = addr.PortList(portlist)
+        if not portlist:
+            raise NetworkstatusParsingError(
+                "Got invalid portlist in 'a'-line for %r!\n  Line: %r"
+                % (fingerprint or 'Unknown', line))
+    except (addr.InvalidPort, NetworkstatusParsingError) as error:
+        logging.error(error)
+        portlist = None
+    else:
+        logging.debug("Parsed networkstatus ORAddress line for %r:"\
+                      "\n  Address: %s  \tPorts: %s"
+                      % (fingerprint or 'Unknown', ip, portlist))
+    finally:
+        return (ip, portlist)
+
+ at deprecate.deprecated(Version('bridgedb', 0, 2, 5))
+def parseSLine(line):
+    """Parse an 's'-line from a bridge networkstatus document.
+
+    The 's'-line contains all flags assigned to a bridge. The flags which may
+    be assigned to a bridge are as follows:
+
+    From torspec.git/dir-spec.txt, commit 36761c7d553d L1526-1554:
+      |
+      | "s" SP Flags NL
+      |
+      |    [Exactly once.]
+      |
+      |    A series of space-separated status flags, in lexical order (as ASCII
+      |    byte strings).  Currently documented flags are:
+      |
+      |      "BadDirectory" if the router is believed to be useless as a
+      |         directory cache (because its directory port isn't working,
+      |         its bandwidth is always throttled, or for some similar
+      |         reason).
+      |      "Fast" if the router is suitable for high-bandwidth circuits.
+      |      "Guard" if the router is suitable for use as an entry guard.
+      |      "HSDir" if the router is considered a v2 hidden service directory.
+      |      "Named" if the router's identity-nickname mapping is canonical,
+      |         and this authority binds names.
+      |      "Stable" if the router is suitable for long-lived circuits.
+      |      "Running" if the router is currently usable.
+      |      "Valid" if the router has been 'validated'.
+      |      "V2Dir" if the router implements the v2 directory protocol.
+
+    :param string line: An 's'-line from an bridge-network-status descriptor.
+    :rtype: tuple
+    :returns: A 2-tuple of booleans, the first is True if the bridge has the
+        "Running" flag, and the second is True if it has the "Stable" flag.
+    """
+    line = line[2:]
+
+    flags = [x.capitalize() for x in line.split()]
+    fast    = 'Fast' in flags
+    running = 'Running' in flags
+    stable  = 'Stable' in flags
+    guard   = 'Guard' in flags
+    valid   = 'Valid' in flags
+
+    if (fast or running or stable or guard or valid):
+        logging.debug("Parsed Flags: %s%s%s%s%s"
+                      % ('Fast ' if fast else '',
+                         'Running ' if running else '',
+                         'Stable ' if stable else '',
+                         'Guard ' if guard else '',
+                         'Valid ' if valid else ''))
+
+    # Right now, we only care about 'Running' and 'Stable'
+    return running, stable
diff --git a/lib/bridgedb/test/legacy_Tests.py b/lib/bridgedb/test/legacy_Tests.py
index 7be5270..d416d22 100644
--- a/lib/bridgedb/test/legacy_Tests.py
+++ b/lib/bridgedb/test/legacy_Tests.py
@@ -35,7 +35,7 @@ from bridgedb.Filters import filterBridgesByNotBlockedIn
 from bridgedb.Stability import BridgeHistory
 
 from bridgedb.parse import addr
-from bridgedb.parse import networkstatus
+from bridgedb.test import deprecated_networkstatus as networkstatus
 
 from math import log
 
diff --git a/lib/bridgedb/test/test_parse_networkstatus.py b/lib/bridgedb/test/test_parse_networkstatus.py
deleted file mode 100644
index 6a89c25..0000000
--- a/lib/bridgedb/test/test_parse_networkstatus.py
+++ /dev/null
@@ -1,414 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# This file is part of BridgeDB, a Tor bridge distribution system.
-#
-# :authors: Isis Lovecruft 0xA3ADB67A2CDB8B35 <isis at torproject.org>
-# :copyright: (c) 2013-2014, Isis Lovecruft
-#             (c) 2007-2014, The Tor Project, Inc.
-# :license: 3-Clause BSD, see LICENSE for licensing information
-
-"""Unittests for the :mod:`bridgedb.parse.networkstatus` module.
-
-These tests are meant to ensure that the :mod:`bridgedb.parse.networkstatus`
-module is functioning correctly.
-"""
-
-from __future__ import print_function
-from __future__ import unicode_literals
-
-import binascii
-
-from twisted.python import log
-from twisted.trial import unittest
-from bridgedb.parse import networkstatus
-
-import sure
-from sure import this, these, those, the, it
-
-
-logFormat  = "%(created)d [%(levelname)s] %(module)s.%(funcName)s(): "
-logFormat += "%(message)s"
-networkstatus.logging.basicConfig(
-    filename='test_parse_networkstatus.log',
-    level=networkstatus.logging.DEBUG,
-    flags='w', format=logFormat)
-
-
-class ParseNetworkStatusRLineTests(unittest.TestCase):
-    """Tests for :func:`bridgedb.parse.networkstatus.parseRLine`.
-
-    The documentation for all class variables, e.g. 'pre' or 'ident', refers
-    to what said value should be in a *valid* descriptor.
-    """
-    rawIdent = 'identdigestidentdig'
-    rawDesc  = 'descdigestdescdiges'
-
-    #: The prefix for the 'r'-line. Should be an 'r', unless testing that
-    #: lines with unknown prefixes are dropped.
-    pre   = 'r '
-    #: An OR nickname string. To be valid, it should be 1-19 alphanumeric
-    #: upper or lower cased characters.
-    nick  = 'Testing'
-    #: A base64-encoded, SHA-1 digest of the DER-formatted, ASN.1-encoded,
-    #: public portion of an OR identity key, with any trailing base64 padding
-    #: (any '=' characters) removed.
-    ident = binascii.b2a_base64(rawIdent).strip().rstrip('==')
-    #: A base64-encoded, SHA-1 digest of the OR
-    #: `@type-[bridge-]server-descriptor` document (the whole thing, up until
-    #: the 'router signature' line, but not including the signature thereafter),
-    #: with any trailing base64 padding (any '=' characters) removed.
-    desc  = binascii.b2a_base64(rawDesc).strip().rstrip('==')
-    #: An ISO-8661 formatted timestamp, with a space separator (rather than a
-    #: 'T' character).
-    ts    = '2013-10-31 15:15:15'
-    #: An IPv4 address.
-    ip    = '221.251.0.42'
-    #: An ORPort number.
-    port  = '9001'
-    #: A DirPort number.
-    dirp  = '0'
-
-    def makeRLine(self, *args, **kwargs):
-        """Concatenate parameters into an 'r'-line and store the result as
-        ``self.line``.
-
-        :keywords: The keyword arguments may be any of the class variables,
-                   i.e. 'nick' or 'ident', and the variables should be similar
-                   to the defaults in the class variables. If not given as
-                   parameters, the class variables will be used.
-        """
-        line = []
-        for kw in ('pre', 'nick', 'ident', 'desc', 'ts', 'ip', 'port', 'dirp'):
-            if kw in kwargs.keys():
-                if kwargs[kw]:
-                    line.append(kwargs[kw])
-                elif kwargs[kw] is False:
-                    pass
-            else:
-                line.append(getattr(self, kw, ''))
-
-        self.line = ' '.join([l for l in line]).strip()
-        log.msg("\n  Testing networkstatusline:\n    %r..." % self.line)
-        self.assertTrue(self.line != '')
-
-    def tearDown(self):
-        self.line = ''
-
-    def assertAllFieldsAreNone(self, fields):
-        """Assert that every field in the iterable ``fields`` is None."""
-        for field in fields:
-            self.assertTrue(field is None)
-
-    def test_missingPrefix(self):
-        """Test a networkstatus 'r'-line that is missing the 'r ' prefix."""
-        self.makeRLine(pre=False)
-        fields = networkstatus.parseRLine(self.line)
-        self.assertAllFieldsAreNone(fields)
-
-    def test_wrongNumberOfFields(self):
-        """Test a line missing digest, ORPort, and DirPort fields."""
-        self.makeRLine(desc=False, port=False, dirp=False)
-        fields = networkstatus.parseRLine(self.line)
-        self.assertAllFieldsAreNone(fields)
-
-    def test_wrongFieldOrder(self):
-        """Test a line with the identity and descriptor digests switched."""
-        self.makeRLine(desc=self.ident, ident=self.desc)
-        fields = networkstatus.parseRLine(self.line)
-        nick, others = fields[0], fields[1:]
-
-        this(nick).should.be.ok
-        this(nick).should.be.a(basestring)
-        this(nick).should.equal(self.nick)
-
-        the(others).should.be.a(tuple)
-        the(others).should.have.length_of(6)
-        for other in others:
-            the(other).should.be(None)
-
-    def test_invalidNicknameNonAlphanumeric(self):
-        """Test a line with a non-alphanumeric router nickname."""
-        self.makeRLine(nick='abcdef/*comment*/')
-        fields = networkstatus.parseRLine(self.line)
-        nick, ident, desc = fields[:3]
-        this(nick).should.be(None)
-        the(ident).should.be.a(basestring)
-        the(desc).should.be(None)
-
-    def test_invalidNicknameTooLong(self):
-        """Test a line with a router nickname which is way too long."""
-        self.makeRLine(nick='ThisIsAReallyReallyLongRouterNickname')
-        fields = networkstatus.parseRLine(self.line)
-        nick, ident, desc = fields[:3]
-        this(nick).should.be(None)
-        the(ident).should.be.a(basestring)
-        the(desc).should.be(None)
-
-    def test_invalidIdentBase64(self):
-        """Test line with '%$>@,<' for an identity digest."""
-        self.makeRLine(ident='%$>#@,<')
-        (nick, ident, desc, ts,
-         ip, port, dirp) = networkstatus.parseRLine(self.line)
-
-        the(nick).should.be.ok
-        the(nick).should.be.a(basestring)
-        the(nick).should.equal(self.nick)
-        the(ident).should.be(None)
-        the(desc).should.be(None)
-
-    def test_invalidIdentSingleQuoteChar(self):
-        """Test a line with a single quote character for the identity digest."""
-        self.makeRLine(ident=chr(0x27))
-        fields = networkstatus.parseRLine(self.line)
-        nick, ident, desc = fields[:3]
-
-        the(nick).should.be.ok
-        the(nick).should.be.a(basestring)
-        the(nick).should.be.equal(self.nick)
-        the(ident).should.be.equal(None)
-        the(desc).should.be.equal(None)
-
-    def test_invalidIdent_withBase64padding(self):
-        """Test a line with invalid base64 (no padding) identity digest."""
-        self.makeRLine(ident=self.ident + '==')
-        fields = networkstatus.parseRLine(self.line)
-        nick, ident, desc = fields[:3]
-
-        the(nick).should.be.ok
-        the(nick).should.be.a(basestring)
-        the(nick).should.be.equal(self.nick)
-        the(ident).should.be.equal(None)
-        the(desc).should.be.equal(None)
-
-    def test_invalidDescriptorDigest(self):
-        """Test an 'r'-line with invalid base64 descriptor digest."""
-        self.makeRLine(desc='敃噸襶')
-        fields = networkstatus.parseRLine(self.line)
-        nick, ident, desc, ts, ip = fields[:5]
-
-        the(nick).should.be.ok
-        the(nick).should.be.a(basestring)
-        the(nick).should.be.equal(self.nick)
-
-        the(ident).should.be.a(basestring)
-        the(ident).should.be.equal(self.rawIdent)
-
-        the(desc).should.be.equal(None)
-        the(ts).should.be.equal(None)
-        the(ip).should.be.equal(None)
-
-    def test_invalidDescriptorDigest_invalidBase64(self):
-        """Test line with '%$>@,<' for an identity digest."""
-        self.makeRLine(desc='%$>#@,<')
-        fields =  networkstatus.parseRLine(self.line)
-        nick, ident, desc, ts, ip = fields[:5]
-
-        the(nick).should.be.ok
-        the(nick).should.be.a(basestring)
-        the(nick).should.equal(self.nick)
-        the(ident).should.be(None)
-        the(desc).should.be(None)
-
-    def test_invalidDescriptorDigest_withBase64padding(self):
-        """Test a line with invalid base64 (no padding) descriptor digest."""
-        self.makeRLine(desc=self.desc + '==')
-        fields = networkstatus.parseRLine(self.line)
-        nick, ident, desc, ts, ip = fields[:5]
-
-        the(nick).should.be.ok
-        the(nick).should.be.a(basestring)
-        the(nick).should.be.equal(self.nick)
-
-        the(ident).should.be.a(basestring)
-        the(ident).should.be.equal(self.rawIdent)
-
-        the(desc).should.be.equal(None)
-        the(ts).should.be.equal(None)
-        the(ip).should.be.equal(None)
-
-    def test_invalidDescriptorDigest_singleQuoteChar(self):
-        """Test with a single quote character for the descriptor digest."""
-        self.makeRLine(desc=chr(0x27))
-        fields = networkstatus.parseRLine(self.line)
-        nick, ident, desc = fields[:3]
-
-        the(nick).should.be.ok
-        the(nick).should.be.a(basestring)
-        the(nick).should.be.equal(self.nick)
-        the(ident).should.be.equal(self.rawIdent)
-        the(desc).should.be.equal(None)
-
-    def test_missingAfterDesc(self):
-        """Test a line that has a valid descriptor digest, and is missing
-        everything after the descriptor digest, i.e. the timestamp, IP address,
-        and DirPort.
-        """
-        self.makeRLine(nick='missingAfterDesc', ts=False, ip=False, dirp=False)
-        fields = networkstatus.parseRLine(self.line)
-        self.assertAllFieldsAreNone(fields)
-
-    def test_missingAfterIdent(self):
-        """Test a line that and is missing the descriptor digest and
-        everything after it, i.e. the timestamp, IP address, and DirPort.
-        """
-        self.makeRLine(nick='noDesc', desc=False, ts=False,
-                       ip=False, dirp=False)
-        fields = networkstatus.parseRLine(self.line)
-        self.assertAllFieldsAreNone(fields)
-
-    def test_invalidTimestamp(self):
-        """Test line with two large integers for the timestamp."""
-        self.makeRLine(ts='123456789 987654321')
-        fields = networkstatus.parseRLine(self.line)
-        nick, ident, desc, ts, ip, port = fields[:6]
-
-        the(nick).should.be.equal(self.nick)
-        the(ident).should.be.equal(self.rawIdent)
-
-        # descDigest is set to `None` if there is an error while parsing:
-        the(desc).should.be(None)
-        the(ts).should.be(None)
-        the(ip).should.be(None)
-
-    def test_invalidTimestampMissingDate(self):
-        """Test a line where the timestamp is missing the date portion."""
-        self.makeRLine(ts='15:15:15')
-        fields = networkstatus.parseRLine(self.line)
-        self.assertAllFieldsAreNone(fields)
-
-    def test_invalidIPAddress(self):
-        """Test a line with an invalid IP address."""
-        self.makeRLine(ip='0.0.0.0')
-        fields = networkstatus.parseRLine(self.line)
-        nick, ident, desc, ts, ip, port = fields[:6]
-
-        the(nick).should.be.equal(self.nick)
-        the(ident).should.be.equal(self.rawIdent)
-
-        # descDigest is set to `None` if there is an error while parsing:
-        the(desc).should.be(None)
-        the(ts).should.be(None)
-        the(ip).should.be(None)
-
-    def test_valid(self):
-        """Test a valid 'r'-line."""
-        self.makeRLine()
-        fields = networkstatus.parseRLine(self.line)
-        nick, ident, desc, ts, ip, port = fields[:6]
-        the(nick).should.be.equal(self.nick)
-        the(ident).should.be.equal(self.rawIdent)
-        the(desc).should.be.equal(self.rawDesc)
-        the(ts).should.be.ok
-        the(ip).should.be.ok
-
-
-class ParseNetworkStatusALineTests(unittest.TestCase):
-    """Tests for :func:`bridgedb.parse.networkstatus.parseALine`.
-
-    The documentation for all class variables, e.g. 'pre' or 'oraddr', refers
-    to what said value should be in a *valid* descriptor.
-    """
-    #: The prefix for the 'a'-line. Should be an 'a', unless testing that
-    #: lines with unknown prefixes are dropped.
-    pre = 'a '
-    #: An ORAddress. As of tor-0.2.5.1-alpha, there is only one and it is an
-    #: IPv6 address.
-    oraddr = '[b8d:48ae:5185:dad:5c2a:4e75:8394:f5f8]'
-
-    def tearDown(self):
-        self.line = ''
-
-    def assertAllFieldsAreNone(self, fields):
-        """Assert that every field in the iterable ``fields`` is None."""
-        for field in fields:
-            self.assertTrue(field is None)
-
-    def test_missingPrefix(self):
-        """Changed to allow a missing 'a' prefix in branch
-        ``hotfix/9462B-netstatus-returns-None``.
-        """
-        self.line = '%s:1234' % self.oraddr
-        ip, port = networkstatus.parseALine(self.line)
-        this(ip).should.be.a(basestring)
-        this(port).should.be(None)
-
-    def test_IPv4(self):
-        self.line = 'a 48.32.199.45:9001'
-        ip, port = networkstatus.parseALine(self.line)
-        ip, port = self.assertWarns(
-            FutureWarning,
-            "Got IPv4 address in networkstatus 'a'-line! "\
-            "Networkstatus document format may have changed!",
-            networkstatus.__file__,
-            networkstatus.parseALine,
-            self.line)
-        this(ip).should.be.a(basestring)
-        this(port).should.be.ok
-        this(port).should.be.a(networkstatus.addr.PortList)
-
-    def test_IPv4BadPortSeparator(self):
-        self.line = 'a 1.1.1.1 9001'
-        fields = networkstatus.parseALine(self.line)
-        self.assertAllFieldsAreNone(fields)
-
-    def test_IPv6BadPortlist(self):
-        self.line = 'a 23.23.23.23:1111,2222,badportlist'
-        ip, port = networkstatus.parseALine(self.line)
-        this(ip).should.be.a(basestring)
-        this(port).should.be(None)
-
-    def test_IPv4MissingPort(self):
-        self.line = 'a 1.1.1.1'
-        fields = networkstatus.parseALine(self.line)
-        self.assertAllFieldsAreNone(fields)
-
-    def test_IPv4InvalidAddress(self):
-        self.line = 'a 127.0.0.1:5555'
-        fields = networkstatus.parseALine(self.line)
-        self.assertAllFieldsAreNone(fields)
-
-    def test_IPv6BadPortSeparator(self):
-        self.line = 'a %s missingcolon' % self.oraddr
-        fields = networkstatus.parseALine(self.line)
-        self.assertAllFieldsAreNone(fields)
-
-    def test_IPv6BadPortlist(self):
-        self.line = 'a %s:1111,2222,badportlist' % self.oraddr
-        ip, port = networkstatus.parseALine(self.line)
-        this(ip).should.be.a(basestring)
-        this(port).should.be(None)
-
-    def test_IPv6(self):
-        self.line = 'a %s:6004' % self.oraddr
-        ip, port = networkstatus.parseALine(self.line)
-        this(ip).should.be.a(basestring)
-        this(port).should.be.ok
-        this(port).should.be.a(networkstatus.addr.PortList)
-
-
-class ParseNetworkStatusSLineTests(unittest.TestCase):
-    """Tests for :func:`bridgedb.parse.networkstatus.parseSLine`."""
-
-    def tearDown(self):
-        """Automatically called after each test_* method to run cleanups."""
-        self.line = ''
-
-    def test_missingPrefix(self):
-        self.line = 'Stable'
-        running, stable = networkstatus.parseSLine(self.line)
-        self.assertFalse(running)
-        self.assertFalse(stable)
-
-    def test_makeBelieveFlag(self):
-        """Test that 's'-parser should ignore a 'MakeBelieve' flag."""
-        self.line = 's Stable Running MakeBelieve BadExit'
-        running, stable = networkstatus.parseSLine(self.line)
-        self.assertTrue(running)
-        self.assertTrue(stable)
-
-    def test_noFlags(self):
-        """Test that an 's'-line with no flags returns False for everything."""
-        self.line = ''
-        running, stable = networkstatus.parseSLine(self.line)
-        self.assertFalse(running)
-        self.assertFalse(stable)





More information about the tor-commits mailing list