def test_annotations(self): """ Checks that content before a descriptor are parsed as annotations. """ desc_text = b'@pepperjack very tasty\n@mushrooms not so much\n' desc_text += RelayDescriptor.content() desc_text += b'\ntrailing text that should be invalid, ho hum' # running _parse_file should provide an iterator with a single descriptor desc_iter = stem.descriptor.server_descriptor._parse_file( io.BytesIO(desc_text), validate=True) self.assertRaises(ValueError, list, desc_iter) desc_text = b'@pepperjack very tasty\n@mushrooms not so much\n' desc_text += RelayDescriptor.content( {'router': 'caerSidi 71.35.133.197 9001 0 0'}) desc_iter = stem.descriptor.server_descriptor._parse_file( io.BytesIO(desc_text)) desc_entries = list(desc_iter) self.assertEqual(1, len(desc_entries)) desc = desc_entries[0] self.assertEqual('caerSidi', desc.nickname) self.assertEqual(b'@pepperjack very tasty', desc.get_annotation_lines()[0]) self.assertEqual(b'@mushrooms not so much', desc.get_annotation_lines()[1]) self.assertEqual( { b'@pepperjack': b'very tasty', b'@mushrooms': b'not so much' }, desc.get_annotations()) self.assertEqual([], desc.get_unrecognized_lines())
def test_annotations(self): """ Checks that content before a descriptor are parsed as annotations. """ desc_text = b'@pepperjack very tasty\n@mushrooms not so much\n' desc_text += RelayDescriptor.content() desc_text += b'\ntrailing text that should be invalid, ho hum' # running _parse_file should provide an iterator with a single descriptor desc_iter = stem.descriptor.server_descriptor._parse_file(io.BytesIO(desc_text), validate = True) self.assertRaises(ValueError, list, desc_iter) desc_text = b'@pepperjack very tasty\n@mushrooms not so much\n' desc_text += RelayDescriptor.content({'router': 'caerSidi 71.35.133.197 9001 0 0'}) desc_iter = stem.descriptor.server_descriptor._parse_file(io.BytesIO(desc_text)) desc_entries = list(desc_iter) self.assertEqual(1, len(desc_entries)) desc = desc_entries[0] self.assertEqual('caerSidi', desc.nickname) self.assertEqual(b'@pepperjack very tasty', desc.get_annotation_lines()[0]) self.assertEqual(b'@mushrooms not so much', desc.get_annotation_lines()[1]) self.assertEqual({b'@pepperjack': b'very tasty', b'@mushrooms': b'not so much'}, desc.get_annotations()) self.assertEqual([], desc.get_unrecognized_lines())
def test_from_str_multiple(self): desc_text = b'\n'.join(( b'@type server-descriptor 1.0', RelayDescriptor.content({'router': 'relay1 71.35.133.197 9001 0 0'}), RelayDescriptor.content({'router': 'relay2 71.35.133.197 9001 0 0'}), )) self.assertEqual(2, len(RelayDescriptor.from_str(desc_text, multiple = True))) self.assertEqual(0, len(RelayDescriptor.from_str('', multiple = True))) self.assertRaisesWith(ValueError, "Descriptor.from_str() expected a single descriptor, but had 2 instead. Please include 'multiple = True' if you want a list of results instead.", RelayDescriptor.from_str, desc_text)
def test_trailing_line(self): """ Includes a line after the 'router-signature' entry. """ desc_text = RelayDescriptor.content() + b'\nhibernate 1' expect_invalid_attr_for_text(self, desc_text)
def test_proceeding_line(self): """ Includes a line prior to the 'router' entry. """ desc_text = b'hibernate 1\n' + RelayDescriptor.content() expect_invalid_attr_for_text(self, desc_text)
def test_duplicate_field(self): """ Constructs with a field appearing twice. """ desc_text = RelayDescriptor.content({'<replace>': ''}) desc_text = desc_text.replace(b'<replace>', b'contact foo\ncontact bar') expect_invalid_attr_for_text(self, desc_text, 'contact', b'foo')
def test_from_str(self): """ Basic exercise for Descriptor.from_str(). """ desc_text = RelayDescriptor.content({'router': 'caerSidi 71.35.133.197 9001 0 0'}) desc = Descriptor.from_str(desc_text, descriptor_type = 'server-descriptor 1.0') self.assertEqual('caerSidi', desc.nickname)
def test_bridge_unsanitized_relay(self): """ Checks that parsing a normal relay descriptor as a bridge will fail due to its unsanatized content. """ desc_text = RelayDescriptor.content({'router-digest': '006FD96BA35E7785A6A3B8B75FE2E2435A13BDB4'}) desc = BridgeDescriptor(desc_text) self.assertFalse(desc.is_scrubbed())
def test_platform_empty(self): """ Constructs with an empty platform entry. """ desc_text = RelayDescriptor.content({'platform': ''}) desc = RelayDescriptor(desc_text, validate=False) self.assertEqual(b'', desc.platform) # does the same but with 'platform ' replaced with 'platform' desc_text = desc_text.replace(b'platform ', b'platform') desc = RelayDescriptor(desc_text, validate=False) self.assertEqual(b'', desc.platform)
def test_platform_empty(self): """ Constructs with an empty platform entry. """ desc_text = RelayDescriptor.content({'platform': ''}) desc = RelayDescriptor(desc_text, validate = False) self.assertEqual(b'', desc.platform) # does the same but with 'platform ' replaced with 'platform' desc_text = desc_text.replace(b'platform ', b'platform') desc = RelayDescriptor(desc_text, validate = False) self.assertEqual(b'', desc.platform)
def test_mirror_mirror_on_the_wall_5(self, downloader_mock, stdout_mock): def tutorial_example(): from stem.descriptor.remote import DescriptorDownloader from stem.util import str_tools # provides a mapping of observed bandwidth to the relay nicknames def get_bw_to_relay(): bw_to_relay = {} downloader = DescriptorDownloader() try: for desc in downloader.get_server_descriptors().run(): if desc.exit_policy.is_exiting_allowed(): bw_to_relay.setdefault(desc.observed_bandwidth, []).append(desc.nickname) except Exception as exc: print('Unable to retrieve the server descriptors: %s' % exc) return bw_to_relay # prints the top fifteen relays bw_to_relay = get_bw_to_relay() count = 1 for bw_value in sorted(bw_to_relay.keys(), reverse=True): for nickname in bw_to_relay[bw_value]: print('%i. %s (%s/s)' % (count, nickname, str_tools.size_label(bw_value, 2))) count += 1 if count > 15: return exit_descriptor = RelayDescriptor.content({ 'router': 'speedyexit 149.255.97.109 9001 0 0' }).replace(b'reject *:*', b'accept *:*') exit_descriptor = RelayDescriptor(exit_descriptor) downloader_mock().get_server_descriptors().run.return_value = [ exit_descriptor, RelayDescriptor.create(), # non-exit exit_descriptor, exit_descriptor, ] tutorial_example() self.assertEqual(MIRROR_MIRROR_OUTPUT, stdout_mock.getvalue())
def test_tor_descriptors(self, stdout_mock, downloader_mock): exit_descriptor = RelayDescriptor.content({ 'router': 'speedyexit 149.255.97.109 9001 0 0' }).replace(b'reject *:*', b'accept *:*') exit_descriptor = RelayDescriptor(exit_descriptor) downloader_mock().get_server_descriptors().run.return_value = [ exit_descriptor, RelayDescriptor.create(), # non-exit exit_descriptor, exit_descriptor, ] import tor_descriptors self.assertEqual(EXPECTED_TOR_DESCRIPTORS, stdout_mock.getvalue())
def test_mirror_mirror_on_the_wall_5(self, downloader_mock, stdout_mock): def tutorial_example(): from stem.descriptor.remote import DescriptorDownloader from stem.util import str_tools # provides a mapping of observed bandwidth to the relay nicknames def get_bw_to_relay(): bw_to_relay = {} downloader = DescriptorDownloader() try: for desc in downloader.get_server_descriptors().run(): if desc.exit_policy.is_exiting_allowed(): bw_to_relay.setdefault(desc.observed_bandwidth, []).append(desc.nickname) except Exception as exc: print('Unable to retrieve the server descriptors: %s' % exc) return bw_to_relay # prints the top fifteen relays bw_to_relay = get_bw_to_relay() count = 1 for bw_value in sorted(bw_to_relay.keys(), reverse = True): for nickname in bw_to_relay[bw_value]: print('%i. %s (%s/s)' % (count, nickname, str_tools.size_label(bw_value, 2))) count += 1 if count > 15: return exit_descriptor = RelayDescriptor.content({'router': 'speedyexit 149.255.97.109 9001 0 0'}).replace(b'reject *:*', b'accept *:*') exit_descriptor = RelayDescriptor(exit_descriptor) downloader_mock().get_server_descriptors().run.return_value = [ exit_descriptor, RelayDescriptor.create(), # non-exit exit_descriptor, exit_descriptor, ] tutorial_example() self.assertEqual(MIRROR_MIRROR_OUTPUT, stdout_mock.getvalue())
def test_from_str_type_handling(self): """ Check our various methods of conveying the descriptor type. There's three: @type annotations, a descriptor_type argument, and using the from_str() of a particular subclass. """ desc_text = RelayDescriptor.content({'router': 'caerSidi 71.35.133.197 9001 0 0'}) desc = Descriptor.from_str(desc_text, descriptor_type = 'server-descriptor 1.0') self.assertEqual('caerSidi', desc.nickname) desc = Descriptor.from_str(b'@type server-descriptor 1.0\n' + desc_text) self.assertEqual('caerSidi', desc.nickname) desc = RelayDescriptor.from_str(desc_text) self.assertEqual('caerSidi', desc.nickname) self.assertRaisesWith(TypeError, "Unable to determine the descriptor's type. filename: '<undefined>', first line: 'router caerSidi 71.35.133.197 9001 0 0'", Descriptor.from_str, desc_text)
def test_missing_required_attr(self): """ Test making a descriptor with a missing required attribute. """ for attr in stem.descriptor.server_descriptor.REQUIRED_FIELDS: desc_text = RelayDescriptor.content(exclude = [attr]) self.assertRaises(ValueError, RelayDescriptor, desc_text, True) # check that we can still construct it without validation desc = RelayDescriptor(desc_text, validate = False) # for one of them checks that the corresponding values are None if attr == 'router': self.assertEqual(None, desc.nickname) self.assertEqual(None, desc.address) self.assertEqual(None, desc.or_port) self.assertEqual(None, desc.socks_port) self.assertEqual(None, desc.dir_port)
def test_missing_required_attr(self): """ Test making a descriptor with a missing required attribute. """ for attr in stem.descriptor.server_descriptor.REQUIRED_FIELDS: desc_text = RelayDescriptor.content(exclude=[attr]) self.assertRaises(ValueError, RelayDescriptor, desc_text, True) # check that we can still construct it without validation desc = RelayDescriptor(desc_text, validate=False) # for one of them checks that the corresponding values are None if attr == 'router': self.assertEqual(None, desc.nickname) self.assertEqual(None, desc.address) self.assertEqual(None, desc.or_port) self.assertEqual(None, desc.socks_port) self.assertEqual(None, desc.dir_port)
def generateDescriptors(count=None, rundir=None): """Run a script which creates fake bridge descriptors for testing purposes. :param integer count: Number of mocked bridges to generate descriptor for. (default: 3) :type rundir: string or None :param rundir: If given, use this directory as the current working directory for the bridge descriptor generator script to run in. The directory MUST already exist, and the descriptor files will be created in it. If None, use the whatever directory we are currently in. """ from stem.descriptor.server_descriptor import RelayDescriptor count = count if count else 3 rundir = rundir if rundir else os.getcwd() for i in range(count): with open(os.path.join(rundir, 'descriptor_%i' % i), 'w') as descriptor_file: descriptor_file.write(RelayDescriptor.content(sign=True))
from stem.descriptor.server_descriptor import RelayDescriptor print(RelayDescriptor.content({'router': 'demo 127.0.0.1 80 0 0'}))