def test_handlers(self): """ Try parsing a document with DocumentHandler.DOCUMENT and DocumentHandler.BARE_DOCUMENT. """ # Simple sanity check that they provide the right type, and that the # document includes or excludes the router status entries as appropriate. entry1 = get_router_status_entry_v3({'s': 'Fast'}) entry2 = get_router_status_entry_v3({ 'r': 'Nightfae AWt0XNId/OU2xX5xs5hVtDc5Mes 6873oEfM7fFIbxYtwllw9GPDwkA 2013-02-20 11:12:27 85.177.66.233 9001 9030', 's': 'Valid', }) content = get_network_status_document_v3(routers = (entry1, entry2), content = True) 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)) self.assertTrue(isinstance(descriptors[0], NetworkStatusDocumentV3)) self.assertEqual(2, len(descriptors[0].routers)) descriptors = list(stem.descriptor.parse_file(io.BytesIO(content), 'network-status-consensus-3 1.0', document_handler = stem.descriptor.DocumentHandler.BARE_DOCUMENT)) self.assertEqual(1, len(descriptors)) self.assertTrue(isinstance(descriptors[0], NetworkStatusDocumentV3)) self.assertEqual(0, len(descriptors[0].routers))
def test_examples(self): """ Run something similar to the examples in the header pydocs. """ # makes a consensus with a couple routers, both with the same nickname entry1 = get_router_status_entry_v3({'s': 'Fast'}) entry2 = get_router_status_entry_v3({'s': 'Valid'}) content = get_network_status_document_v3(routers = (entry1, entry2), content = True) # first example: parsing via the NetworkStatusDocumentV3 constructor consensus_file = io.BytesIO(content) consensus = NetworkStatusDocumentV3(consensus_file.read()) consensus_file.close() for router in consensus.routers.values(): self.assertEqual('caerSidi', router.nickname) # second example: using stem.descriptor.parse_file with io.BytesIO(content) as consensus_file: for router in stem.descriptor.parse_file(consensus_file, 'network-status-consensus-3 1.0'): self.assertEqual('caerSidi', router.nickname)
def test_flags(self): """ Handles a variety of flag inputs. """ test_values = { "": [], "Fast": [Flag.FAST], "Fast Valid": [Flag.FAST, Flag.VALID], "Ugabuga": ["Ugabuga"], } for s_line, expected in test_values.items(): entry = get_router_status_entry_v3({'s': s_line}) self.assertEquals(expected, entry.flags) # tries some invalid inputs test_values = { "Fast ": [Flag.FAST, "", "", ""], "Fast Valid": [Flag.FAST, "", Flag.VALID], "Fast Fast": [Flag.FAST, Flag.FAST], } for s_line, expected in test_values.items(): content = get_router_status_entry_v3({'s': s_line}, content=True) self._expect_invalid_attr(content, "flags", expected)
def test_flags(self): """ Handles a variety of flag inputs. """ test_values = { "": [], "Fast": [Flag.FAST], "Fast Valid": [Flag.FAST, Flag.VALID], "Ugabuga": ["Ugabuga"], } for s_line, expected in test_values.items(): entry = get_router_status_entry_v3({'s': s_line}) self.assertEquals(expected, entry.flags) # tries some invalid inputs test_values = { "Fast ": [Flag.FAST, "", "", ""], "Fast Valid": [Flag.FAST, "", Flag.VALID], "Fast Fast": [Flag.FAST, Flag.FAST], } for s_line, expected in test_values.items(): content = get_router_status_entry_v3({'s': s_line}, content = True) self._expect_invalid_attr(content, "flags", expected)
def test_with_router_status_entries(self): """ Includes router status entries within the document. This isn't to test the RouterStatusEntry parsing but rather the inclusion of it within the document. """ entry1 = get_router_status_entry_v3({'s': "Fast"}) entry2 = get_router_status_entry_v3({ 'r': "Nightfae AWt0XNId/OU2xX5xs5hVtDc5Mes 6873oEfM7fFIbxYtwllw9GPDwkA 2013-02-20 11:12:27 85.177.66.233 9001 9030", 's': "Valid", }) document = get_network_status_document_v3(routers = (entry1, entry2)) self.assertTrue(entry1 in document.routers.values()) self.assertTrue(entry2 in document.routers.values()) # try with an invalid RouterStatusEntry entry3 = RouterStatusEntryV3(get_router_status_entry_v3({'r': "ugabuga"}, content = True), False) content = get_network_status_document_v3(routers = (entry3,), content = True) self.assertRaises(ValueError, NetworkStatusDocumentV3, content) document = NetworkStatusDocumentV3(content, False) self.assertEquals([entry3], document.routers.values()) # try including with a microdescriptor consensus content = get_network_status_document_v3({"network-status-version": "3 microdesc"}, routers = (entry1,), content = True) self.assertRaises(ValueError, NetworkStatusDocumentV3, content) document = NetworkStatusDocumentV3(content, False) self.assertEqual([RouterStatusEntryMicroV3(str(entry1), False)], document.routers.values())
def test_bandwidth(self): """ Handles a variety of 'w' lines. """ test_values = { "Bandwidth=0": (0, None, []), "Bandwidth=63138": (63138, None, []), "Bandwidth=11111 Measured=482": (11111, 482, []), "Bandwidth=11111 Measured=482 Blarg!": (11111, 482, ["Blarg!"]), } for w_line, expected in test_values.items(): entry = get_router_status_entry_v3({'w': w_line}) self.assertEquals(expected[0], entry.bandwidth) self.assertEquals(expected[1], entry.measured) self.assertEquals(expected[2], entry.unrecognized_bandwidth_entries) # tries some invalid inputs test_values = ( "", "blarg", "Bandwidth", "Bandwidth=", "Bandwidth:0", "Bandwidth 0", "Bandwidth=-10", "Bandwidth=10 Measured", "Bandwidth=10 Measured=", "Bandwidth=10 Measured=-50", ) for w_line in test_values: content = get_router_status_entry_v3({'w': w_line}, content = True) self._expect_invalid_attr(content)
def test_handlers(self): """ Try parsing a document with DocumentHandler.DOCUMENT and DocumentHandler.BARE_DOCUMENT. """ # Simple sanity check that they provide the right type, and that the # document includes or excludes the router status entries as appropriate. entry1 = get_router_status_entry_v3({'s': "Fast"}) entry2 = get_router_status_entry_v3({'s': "Valid"}) content = get_network_status_document_v3(routers=(entry1, entry2), content=True) descriptors = list( stem.descriptor.parse_file( StringIO.StringIO(content), 'network-status-consensus-3 1.0', document_handler=stem.descriptor.DocumentHandler.DOCUMENT)) self.assertEqual(1, len(descriptors)) self.assertTrue(isinstance(descriptors[0], NetworkStatusDocumentV3)) self.assertEqual(2, len(descriptors[0].routers)) descriptors = list( stem.descriptor.parse_file(StringIO.StringIO(content), 'network-status-consensus-3 1.0', document_handler=stem.descriptor. DocumentHandler.BARE_DOCUMENT)) self.assertEqual(1, len(descriptors)) self.assertTrue(isinstance(descriptors[0], NetworkStatusDocumentV3)) self.assertEqual(0, len(descriptors[0].routers))
def test_handlers(self): """ Try parsing a document with DocumentHandler.DOCUMENT and DocumentHandler.BARE_DOCUMENT. """ # Simple sanity check that they provide the right type, and that the # document includes or excludes the router status entries as appropriate. entry1 = get_router_status_entry_v3({'s': "Fast"}) entry2 = get_router_status_entry_v3({ 'r': "Nightfae AWt0XNId/OU2xX5xs5hVtDc5Mes 6873oEfM7fFIbxYtwllw9GPDwkA 2013-02-20 11:12:27 85.177.66.233 9001 9030", 's': "Valid", }) content = get_network_status_document_v3(routers = (entry1, entry2), content = True) 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)) self.assertTrue(isinstance(descriptors[0], NetworkStatusDocumentV3)) self.assertEqual(2, len(descriptors[0].routers)) descriptors = list(stem.descriptor.parse_file(io.BytesIO(content), 'network-status-consensus-3 1.0', document_handler = stem.descriptor.DocumentHandler.BARE_DOCUMENT)) self.assertEqual(1, len(descriptors)) self.assertTrue(isinstance(descriptors[0], NetworkStatusDocumentV3)) self.assertEqual(0, len(descriptors[0].routers))
def test_examples(self): """ Run something similar to the examples in the header pydocs. """ # makes a consensus with a couple routers, both with the same nickname entry1 = get_router_status_entry_v3({'s': "Fast"}) entry2 = get_router_status_entry_v3({'s': "Valid"}) content = get_network_status_document_v3(routers=(entry1, entry2), content=True) # first example: parsing via the NetworkStatusDocumentV3 constructor consensus_file = StringIO.StringIO(content) consensus = NetworkStatusDocumentV3(consensus_file.read()) consensus_file.close() for router in consensus.routers: self.assertEqual('caerSidi', router.nickname) # second example: using stem.descriptor.parse_file with support_with(StringIO.StringIO(content)) as consensus_file: for router in stem.descriptor.parse_file( consensus_file, 'network-status-consensus-3 1.0'): self.assertEqual('caerSidi', router.nickname)
def test_flags(self): """ Handles a variety of flag inputs. """ test_values = { '': [], 'Fast': [Flag.FAST], 'Fast Valid': [Flag.FAST, Flag.VALID], 'Ugabuga': ['Ugabuga'], } for s_line, expected in test_values.items(): entry = get_router_status_entry_v3({'s': s_line}) self.assertEquals(expected, entry.flags) # tries some invalid inputs test_values = { 'Fast ': [Flag.FAST, '', '', ''], 'Fast Valid': [Flag.FAST, '', Flag.VALID], 'Fast Fast': [Flag.FAST, Flag.FAST], } for s_line, expected in test_values.items(): content = get_router_status_entry_v3({'s': s_line}, content=True) self._expect_invalid_attr(content, 'flags', expected)
def test_exit_policy(self): """ Handles a variety of 'p' lines. """ test_values = { 'reject 1-65535': MicroExitPolicy('reject 1-65535'), 'accept 80,110,143,443': MicroExitPolicy('accept 80,110,143,443'), } for p_line, expected in test_values.items(): entry = get_router_status_entry_v3({'p': p_line}) self.assertEqual(expected, entry.exit_policy) # tries some invalid inputs test_values = ( '', 'blarg', 'reject -50', 'accept 80,', ) for p_line in test_values: content = get_router_status_entry_v3({'p': p_line}, content = True) self._expect_invalid_attr(content, 'exit_policy')
def test_exit_policy(self): """ Handles a variety of 'p' lines. """ test_values = { 'reject 1-65535': MicroExitPolicy('reject 1-65535'), 'accept 80,110,143,443': MicroExitPolicy('accept 80,110,143,443'), } for p_line, expected in test_values.items(): entry = get_router_status_entry_v3({'p': p_line}) self.assertEquals(expected, entry.exit_policy) # tries some invalid inputs test_values = ( '', 'blarg', 'reject -50', 'accept 80,', ) for p_line in test_values: content = get_router_status_entry_v3({'p': p_line}, content=True) self._expect_invalid_attr(content, 'exit_policy')
def test_flags(self): """ Handles a variety of flag inputs. """ test_values = { '': [], 'Fast': [Flag.FAST], 'Fast Valid': [Flag.FAST, Flag.VALID], 'Ugabuga': ['Ugabuga'], } for s_line, expected in test_values.items(): entry = get_router_status_entry_v3({'s': s_line}) self.assertEqual(expected, entry.flags) # tries some invalid inputs test_values = { 'Fast ': [Flag.FAST, '', '', ''], 'Fast Valid': [Flag.FAST, '', Flag.VALID], 'Fast Fast': [Flag.FAST, Flag.FAST], } for s_line, expected in test_values.items(): content = get_router_status_entry_v3({'s': s_line}, content = True) self._expect_invalid_attr(content, 'flags', expected)
def test_with_router_status_entries(self): """ Includes router status entries within the document. This isn't to test the RouterStatusEntry parsing but rather the inclusion of it within the document. """ entry1 = get_router_status_entry_v3({'s': 'Fast'}) entry2 = get_router_status_entry_v3({ 'r': 'Nightfae AWt0XNId/OU2xX5xs5hVtDc5Mes 6873oEfM7fFIbxYtwllw9GPDwkA 2013-02-20 11:12:27 85.177.66.233 9001 9030', 's': 'Valid', }) document = get_network_status_document_v3(routers = (entry1, entry2)) self.assertTrue(entry1 in document.routers.values()) self.assertTrue(entry2 in document.routers.values()) # try with an invalid RouterStatusEntry entry3 = RouterStatusEntryV3(get_router_status_entry_v3({'r': 'ugabuga'}, content = True), False) content = get_network_status_document_v3(routers = (entry3,), content = True) self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True) document = NetworkStatusDocumentV3(content, False) self.assertEqual([entry3], list(document.routers.values())) # try including with a microdescriptor consensus content = get_network_status_document_v3({'network-status-version': '3 microdesc'}, routers = (entry1,), content = True) self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True) document = NetworkStatusDocumentV3(content, False) self.assertEqual([RouterStatusEntryMicroV3(str(entry1), False)], list(document.routers.values()))
def test_exit_policy(self): """ Handles a variety of 'p' lines. """ test_values = { "reject 1-65535": MicroExitPolicy("reject 1-65535"), "accept 80,110,143,443": MicroExitPolicy("accept 80,110,143,443"), } for p_line, expected in test_values.items(): entry = get_router_status_entry_v3({'p': p_line}) self.assertEquals(expected, entry.exit_policy) # tries some invalid inputs test_values = ( "", "blarg", "reject -50", "accept 80,", ) for p_line in test_values: content = get_router_status_entry_v3({'p': p_line}, content=True) self._expect_invalid_attr(content, "exit_policy")
def test_votes_by_bandwidth_authorities(self, query_mock, get_authorities_mock, stdout_mock): directory_values = [ DIRECTORY_AUTHORITIES['gabelmoo'], DIRECTORY_AUTHORITIES['tor26'], DIRECTORY_AUTHORITIES['moria1'], DIRECTORY_AUTHORITIES['maatuska'], ] directory_values[0].address = '131.188.40.189' get_authorities_mock().values.return_value = directory_values entry_with_measurement = get_router_status_entry_v3({'w': 'Bandwidth=1 Measured=1'}) entry_without_measurement = get_router_status_entry_v3() query1 = Mock() query1.download_url = 'http://131.188.40.189:80/tor/status-vote/current/authority' query1.run.return_value = [entry_with_measurement] * 5935 + [entry_without_measurement] * 1332 query2 = Mock() query2.download_url = 'http://86.59.21.38:80/tor/status-vote/current/authority' query2.run.return_value = [entry_with_measurement] * 5735 + [entry_without_measurement] * 1690 query3 = Mock() query3.download_url = 'http://128.31.0.39:9131/tor/status-vote/current/authority' query3.run.return_value = [entry_with_measurement] * 6647 + [entry_without_measurement] * 625 query4 = Mock() query4.download_url = 'http://171.25.193.9:443/tor/status-vote/current/authority' query4.run.return_value = [entry_with_measurement] * 6313 + [entry_without_measurement] * 1112 query_mock.side_effect = [query1, query2, query3, query4] exec_documentation_example('votes_by_bandwidth_authorities.py') self.assert_equal_unordered(VOTES_BY_BANDWIDTH_AUTHORITIES_OUTPUT, stdout_mock.getvalue())
def test_exit_policy(self): """ Handles a variety of 'p' lines. """ test_values = { "reject 1-65535": MicroExitPolicy("reject 1-65535"), "accept 80,110,143,443": MicroExitPolicy("accept 80,110,143,443"), } for p_line, expected in test_values.items(): entry = get_router_status_entry_v3({'p': p_line}) self.assertEquals(expected, entry.exit_policy) # tries some invalid inputs test_values = ( "", "blarg", "reject -50", "accept 80,", ) for p_line in test_values: content = get_router_status_entry_v3({'p': p_line}, content = True) self._expect_invalid_attr(content, "exit_policy")
def test_new_consensus_event(self): expected_desc = [] expected_desc.append( mocking.get_router_status_entry_v3( { "r": "Beaver /96bKo4soysolMgKn5Hex2nyFSY pAJH9dSBp/CG6sPhhVY/5bLaVPM 2012-12-02 22:02:45 77.223.43.54 9001 0", "s": "Fast Named Running Stable Valid", } ) ) expected_desc.append( mocking.get_router_status_entry_v3( { "r": "Unnamed /+fJRWjmIGNAL2C5rRZHq3R91tA 7AnpZjfdBpYzXnMNm+w1bTsFF6Y 2012-12-02 17:51:10 91.121.184.87 9001 0", "s": "Fast Guard Running Stable Valid", } ) ) event = _get_event(NEWCONSENSUS_EVENT) self.assertTrue(isinstance(event, stem.response.events.NewConsensusEvent)) self.assertEqual(expected_desc, event.desc)
def test_with_router_status_entries(self): """ Includes router status entries within the document. This isn't to test the RouterStatusEntry parsing but rather the inclusion of it within the document. """ entry1 = get_router_status_entry_v3({'s': "Fast"}) entry2 = get_router_status_entry_v3({'s': "Valid"}) document = get_network_status_document_v3(routers = (entry1, entry2)) self.assertEquals((entry1, entry2), document.routers) # try with an invalid RouterStatusEntry entry3 = RouterStatusEntryV3(get_router_status_entry_v3({'r': "ugabuga"}, content = True), False) content = get_network_status_document_v3(routers = (entry3,), content = True) self.assertRaises(ValueError, NetworkStatusDocumentV3, content) document = NetworkStatusDocumentV3(content, False) self.assertEquals((entry3,), document.routers) # try including with a microdescriptor consensus content = get_network_status_document_v3({"network-status-version": "3 microdesc"}, routers = (entry1, entry2), content = True) self.assertRaises(ValueError, NetworkStatusDocumentV3, content) expected_routers = ( RouterStatusEntryMicroV3(str(entry1), False), RouterStatusEntryMicroV3(str(entry2), False), ) document = NetworkStatusDocumentV3(content, False) self.assertEquals(expected_routers, document.routers)
def test_examples(self): """ Run something similar to the examples in the header pydocs. """ # makes a consensus with a couple routers, both with the same nickname entry1 = get_router_status_entry_v3({'s': "Fast"}) entry2 = get_router_status_entry_v3({'s': "Valid"}) content = get_network_status_document_v3(routers = (entry1, entry2), content = True) # first example: parsing via the NetworkStatusDocumentV3 constructor consensus_file = StringIO.StringIO(content) consensus = NetworkStatusDocumentV3(consensus_file.read()) consensus_file.close() for router in consensus.routers: self.assertEqual('caerSidi', router.nickname) # second example: using parse_file with support_with(StringIO.StringIO(content)) as consensus_file: for router in parse_file(consensus_file): self.assertEqual('caerSidi', router.nickname)
def test_microdescriptor_hashes(self): """ Handles a variety of 'm' lines. """ test_values = { '8,9,10,11,12': [([8, 9, 10, 11, 12], {})], '8,9,10,11,12 sha256=g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs': [([8, 9, 10, 11, 12], { 'sha256': 'g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs' })], '8,9,10,11,12 sha256=g1vx9si329muxV md5=3tquWIXXySNOIwRGMeAESKs/v4DWs': [([8, 9, 10, 11, 12], { 'sha256': 'g1vx9si329muxV', 'md5': '3tquWIXXySNOIwRGMeAESKs/v4DWs' })], } for m_line, expected in test_values.items(): content = get_router_status_entry_v3({'m': m_line}, content=True) entry = RouterStatusEntryV3(content, document=vote_document()) self.assertEqual(expected, entry.microdescriptor_hashes) # try with multiple 'm' lines content = get_router_status_entry_v3(content=True) content += b'\nm 11,12 sha256=g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs' content += b'\nm 31,32 sha512=g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs' expected = [ ([11, 12], { 'sha256': 'g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs' }), ([31, 32], { 'sha512': 'g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs' }), ] entry = RouterStatusEntryV3(content, document=vote_document()) self.assertEqual(expected, entry.microdescriptor_hashes) # try without a document content = get_router_status_entry_v3({'m': '8,9,10,11,12'}, content=True) self._expect_invalid_attr(content, 'microdescriptor_hashes', expected_value=[]) # tries some invalid inputs test_values = ( '', '4,a,2', '1,2,3 stuff', ) for m_line in test_values: content = get_router_status_entry_v3({'m': m_line}, content=True) self.assertRaises(ValueError, RouterStatusEntryV3, content, True, vote_document())
def test_microdescriptor_hashes(self): """ Handles a variety of 'm' lines. """ test_values = { '8,9,10,11,12': [([8, 9, 10, 11, 12], {})], '8,9,10,11,12 sha256=g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs': [([8, 9, 10, 11, 12], {'sha256': 'g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs'})], '8,9,10,11,12 sha256=g1vx9si329muxV md5=3tquWIXXySNOIwRGMeAESKs/v4DWs': [([8, 9, 10, 11, 12], {'sha256': 'g1vx9si329muxV', 'md5': '3tquWIXXySNOIwRGMeAESKs/v4DWs'})], } # we need a document that's a vote mock_document = lambda x: x # just need anything with a __dict__ setattr(mock_document, 'is_vote', True) setattr(mock_document, 'is_consensus', False) for m_line, expected in test_values.items(): content = get_router_status_entry_v3({'m': m_line}, content = True) entry = RouterStatusEntryV3(content, document = mock_document) self.assertEqual(expected, entry.microdescriptor_hashes) # try with multiple 'm' lines content = get_router_status_entry_v3(content = True) content += b'\nm 11,12 sha256=g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs' content += b'\nm 31,32 sha512=g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs' expected = [ ([11, 12], {'sha256': 'g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs'}), ([31, 32], {'sha512': 'g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs'}), ] entry = RouterStatusEntryV3(content, document = mock_document) self.assertEqual(expected, entry.microdescriptor_hashes) # try without a document content = get_router_status_entry_v3({'m': '8,9,10,11,12'}, content = True) self._expect_invalid_attr(content, 'microdescriptor_hashes', expected_value = []) # tries some invalid inputs test_values = ( '', '4,a,2', '1,2,3 stuff', ) for m_line in test_values: content = get_router_status_entry_v3({'m': m_line}, content = True) self.assertRaises(ValueError, RouterStatusEntryV3, content, True, mock_document)
def test_microdescriptor_hashes(self): """ Handles a variety of 'm' lines. """ test_values = { "8,9,10,11,12": [([8, 9, 10, 11, 12], {})], "8,9,10,11,12 sha256=g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs": [([8, 9, 10, 11, 12], {"sha256": "g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs"})], "8,9,10,11,12 sha256=g1vx9si329muxV md5=3tquWIXXySNOIwRGMeAESKs/v4DWs": [([8, 9, 10, 11, 12], {"sha256": "g1vx9si329muxV", "md5": "3tquWIXXySNOIwRGMeAESKs/v4DWs"})], } # we need a document that's a vote mock_document = lambda x: x # just need anything with a __dict__ setattr(mock_document, "is_vote", True) setattr(mock_document, "is_consensus", False) for m_line, expected in test_values.items(): content = get_router_status_entry_v3({'m': m_line}, content = True) entry = RouterStatusEntryV3(content, document = mock_document) self.assertEquals(expected, entry.microdescriptor_hashes) # try with multiple 'm' lines content = get_router_status_entry_v3(content = True) content += "\nm 11,12 sha256=g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs" content += "\nm 31,32 sha512=g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs" expected = [ ([11, 12], {"sha256": "g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs"}), ([31, 32], {"sha512": "g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs"}), ] entry = RouterStatusEntryV3(content, document = mock_document) self.assertEquals(expected, entry.microdescriptor_hashes) # try without a document content = get_router_status_entry_v3({'m': "8,9,10,11,12"}, content = True) self._expect_invalid_attr(content, "microdescriptor_hashes", expected_value = []) # tries some invalid inputs test_values = ( "", "4,a,2", "1,2,3 stuff", ) for m_line in test_values: content = get_router_status_entry_v3({'m': m_line}, content = True) self.assertRaises(ValueError, RouterStatusEntryV3, content, True, mock_document)
def test_microdescriptor_hashes(self): """ Handles a variety of 'm' lines. """ test_values = { "8,9,10,11,12": [([8, 9, 10, 11, 12], {})], "8,9,10,11,12 sha256=g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs": [([8, 9, 10, 11, 12], {"sha256": "g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs"})], "8,9,10,11,12 sha256=g1vx9si329muxV md5=3tquWIXXySNOIwRGMeAESKs/v4DWs": [([8, 9, 10, 11, 12], {"sha256": "g1vx9si329muxV", "md5": "3tquWIXXySNOIwRGMeAESKs/v4DWs"})], } # we need a document that's a vote mock_document = lambda x: x # just need anything with a __dict__ setattr(mock_document, "is_vote", True) setattr(mock_document, "is_consensus", False) for m_line, expected in test_values.items(): content = get_router_status_entry_v3({'m': m_line}, content = True) entry = RouterStatusEntryV3(content, document = mock_document) self.assertEquals(expected, entry.microdescriptor_hashes) # try with multiple 'm' lines content = get_router_status_entry_v3(content = True) content += b"\nm 11,12 sha256=g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs" content += b"\nm 31,32 sha512=g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs" expected = [ ([11, 12], {"sha256": "g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs"}), ([31, 32], {"sha512": "g1vx9si329muxV3tquWIXXySNOIwRGMeAESKs/v4DWs"}), ] entry = RouterStatusEntryV3(content, document = mock_document) self.assertEquals(expected, entry.microdescriptor_hashes) # try without a document content = get_router_status_entry_v3({'m': "8,9,10,11,12"}, content = True) self._expect_invalid_attr(content, "microdescriptor_hashes", expected_value = []) # tries some invalid inputs test_values = ( "", "4,a,2", "1,2,3 stuff", ) for m_line in test_values: content = get_router_status_entry_v3({'m': m_line}, content = True) self.assertRaises(ValueError, RouterStatusEntryV3, content, True, mock_document)
def test_missing_fields(self): """ Parses a router status entry that's missing fields. """ content = get_router_status_entry_v3(exclude=('r', 's'), content=True) self._expect_invalid_attr(content, 'address') content = get_router_status_entry_v3(exclude=('r', ), content=True) self._expect_invalid_attr(content, 'address') content = get_router_status_entry_v3(exclude=('s', ), content=True) self._expect_invalid_attr(content, 'flags')
def test_missing_fields(self): """ Parses a router status entry that's missing fields. """ content = get_router_status_entry_v3(exclude = ('r', 's'), content = True) self._expect_invalid_attr(content, "address") content = get_router_status_entry_v3(exclude = ('r',), content = True) self._expect_invalid_attr(content, "address") content = get_router_status_entry_v3(exclude = ('s',), content = True) self._expect_invalid_attr(content, "flags")
def test_ipv6_addresses(self): """ Handles a variety of 'a' lines. """ test_values = { "[2607:fcd0:daaa:101::602c:bd62]:443": { '2607:fcd0:daaa:101::602c:bd62': [(443, 443)] }, "[2607:fcd0:daaa:101::602c:bd62]:80,443": { '2607:fcd0:daaa:101::602c:bd62': [(80, 80), (443, 443)] }, "[2607:fcd0:daaa:101::602c:bd62]:443-512": { '2607:fcd0:daaa:101::602c:bd62': [(443, 512)] }, } for a_line, expected in test_values.items(): entry = get_router_status_entry_v3({'a': a_line}) self.assertEquals(expected, entry.addresses_v6) # includes multiple 'a' lines content = get_router_status_entry_v3(content=True) content += "\na [2607:fcd0:daaa:101::602c:bd62]:80,443" content += "\na [2607:fcd0:daaa:101::602c:bd62]:512-600" content += "\na [1148:fcd0:daaa:101::602c:bd62]:80" expected = { '2607:fcd0:daaa:101::602c:bd62': [(80, 80), (443, 443), (512, 600)], '1148:fcd0:daaa:101::602c:bd62': [(80, 80)], } entry = RouterStatusEntryV3(content) self.assertEquals(expected, entry.addresses_v6) # tries some invalid inputs test_values = ( "", "127.0.0.1:80", "[1148:fcd0:daaa:101::602c:bd62]:80000", ) for a_line in test_values: content = get_router_status_entry_v3({'a': a_line}, content=True) self._expect_invalid_attr(content, expected_value={})
def test_persisting_a_consensus(self, query_mock, open_mock, parse_file_mock, stdout_mock): def tutorial_example_1(): from stem.descriptor import DocumentHandler from stem.descriptor.remote import DescriptorDownloader downloader = DescriptorDownloader() consensus = downloader.get_consensus(document_handler = DocumentHandler.DOCUMENT).run()[0] with open('/tmp/descriptor_dump', 'w') as descriptor_file: descriptor_file.write(str(consensus)) def tutorial_example_2(): from stem.descriptor import DocumentHandler, parse_file consensus = next(parse_file( '/tmp/descriptor_dump', descriptor_type = 'network-status-consensus-3 1.0', document_handler = DocumentHandler.DOCUMENT, )) for fingerprint, relay in consensus.routers.items(): print('%s: %s' % (fingerprint, relay.nickname)) network_status = get_network_status_document_v3(routers = (get_router_status_entry_v3(),)) query_mock().run.return_value = [network_status] parse_file_mock.return_value = itertools.cycle([network_status]) tutorial_example_1() tutorial_example_2() self.assertEqual(PERSISTING_A_CONSENSUS_OUTPUT, stdout_mock.getvalue())
def test_minimal_v3(self): """ Parses a minimal v3 router status entry. """ entry = get_router_status_entry_v3() expected_flags = set( [Flag.FAST, Flag.NAMED, Flag.RUNNING, Flag.STABLE, Flag.VALID]) self.assertEqual(None, entry.document) self.assertEqual('caerSidi', entry.nickname) self.assertEqual('A7569A83B5706AB1B1A9CB52EFF7D2D32E4553EB', entry.fingerprint) self.assertEqual('A106452D87BD7B803B6CE916291ED368DC5BD091', entry.digest) self.assertEqual(datetime.datetime(2012, 8, 6, 11, 19, 31), entry.published) self.assertEqual('71.35.150.29', entry.address) self.assertEqual(9001, entry.or_port) self.assertEqual(None, entry.dir_port) self.assertEqual(expected_flags, set(entry.flags)) self.assertEqual(None, entry.version_line) self.assertEqual(None, entry.version) self.assertEqual(None, entry.bandwidth) self.assertEqual(None, entry.measured) self.assertEqual(False, entry.is_unmeasured) self.assertEqual([], entry.unrecognized_bandwidth_entries) self.assertEqual(None, entry.exit_policy) self.assertEqual([], entry.microdescriptor_hashes) self.assertEqual([], entry.get_unrecognized_lines())
def test_persisting_a_consensus(self, query_mock, open_mock, parse_file_mock, stdout_mock): def tutorial_example_1(): from stem.descriptor import DocumentHandler from stem.descriptor.remote import DescriptorDownloader downloader = DescriptorDownloader() consensus = downloader.get_consensus(document_handler = DocumentHandler.DOCUMENT).run()[0] with open('/tmp/descriptor_dump', 'w') as descriptor_file: descriptor_file.write(str(consensus)) def tutorial_example_2(): from stem.descriptor import DocumentHandler, parse_file consensus = next(parse_file( '/tmp/descriptor_dump', descriptor_type = 'network-status-consensus-3 1.0', document_handler = DocumentHandler.DOCUMENT, )) for fingerprint, relay in consensus.routers.items(): print("%s: %s" % (fingerprint, relay.nickname)) network_status = get_network_status_document_v3(routers = (get_router_status_entry_v3(),)) query_mock().run.return_value = [network_status] parse_file_mock.return_value = itertools.cycle([network_status]) tutorial_example_1() tutorial_example_2() self.assertEqual(PERSISTING_A_CONSENSUS_OUTPUT, stdout_mock.getvalue())
def test_malformed_port(self): """ Parses an 'r' line with a malformed ORPort or DirPort. """ test_values = ( '', '-1', '399482', 'blarg', ) for value in test_values: for include_or_port in (False, True): for include_dir_port in (False, True): if not include_or_port and not include_dir_port: continue r_line = ROUTER_STATUS_ENTRY_V3_HEADER[0][1] if include_or_port: r_line = r_line.replace(' 9001 ', ' %s ' % value) if include_dir_port: r_line = r_line[:-1] + value attr = 'or_port' if include_or_port else 'dir_port' expected = int(value) if value.isdigit() else None content = get_router_status_entry_v3({'r': r_line}, content=True) self._expect_invalid_attr(content, attr, expected)
def test_persisting_a_consensus(self, query_mock, open_mock, parse_file_mock, stdout_mock): def tutorial_example_2(): from stem.descriptor import DocumentHandler, parse_file consensus = next( parse_file( '/tmp/descriptor_dump', descriptor_type='network-status-consensus-3 1.0', document_handler=DocumentHandler.DOCUMENT, )) for fingerprint, relay in consensus.routers.items(): print('%s: %s' % (fingerprint, relay.nickname)) network_status = get_network_status_document_v3( routers=(get_router_status_entry_v3(), )) query_mock().run.return_value = [network_status] parse_file_mock.return_value = itertools.cycle([network_status]) exec_documentation_example('persisting_a_consensus.py') exec_documentation_example('persisting_a_consensus_with_parse_file.py') self.assertEqual(PERSISTING_A_CONSENSUS_OUTPUT, stdout_mock.getvalue()) if os.path.exists('/tmp/descriptor_dump'): os.remove('/tmp/descriptor_dump')
def test_malformed_nickname(self): """ Parses an 'r' line with a malformed nickname. """ test_values = ( '', 'saberrider2008ReallyLongNickname', # too long '$aberrider2008', # invalid characters ) for value in test_values: r_line = ROUTER_STATUS_ENTRY_V3_HEADER[0][1].replace( 'caerSidi', value) content = get_router_status_entry_v3({'r': r_line}, content=True) # TODO: Initial whitespace is consumed as part of the keyword/value # divider. This is a bug in the case of V3 router status entries, but # proper behavior for V2 router status entries and server/extrainfo # descriptors. # # I'm inclined to leave this as-is for the moment since fixing it # requires special KEYWORD_LINE handling, and the only result of this bug # is that our validation doesn't catch the new SP restriction on V3 # entries. if value == '': value = None self._expect_invalid_attr(content, 'nickname', value)
def test_malformed_published_date(self): """ Parses an 'r' line with a malformed published date. """ test_values = ( '', '2012-08-06 11:19:', '2012-08-06 11:19:71', '2012-08-06 11::31', '2012-08-06 11:79:31', '2012-08-06 :19:31', '2012-08-06 41:19:31', '2012-08- 11:19:31', '2012-08-86 11:19:31', '2012--06 11:19:31', '2012-38-06 11:19:31', '-08-06 11:19:31', '2012-08-06 11:19:31', ) for value in test_values: r_line = ROUTER_STATUS_ENTRY_V3_HEADER[0][1].replace( '2012-08-06 11:19:31', value) content = get_router_status_entry_v3({'r': r_line}, content=True) self._expect_invalid_attr(content, 'published')
def test_mirror_mirror_on_the_wall_2(self): def tutorial_example(): from stem.descriptor import parse_file 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=[mocking.get_router_status_entry_v3()], content=True, )) mocking.support_with(test_file) test_file.name = "/home/atagar/.tor/cached-consensus" if is_python_3(): import builtins mocking.mock(open, mocking.return_value(test_file), target_module=builtins) else: mocking.mock(open, mocking.return_value(test_file)) tutorial_example() self.assertEqual( "found relay caerSidi (A7569A83B5706AB1B1A9CB52EFF7D2D32E4553EB)\n", self.stdout.getvalue())
def test_malformed_port(self): """ Parses an 'r' line with a malformed ORPort or DirPort. """ test_values = ( '', '-1', '399482', 'blarg', ) for value in test_values: for include_or_port in (False, True): for include_dir_port in (False, True): if not include_or_port and not include_dir_port: continue r_line = ROUTER_STATUS_ENTRY_V3_HEADER[0][1] if include_or_port: r_line = r_line.replace(' 9001 ', ' %s ' % value) if include_dir_port: r_line = r_line[:-1] + value attr = 'or_port' if include_or_port else 'dir_port' content = get_router_status_entry_v3({'r': r_line}, content = True) self._expect_invalid_attr(content, attr)
def test_unrecognized_lines(self): """ Parses a router status entry with new keywords. """ entry = get_router_status_entry_v3({'z': 'New tor feature: sparkly unicorns!'}) self.assertEquals(['z New tor feature: sparkly unicorns!'], entry.get_unrecognized_lines())
def test_proceeding_line(self): """ Includes content prior to the 'r' line. """ content = 'z some stuff\n' + get_router_status_entry_v3(content = True) self._expect_invalid_attr(content, "_unrecognized_lines", ['z some stuff'])
def test_minimal_v3(self): """ Parses a minimal v3 router status entry. """ entry = get_router_status_entry_v3() expected_flags = set( [Flag.FAST, Flag.NAMED, Flag.RUNNING, Flag.STABLE, Flag.VALID]) self.assertEqual(None, entry.document) self.assertEqual("caerSidi", entry.nickname) self.assertEqual("A7569A83B5706AB1B1A9CB52EFF7D2D32E4553EB", entry.fingerprint) self.assertEqual("oQZFLYe9e4A7bOkWKR7TaNxb0JE", entry.digest) self.assertEqual(datetime.datetime(2012, 8, 6, 11, 19, 31), entry.published) self.assertEqual("71.35.150.29", entry.address) self.assertEqual(9001, entry.or_port) self.assertEqual(None, entry.dir_port) self.assertEqual(expected_flags, set(entry.flags)) self.assertEqual(None, entry.version_line) self.assertEqual(None, entry.version) self.assertEqual(None, entry.bandwidth) self.assertEqual(None, entry.measured) self.assertEqual([], entry.unrecognized_bandwidth_entries) self.assertEqual(None, entry.exit_policy) self.assertEqual([], entry.microdescriptor_hashes) self.assertEqual([], entry.get_unrecognized_lines())
def test_minimal_v3(self): """ Parses a minimal v3 router status entry. """ entry = get_router_status_entry_v3() expected_flags = set([Flag.FAST, Flag.NAMED, Flag.RUNNING, Flag.STABLE, Flag.VALID]) self.assertEqual(None, entry.document) self.assertEqual("caerSidi", entry.nickname) self.assertEqual("A7569A83B5706AB1B1A9CB52EFF7D2D32E4553EB", entry.fingerprint) self.assertEqual("A106452D87BD7B803B6CE916291ED368DC5BD091", entry.digest) self.assertEqual(datetime.datetime(2012, 8, 6, 11, 19, 31), entry.published) self.assertEqual("71.35.150.29", entry.address) self.assertEqual(9001, entry.or_port) self.assertEqual(None, entry.dir_port) self.assertEqual(expected_flags, set(entry.flags)) self.assertEqual(None, entry.version_line) self.assertEqual(None, entry.version) self.assertEqual(None, entry.bandwidth) self.assertEqual(None, entry.measured) self.assertEqual(False, entry.is_unmeasured) self.assertEqual([], entry.unrecognized_bandwidth_entries) self.assertEqual(None, entry.exit_policy) self.assertEqual([], entry.microdescriptor_hashes) self.assertEqual([], entry.get_unrecognized_lines())
def test_malformed_nickname(self): """ Parses an 'r' line with a malformed nickname. """ test_values = ( "", "saberrider2008ReallyLongNickname", # too long "$aberrider2008", # invalid characters ) for value in test_values: r_line = ROUTER_STATUS_ENTRY_V3_HEADER[0][1].replace("caerSidi", value) content = get_router_status_entry_v3({'r': r_line}, content = True) # TODO: Initial whitespace is consumed as part of the keyword/value # divider. This is a bug in the case of V3 router status entries, but # proper behavior for V2 router status entries and server/extrainfo # descriptors. # # I'm inclined to leave this as-is for the moment since fixing it # requires special KEYWORD_LINE handling, and the only result of this bug # is that our validation doesn't catch the new SP restriction on V3 # entries. if value == "": value = None self._expect_invalid_attr(content, "nickname", value)
def test_malformed_published_date(self): """ Parses an 'r' line with a malformed published date. """ test_values = ( "", "2012-08-06 11:19:", "2012-08-06 11:19:71", "2012-08-06 11::31", "2012-08-06 11:79:31", "2012-08-06 :19:31", "2012-08-06 41:19:31", "2012-08- 11:19:31", "2012-08-86 11:19:31", "2012--06 11:19:31", "2012-38-06 11:19:31", "-08-06 11:19:31", "2012-08-06 11:19:31", ) for value in test_values: r_line = ROUTER_STATUS_ENTRY_V3_HEADER[0][1].replace("2012-08-06 11:19:31", value) content = get_router_status_entry_v3({'r': r_line}, content = True) self._expect_invalid_attr(content, "published")
def test_malformed_port(self): """ Parses an 'r' line with a malformed ORPort or DirPort. """ test_values = ( "", "-1", "399482", "blarg", ) for value in test_values: for include_or_port in (False, True): for include_dir_port in (False, True): if not include_or_port and not include_dir_port: continue r_line = ROUTER_STATUS_ENTRY_V3_HEADER[0][1] if include_or_port: r_line = r_line.replace(" 9001 ", " %s " % value) if include_dir_port: r_line = r_line[:-1] + value attr = "or_port" if include_or_port else "dir_port" expected = int(value) if value.isdigit() else None content = get_router_status_entry_v3({'r': r_line}, content = True) self._expect_invalid_attr(content, attr, expected)
def test_proceeding_line(self): """ Includes content prior to the 'r' line. """ content = b'z some stuff\n' + get_router_status_entry_v3(content = True) self._expect_invalid_attr(content, "_unrecognized_lines", ['z some stuff'])
def test_proceeding_line(self): """ Includes content prior to the 'r' line. """ content = b'z some stuff\n' + get_router_status_entry_v3(content = True) self.assertRaises(ValueError, RouterStatusEntryV3, content, True) self.assertEqual(['z some stuff'], RouterStatusEntryV3(content, False).get_unrecognized_lines())
def test_blank_lines(self): """ Includes blank lines, which should be ignored. """ content = get_router_status_entry_v3(content = True) + b"\n\nv Tor 0.2.2.35\n\n" entry = RouterStatusEntryV3(content) self.assertEqual("Tor 0.2.2.35", entry.version_line)
def test_blank_lines(self): """ Includes blank lines, which should be ignored. """ content = get_router_status_entry_v3(content = True) + "\n\nv Tor 0.2.2.35\n\n" entry = RouterStatusEntryV3(content) self.assertEqual("Tor 0.2.2.35", entry.version_line)
def test_new_consensus_event(self): expected_desc = [] expected_desc.append(mocking.get_router_status_entry_v3({ "r": "Beaver /96bKo4soysolMgKn5Hex2nyFSY pAJH9dSBp/CG6sPhhVY/5bLaVPM 2012-12-02 22:02:45 77.223.43.54 9001 0", "s": "Fast Named Running Stable Valid", })) expected_desc.append(mocking.get_router_status_entry_v3({ "r": "Unnamed /+fJRWjmIGNAL2C5rRZHq3R91tA 7AnpZjfdBpYzXnMNm+w1bTsFF6Y 2012-12-02 17:51:10 91.121.184.87 9001 0", "s": "Fast Guard Running Stable Valid", })) event = _get_event(NEWCONSENSUS_EVENT) self.assertTrue(isinstance(event, stem.response.events.NewConsensusEvent)) self.assertEqual(expected_desc, event.desc)
def test_bandwidth(self): """ Handles a variety of 'w' lines. """ test_values = { 'Bandwidth=0': (0, None, False, []), 'Bandwidth=63138': (63138, None, False, []), 'Bandwidth=11111 Measured=482': (11111, 482, False, []), 'Bandwidth=11111 Measured=482 Blarg!': (11111, 482, False, ['Blarg!']), 'Bandwidth=11111 Measured=482 Unmeasured=1 Blarg!': (11111, 482, True, ['Blarg!']), } for w_line, expected in test_values.items(): entry = get_router_status_entry_v3({'w': w_line}) self.assertEquals(expected[0], entry.bandwidth) self.assertEquals(expected[1], entry.measured) self.assertEquals(expected[2], entry.is_unmeasured) self.assertEquals(expected[3], entry.unrecognized_bandwidth_entries) # tries some invalid inputs test_values = ( '', 'blarg', 'Bandwidth', 'Bandwidth=', 'Bandwidth:0', 'Bandwidth 0', 'Bandwidth=-10', 'Bandwidth=10 Measured', 'Bandwidth=10 Measured=', 'Bandwidth=10 Measured=-50', 'Bandwidth=10 Measured=482 Unmeasured', 'Bandwidth=10 Measured=482 Unmeasured=', 'Bandwidth=10 Measured=482 Unmeasured=0', 'Bandwidth=10 Measured=482 Unmeasured=842', 'Bandwidth=10 Measured=482 Unmeasured=-5', ) for w_line in test_values: content = get_router_status_entry_v3({'w': w_line}, content=True) self._expect_invalid_attr(content)
def test_ipv6_addresses(self): """ Handles a variety of 'a' lines. """ test_values = { "[2607:fcd0:daaa:101::602c:bd62]:443": { '2607:fcd0:daaa:101::602c:bd62': [(443, 443)]}, "[2607:fcd0:daaa:101::602c:bd62]:80,443": { '2607:fcd0:daaa:101::602c:bd62': [(80, 80), (443, 443)]}, "[2607:fcd0:daaa:101::602c:bd62]:443-512": { '2607:fcd0:daaa:101::602c:bd62': [(443, 512)]}, } for a_line, expected in test_values.items(): entry = get_router_status_entry_v3({'a': a_line}) self.assertEquals(expected, entry.addresses_v6) # includes multiple 'a' lines content = get_router_status_entry_v3(content = True) content += "\na [2607:fcd0:daaa:101::602c:bd62]:80,443" content += "\na [2607:fcd0:daaa:101::602c:bd62]:512-600" content += "\na [1148:fcd0:daaa:101::602c:bd62]:80" expected = { '2607:fcd0:daaa:101::602c:bd62': [(80, 80), (443, 443), (512, 600)], '1148:fcd0:daaa:101::602c:bd62': [(80, 80)], } entry = RouterStatusEntryV3(content) self.assertEquals(expected, entry.addresses_v6) # tries some invalid inputs test_values = ( "", "127.0.0.1:80", "[1148:fcd0:daaa:101::602c:bd62]:80000", ) for a_line in test_values: content = get_router_status_entry_v3({'a': a_line}, content = True) self._expect_invalid_attr(content, expected_value = {})
def _get_router_status(address = None, port = None, nickname = None, fingerprint_base64 = None, s_line = None): r_line = ROUTER_STATUS_ENTRY_V3_HEADER[0][1] if address: r_line = r_line.replace('71.35.150.29', address) if port: r_line = r_line.replace('9001', port) if nickname: r_line = r_line.replace('caerSidi', nickname) if fingerprint_base64: r_line = r_line.replace('p1aag7VwarGxqctS7/fS0y5FU+s', fingerprint_base64) if s_line: return get_router_status_entry_v3({'r': r_line, 's': s_line}) else: return get_router_status_entry_v3({'r': r_line})
def test_ns_event(self): expected_desc = mocking.get_router_status_entry_v3({ "r": "whnetz dbBxYcJriTTrcxsuy4PUZcMRwCA VStM7KAIH/mXXoGDUpoGB1OXufg 2012-12-02 21:03:56 141.70.120.13 9001 9030", "s": "Fast HSDir Named Stable V2Dir Valid", }) event = _get_event(NS_EVENT) self.assertTrue(isinstance(event, stem.response.events.NetworkStatusEvent)) self.assertEqual([expected_desc], event.desc)
def test_proceeding_line(self): """ Includes content prior to the 'r' line. """ content = b'z some stuff\n' + get_router_status_entry_v3(content=True) self.assertRaises(ValueError, RouterStatusEntryV3, content, True) self.assertEqual(['z some stuff'], RouterStatusEntryV3(content, False).get_unrecognized_lines())
def test_bandwidth(self): """ Handles a variety of 'w' lines. """ test_values = { 'Bandwidth=0': (0, None, False, []), 'Bandwidth=63138': (63138, None, False, []), 'Bandwidth=11111 Measured=482': (11111, 482, False, []), 'Bandwidth=11111 Measured=482 Blarg!': (11111, 482, False, ['Blarg!']), 'Bandwidth=11111 Measured=482 Unmeasured=1 Blarg!': (11111, 482, True, ['Blarg!']), } for w_line, expected in test_values.items(): entry = get_router_status_entry_v3({'w': w_line}) self.assertEqual(expected[0], entry.bandwidth) self.assertEqual(expected[1], entry.measured) self.assertEqual(expected[2], entry.is_unmeasured) self.assertEqual(expected[3], entry.unrecognized_bandwidth_entries) # tries some invalid inputs test_values = ( '', 'blarg', 'Bandwidth', 'Bandwidth=', 'Bandwidth:0', 'Bandwidth 0', 'Bandwidth=-10', 'Bandwidth=10 Measured', 'Bandwidth=10 Measured=', 'Bandwidth=10 Measured=-50', 'Bandwidth=10 Measured=482 Unmeasured', 'Bandwidth=10 Measured=482 Unmeasured=', 'Bandwidth=10 Measured=482 Unmeasured=0', 'Bandwidth=10 Measured=482 Unmeasured=842', 'Bandwidth=10 Measured=482 Unmeasured=-5', ) for w_line in test_values: content = get_router_status_entry_v3({'w': w_line}, content = True) self._expect_invalid_attr(content)
def test_versions(self): """ Handles a variety of version inputs. """ test_values = { "Tor 0.2.2.35": Version("0.2.2.35"), "Tor 0.1.2": Version("0.1.2"), "Torr new_stuff": None, "new_stuff and stuff": None, } for v_line, expected in test_values.items(): entry = get_router_status_entry_v3({'v': v_line}) self.assertEquals(expected, entry.version) self.assertEquals(v_line, entry.version_line) # tries an invalid input content = get_router_status_entry_v3({'v': "Tor ugabuga"}, content = True) self._expect_invalid_attr(content, "version")
def test_parse_file(self): """ Try parsing a document via the _parse_file() function. """ entry1 = get_router_status_entry_v3({'s': "Fast"}) entry2 = get_router_status_entry_v3({'s': "Valid"}) content = get_network_status_document_v3(routers = (entry1, entry2), content = True) # the document that the entries refer to should actually be the minimal # descriptor (ie, without the entries) expected_document = get_network_status_document_v3() descriptor_file = io.BytesIO(content) entries = list(_parse_file(descriptor_file)) self.assertEquals(entry1, entries[0]) self.assertEquals(entry2, entries[1]) self.assertEquals(expected_document, entries[0].document)