[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [bridgedb/master] Add mock descriptors and several Bridge class unittests.
commit 7150bd19e86125bcaf48f8f48a960244047ae8b2
Author: Isis Lovecruft <isis@xxxxxxxxxxxxxx>
Date: Sun Dec 28 12:39:04 2014 +0000
Add mock descriptors and several Bridge class unittests.
---
lib/bridgedb/test/test_bridges.py | 406 +++++++++++++++++++++++++++++++++++++
1 file changed, 406 insertions(+)
diff --git a/lib/bridgedb/test/test_bridges.py b/lib/bridgedb/test/test_bridges.py
index cca920d..8328e16 100644
--- a/lib/bridgedb/test/test_bridges.py
+++ b/lib/bridgedb/test/test_bridges.py
@@ -15,6 +15,7 @@ from binascii import a2b_hex
import ipaddr
import io
import hashlib
+import os
import warnings
from twisted.trial import unittest
@@ -22,13 +23,90 @@ from twisted.trial import unittest
from bridgedb import bridges
from bridgedb.Bridges import FilteredBridgeSplitter
from bridgedb.bridgerequest import BridgeRequestBase
+from bridgedb.parse import descriptors
from bridgedb.parse.addr import PortList
+from bridgedb.parse.nickname import InvalidRouterNickname
+
# Don't print "WARNING:root: Couldn't parse K=V from PT arg: ''" a bunch of
# times while running the tests.
warnings.filterwarnings("ignore", ".*Couldn't parse K=V from PT arg.*", Warning)
+BRIDGE_NETWORKSTATUS = '''\
+r FourfoldQuirked LDIlxIBTMQJeIR9Lblv0XDM/3Sw c4EVu2rO/iD/DJYBX/Ll38DGQWI 2014-12-22 21:51:27 179.178.155.140 36489 0
+a [6bf3:806b:78cd:d4b4:f6a7:4ced:cfad:dad4]:36488
+s Fast Guard Running Stable Valid
+w Bandwidth=1585163
+p reject 1-65535
+'''
+
+BRIDGE_SERVER_DESCRIPTOR = '''\
+@purpose bridge
+router FourfoldQuirked 179.178.155.140 36489 0 0
+or-address [6bf3:806b:78cd:d4b4:f6a7:4ced:cfad:dad4]:36488
+platform Tor 0.2.3.24-rc on Linux
+opt protocols Link 1 2 Circuit 1
+published 2014-12-22 21:51:27
+opt fingerprint 2C32 25C4 8053 3102 5E21 1F4B 6E5B F45C 333F DD2C
+uptime 33200687
+bandwidth 1866688205 2110169275 1623207134
+opt extra-info-digest 4497E81715D958105C6A39D348163AD8F3080FB2
+onion-key
+-----BEGIN RSA PUBLIC KEY-----
+MIGJAoGBANKicvIGWp9WGKOJV8Fs3YKdTDrgxlggzyKgkW+MZWEPQ9lLcrmXqBdW
+nVK5EABByHnnxJfk+sm+6yDYxY/lFVL1SEP84pAK1Z21f4+grNlwox1DLyntXDdz
+BCZuRszuBYK3ncsk+ePQeUzRKQ/GZt9s/oy0IjtNbAoAoq7DKUVzAgMBAAE=
+-----END RSA PUBLIC KEY-----
+signing-key
+-----BEGIN RSA PUBLIC KEY-----
+MIGJAoGBALnJK7A9aZIp2ry9ruVYzm4VfaXzNHdTcvkXTrETu/jLXsosEwj9viSe
+Ry3W/uctbjzdwlIY0ZBUuV20q9bh+/c7Q0T8LOHBZouOy+nhFOUX+Q5YCG9cRnY0
+hBebYTzyplh0tT8xyYwcS8y6esL+gjVDLo6Og3QPhWRFQ4CyCic9AgMBAAE=
+-----END RSA PUBLIC KEY-----
+contact Somebody <somebody@xxxxxxxxxxx>
+ntor-onion-key aVmfOm9C046wM8ktGnpfBHSNj1Jm30M/m2P7W3a7Xn8
+reject *:*
+router-signature
+-----BEGIN SIGNATURE-----
+nxml4rTyTrj8dHcsFt2B4ACz2AN5CuZ2t5UF1BtXUpuzHmqVlg7imy8Cp2xIwoDa
+4uv/tTG32macauVnMHt0hSbtBF5nHfxU9G1T/XzdtL+KD8REDGky4allXnmvF6In
+rFtSn2OeZewvi8oYPmVYKgzHL6tzZxs2Sn/bOTj5sRw=
+-----END SIGNATURE-----
+'''
+
+BRIDGE_EXTRAINFO = '''\
+extra-info FourfoldQuirked 2C3225C4805331025E211F4B6E5BF45C333FDD2C
+published 2014-12-22 21:51:27
+write-history 2014-12-22 21:51:27 (900 s) 3188736,2226176,2866176
+read-history 2014-12-22 21:51:27 (900 s) 3891200,2483200,2698240
+dirreq-write-history 2014-12-22 21:51:27 (900 s) 1024,0,2048
+dirreq-read-history 2014-12-22 21:51:27 (900 s) 0,0,0
+geoip-db-digest 51AE9611B53880B2BCF9C71E735D73F33FAD2DFE
+geoip6-db-digest 26B0D55B20BEB496A3ADE7C6FDD866F5A81027F7
+dirreq-stats-end 2014-12-22 21:51:27 (86400 s)
+dirreq-v3-ips
+dirreq-v3-reqs
+dirreq-v3-resp ok=16,not-enough-sigs=0,unavailable=0,not-found=0,not-modified=0,busy=0
+dirreq-v3-direct-dl complete=0,timeout=0,running=0
+dirreq-v3-tunneled-dl complete=12,timeout=0,running=0
+transport obfs3 179.178.155.140:36490
+transport obfs2 179.178.155.140:36491
+transport scramblesuit 179.178.155.140:36492 password=ABCDEFGHIJKLMNOPQRSTUVWXYZ234567
+transport obfs4 179.178.155.140:36493 iat-mode=0,node-id=25293f2761d658cc70c19515861842d712751bdc,public-key=02d20bbd7e394ad5999a4cebabac9619732c343a4cac99470c03e23ba2bdc2bc
+bridge-stats-end 2014-12-22 21:51:27 (86400 s)
+bridge-ips ca=8
+bridge-ip-versions v4=8,v6=0
+bridge-ip-transports <OR>=8
+router-signature
+-----BEGIN SIGNATURE-----
+cn4+8pQwCMPnHcp1s8wm7ZYsnd9AXJH6ysNlvQ63jsPCG9JdE5E8BwCThEgUccJI
+XILT4o+SveEQUG72R4bENsKxqV4rRNh1g6CNAbYhAITqrU9B+jImDgrBBW+XWT5K
+78ECRPn6Y4KsxFb0TIn7ddv9QjApyBJNIDMihH80Yng=
+-----END SIGNATURE-----
+'''
+
+
class BridgeIntegrationTests(unittest.TestCase):
"""Integration tests to ensure that the new :class:`bridgedb.bridges.Bridge`
class has compatible behaviour with the expected behaviour of the old
@@ -488,3 +566,331 @@ class PluggableTransportTests(unittest.TestCase):
self.assertTrue(
("password=unicorns sharedsecret=foobar" in bridgeLine) or
("sharedsecret=foobar password=unicorns" in bridgeLine))
+
+
+class BridgeBackwardsCompatibilityTests(unittest.TestCase):
+ """Tests for :class:`bridgedb.bridges.BridgeBackwardsCompatibility`."""
+
+ def setUp(self):
+ self.nickname = "RouterNickname"
+ self.address = "23.23.23.23"
+ self.orPort = 9001
+ self.fingerprint = "0123456789ABCDEF0123456789ABCDEF01234567"
+ self.orAddresses = {"2006:42::123F": PortList(443, 9001, 1337),
+ "2006:42::123E": PortList(9001, 993)}
+
+ def test_BridgeBackwardsCompatibility_init_with_PortList(self):
+ """Test initialisation with the usual number of valid arguments and
+ PortLists for the orAddresses.
+ """
+ bridge = bridges.BridgeBackwardsCompatibility(
+ self.nickname,
+ self.address,
+ self.orPort,
+ self.fingerprint,
+ self.orAddresses)
+ self.assertIsInstance(bridge, bridges.BridgeBackwardsCompatibility)
+
+ def test_BridgeBackwardsCompatibility_init_without_PortList(self):
+ """Test initialisation with the usual number of valid arguments and
+ integers for the orAddresses' ports.
+ """
+ bridge = bridges.BridgeBackwardsCompatibility(
+ self.nickname,
+ self.address,
+ self.orPort,
+ self.fingerprint,
+ {"2006:42::123F": 443,
+ "2006:42::123E": 9001})
+ self.assertIsInstance(bridge, bridges.BridgeBackwardsCompatibility)
+
+ def test_BridgeBackwardsCompatibility_init_without_address(self):
+ """Test initialisation without an IP address."""
+ bridge = bridges.BridgeBackwardsCompatibility(
+ nickname=self.nickname,
+ orport=self.orPort,
+ fingerprint=self.fingerprint,
+ or_addresses={"2006:42::123F": 443, "2006:42::123E": 9001})
+ self.assertIsInstance(bridge, bridges.BridgeBackwardsCompatibility)
+
+ def test_BridgeBackwardsCompatibility_init_invalid_orAddresses_address(self):
+ """Test initialisation with an invalid ORAddress."""
+ bridge = bridges.BridgeBackwardsCompatibility(
+ nickname=self.nickname,
+ ip=self.address,
+ orport=self.orPort,
+ fingerprint=self.fingerprint,
+ or_addresses={"10.1.2.3": 443, "2006:42::123E": 9001})
+ self.assertIsInstance(bridge, bridges.BridgeBackwardsCompatibility)
+ self.assertEqual(len(bridge.orAddresses), 1)
+
+ def test_BridgeBackwardsCompatibility_init_invalid_orAddresses_port(self):
+ """Test initialisation with an invalid ORPort."""
+ bridge = bridges.BridgeBackwardsCompatibility(
+ nickname=self.nickname,
+ ip=self.address,
+ orport=self.orPort,
+ fingerprint=self.fingerprint,
+ or_addresses={"2006:42::123F": 443, "2006:42::123E": "anyport"})
+ self.assertIsInstance(bridge, bridges.BridgeBackwardsCompatibility)
+ self.assertEqual(len(bridge.orAddresses), 1)
+
+ def test_BridgeBackwardsCompatibility_setStatus_running(self):
+ """Using setStatus() to set the Running flag should set Bridge.running
+ and Bridge.flags.running to True.
+ """
+ bridge = bridges.BridgeBackwardsCompatibility(
+ nickname=self.nickname,
+ ip=self.address,
+ orport="anyport",
+ fingerprint=self.fingerprint,
+ or_addresses={"2006:42::123F": 443, "2006:42::123E": 9001})
+ self.assertIsInstance(bridge, bridges.BridgeBackwardsCompatibility)
+ self.assertFalse(bridge.running)
+ self.assertFalse(bridge.flags.running)
+
+ bridge.setStatus(running=True)
+ self.assertTrue(bridge.running)
+ self.assertTrue(bridge.flags.running)
+
+ def test_BridgeBackwardsCompatibility_setStatus_running(self):
+ """Using setStatus() to set the Running and Stable flags should set
+ Bridge.running, Bridge.flags.running, Bridge.stable, and
+ Bridge.flags.stable.
+ """
+ bridge = bridges.BridgeBackwardsCompatibility(
+ nickname=self.nickname,
+ ip=self.address,
+ orport="anyport",
+ fingerprint=self.fingerprint,
+ or_addresses={"2006:42::123F": 443, "2006:42::123E": 9001})
+ self.assertIsInstance(bridge, bridges.BridgeBackwardsCompatibility)
+ self.assertFalse(bridge.running)
+ self.assertFalse(bridge.flags.running)
+ self.assertFalse(bridge.stable)
+ self.assertFalse(bridge.flags.stable)
+
+ bridge.setStatus(running=True, stable=True)
+ self.assertTrue(bridge.running)
+ self.assertTrue(bridge.flags.running)
+ self.assertTrue(bridge.stable)
+ self.assertTrue(bridge.flags.stable)
+
+
+class BridgeTests(unittest.TestCase):
+ """Tests for :class:`bridgedb.bridges.Bridge`."""
+
+ def _writeDescriptorFiles(self):
+ with open(self._networkstatusFile, 'w') as fh:
+ fh.write(BRIDGE_NETWORKSTATUS)
+ fh.flush()
+
+ with open(self._serverDescriptorFile, 'w') as fh:
+ fh.write(BRIDGE_SERVER_DESCRIPTOR)
+ fh.flush()
+
+ with open(self._extrainfoFile, 'w') as fh:
+ fh.write(BRIDGE_EXTRAINFO)
+ fh.flush()
+
+ def setUp(self):
+ def _cwd(filename):
+ return os.path.sep.join([os.getcwd(), filename])
+
+ self._networkstatusFile = _cwd('BridgeTests-networkstatus-bridges')
+ self._serverDescriptorFile = _cwd('BridgeTests-bridge-descriptors')
+ self._extrainfoFile = _cwd('BridgeTests-cached-extrainfo')
+
+ self._writeDescriptorFiles()
+
+ self.networkstatus = descriptors.parseNetworkStatusFile(
+ self._networkstatusFile)[0]
+ self.serverdescriptor = descriptors.parseServerDescriptorsFile(
+ self._serverDescriptorFile)[0]
+ self.extrainfo = descriptors.parseExtraInfoFiles(
+ self._extrainfoFile).values()[0]
+
+ self.bridge = bridges.Bridge()
+
+ def tearDown(self):
+ """Reset safelogging to its default (disabled) state, due to
+ test_Bridge_str_with_safelogging changing it.
+ """
+ bridges.safelog.safe_logging = False
+
+ def test_Bridge_nickname_del(self):
+ """The del method for the nickname property should reset the nickname
+ to None.
+ """
+ self.bridge.updateFromNetworkStatus(self.networkstatus)
+ self.assertEqual(self.bridge.nickname, "FourfoldQuirked")
+
+ del(self.bridge.nickname)
+ self.assertIsNone(self.bridge.nickname)
+ self.assertIsNone(self.bridge._nickname)
+
+ def test_Bridge_nickname_invalid(self):
+ """The del method for the nickname property should reset the nickname
+ to None.
+ """
+ # Create a networkstatus descriptor with an invalid nickname:
+ filename = self._networkstatusFile + "-invalid"
+ fh = open(filename, 'w')
+ invalid = BRIDGE_NETWORKSTATUS.replace(
+ "FourfoldQuirked",
+ "ThisRouterNicknameContainsWayMoreThanNineteenBytes")
+ fh.seek(0)
+ fh.write(invalid)
+ fh.flush()
+ fh.close()
+
+ self.assertRaises(InvalidRouterNickname,
+ descriptors.parseNetworkStatusFile,
+ filename)
+
+ def test_Bridge_orport_del(self):
+ """The del method for the orPort property should reset the orPort
+ to None.
+ """
+ self.bridge.updateFromNetworkStatus(self.networkstatus)
+ self.assertEqual(self.bridge.orPort, 36489)
+
+ del(self.bridge.orPort)
+ self.assertIsNone(self.bridge.orPort)
+ self.assertIsNone(self.bridge._orPort)
+
+ def test_Bridge_str_without_safelogging(self):
+ """The str() method of a Bridge should return an identifier for the
+ Bridge, which should be different if safelogging is enabled.
+ """
+ bridges.safelog.safe_logging = False
+
+ bridge = bridges.Bridge()
+ bridge.updateFromNetworkStatus(self.networkstatus)
+
+ identifier = str(bridge)
+ self.assertEqual(identifier,
+ ''.join(['$', bridge.fingerprint,
+ '~', bridge.nickname]))
+
+ def test_Bridge_str_with_safelogging(self):
+ """The str() method of a Bridge should return an identifier for the
+ Bridge, which should be different if safelogging is enabled.
+ """
+ bridges.safelog.safe_logging = True
+
+ bridge = bridges.Bridge()
+ bridge.updateFromNetworkStatus(self.networkstatus)
+
+ identifier = str(bridge)
+ self.assertEqual(
+ identifier,
+ ''.join(['$$',
+ hashlib.sha1(bridge.fingerprint).hexdigest().upper(),
+ '~', bridge.nickname]))
+
+ def test_Bridge_str_without_fingerprint(self):
+ """The str() method of a Bridge should return an identifier for the
+ Bridge, which should be different if the fingerprint is unknown.
+ """
+ bridge = bridges.Bridge()
+ bridge.updateFromNetworkStatus(self.networkstatus)
+ del(bridge.fingerprint)
+
+ identifier = str(bridge)
+ self.assertEqual(identifier,
+ ''.join(['$', '0'*40,
+ '~', bridge.nickname]))
+
+ def test_Bridge_updateFromServerDescriptor(self):
+ """ """
+ self.bridge.updateFromNetworkStatus(self.networkstatus)
+ self.bridge.updateFromServerDescriptor(self.serverdescriptor)
+
+ self.assertEqual(self.bridge.fingerprint,
+ '2C3225C4805331025E211F4B6E5BF45C333FDD2C')
+
+ def test_Bridge_updateFromServerDescriptor_no_networkstatus(self):
+ """Parsing a server descriptor for a bridge which wasn't included in
+ the networkstatus document from the BridgeAuthority should raise a
+ ServerDescriptorWithoutNetworkstatus exception.
+ """
+ self.assertRaises(bridges.ServerDescriptorWithoutNetworkstatus,
+ self.bridge.updateFromServerDescriptor,
+ self.serverdescriptor)
+
+ def test_Bridge_updateFromExtraInfoDescriptor(self):
+ """Bridge.updateFromExtraInfoDescriptor() should add the expected
+ number of pluggable transports.
+ """
+ self.bridge.updateFromNetworkStatus(self.networkstatus)
+ self.assertEqual(self.bridge.fingerprint,
+ '2C3225C4805331025E211F4B6E5BF45C333FDD2C')
+ self.assertEqual(self.bridge.bandwidthObserved, None)
+ self.assertEqual(len(self.bridge.transports), 0)
+
+ self.bridge.updateFromServerDescriptor(self.serverdescriptor)
+ self.assertEqual(self.bridge.fingerprint,
+ '2C3225C4805331025E211F4B6E5BF45C333FDD2C')
+ self.assertEqual(self.bridge.bandwidthObserved, 1623207134)
+ self.assertEqual(len(self.bridge.transports), 0)
+
+ self.bridge.updateFromExtraInfoDescriptor(self.extrainfo)
+ self.assertEqual(self.bridge.fingerprint,
+ '2C3225C4805331025E211F4B6E5BF45C333FDD2C')
+ self.assertEqual(self.bridge.bandwidthObserved, 1623207134)
+ self.assertEqual(len(self.bridge.transports), 4)
+
+ def test_Bridge_descriptorDigest(self):
+ """Parsing a networkstatus descriptor should result in
+ Bridge.descriptorDigest being set.
+ """
+ realdigest = "738115BB6ACEFE20FF0C96015FF2E5DFC0C64162"
+ self.bridge.updateFromNetworkStatus(self.networkstatus)
+ self.assertEqual(self.bridge.descriptorDigest, realdigest)
+
+ def test_Bridge_checkServerDescriptor(self):
+ """Parsing a server descriptor when the bridge's networkstatus document
+ didn't have a digest of the server descriptor should raise a
+ MissingServerDescriptorDigest.
+ """
+ # Create a networkstatus descriptor without a server descriptor digest:
+ filename = self._networkstatusFile + "-missing-digest"
+ fh = open(filename, 'w')
+ invalid = BRIDGE_NETWORKSTATUS.replace("c4EVu2rO/iD/DJYBX/Ll38DGQWI", "foo")
+ fh.seek(0)
+ fh.write(invalid)
+ fh.flush()
+ fh.close()
+
+ realdigest = "738115BB6ACEFE20FF0C96015FF2E5DFC0C64162"
+
+ #networkstatus = descriptors.parseNetworkStatusFile(filename)
+ #self.bridge.updateFromNetworkStatus(networkstatus[0])
+ #self.assertRaises(bridges.MissingServerDescriptorDigest,
+ # self.bridge.updateFromNetworkStatus,
+ # networkstatus[0])
+
+ def test_Bridge_checkServerDescriptor_digest_mismatch(self):
+ """Parsing a server descriptor whose digest doesn't match the one given
+ in the bridge's networkstatus document should raise a
+ ServerDescriptorDigestMismatch.
+ """
+ # Create a networkstatus descriptor without a server descriptor digest:
+ filename = self._networkstatusFile + "-mismatched-digest"
+ fh = open(filename, 'w')
+ invalid = BRIDGE_NETWORKSTATUS.replace("c4EVu2rO/iD/DJYBX/Ll38DGQWI",
+ "c4EVu2r1/iD/DJYBX/Ll38DGQWI")
+ fh.seek(0)
+ fh.write(invalid)
+ fh.flush()
+ fh.close()
+
+ realdigest = "738115BB6ACEFE20FF0C96015FF2E5DFC0C64162"
+ networkstatus = descriptors.parseNetworkStatusFile(filename)
+ self.bridge.updateFromNetworkStatus(networkstatus[0])
+ #self.bridge.updateFromServerDescriptor(self.serverdescriptor)
+
+ self.assertRaises(bridges.ServerDescriptorDigestMismatch,
+ self.bridge.updateFromServerDescriptor,
+ self.serverdescriptor)
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits