commit 2f6544d56a2f46a001a55a639e4fa4b996b0e9f7 Author: Damian Johnson atagar@torproject.org Date: Sat Mar 11 23:12:55 2017 -0800
Use assertRaisesRegexp to check exception messages
Interesting! New tests used assertRaisesRegexp which is a much nicer method of asserting what an exception message is. Using this throughout our codebase. --- test/integ/control/controller.py | 24 +++++-------- test/integ/process.py | 23 ++++++------ test/integ/util/system.py | 6 +--- test/unit/control/controller.py | 15 +++----- test/unit/descriptor/extrainfo_descriptor.py | 10 +++--- test/unit/descriptor/microdescriptor.py | 7 ++-- test/unit/descriptor/networkstatus/document_v3.py | 9 ++--- test/unit/descriptor/server_descriptor.py | 14 +++----- test/unit/manual.py | 43 +++++++---------------- test/unit/response/add_onion.py | 16 +++------ test/unit/util/proc.py | 9 ++--- 11 files changed, 56 insertions(+), 120 deletions(-)
diff --git a/test/integ/control/controller.py b/test/integ/control/controller.py index a1f155b..f5c91d7 100644 --- a/test/integ/control/controller.py +++ b/test/integ/control/controller.py @@ -581,13 +581,11 @@ class TestController(unittest.TestCase): runner = test.runner.get_runner()
with runner.get_tor_controller() as controller: + # try creating a service with an invalid ports + for ports in (4567890, [4567, 4567890], {4567: '-:4567'}): - try: - # try creating a service with an invalid port - response = controller.create_ephemeral_hidden_service(ports) - self.fail("we should've raised a stem.ProtocolError") - except stem.ProtocolError as exc: - self.assertEqual("ADD_ONION response didn't have an OK status: Invalid VIRTPORT/TARGET", str(exc)) + exc_msg = "ADD_ONION response didn't have an OK status: Invalid VIRTPORT/TARGET" + self.assertRaisesRegexp(stem.ProtocolError, exc_msg, controller.create_ephemeral_hidden_service, ports)
response = controller.create_ephemeral_hidden_service(4567) self.assertEqual([response.service_id], controller.list_ephemeral_hidden_services()) @@ -654,11 +652,8 @@ class TestController(unittest.TestCase): runner = test.runner.get_runner()
with runner.get_tor_controller() as controller: - try: - controller.create_ephemeral_hidden_service(4567, basic_auth = {}) - self.fail('ADD_ONION should fail when using basic auth without any clients') - except stem.ProtocolError as exc: - self.assertEqual("ADD_ONION response didn't have an OK status: No auth clients specified", str(exc)) + exc_msg = "ADD_ONION response didn't have an OK status: No auth clients specified" + self.assertRaisesRegexp(stem.ProtocolError, exc_msg, controller.create_ephemeral_hidden_service, 4567, basic_auth = {})
@require_controller @require_version(Requirement.ADD_ONION) @@ -1266,11 +1261,8 @@ class TestController(unittest.TestCase):
# try to fetch something that doesn't exist
- try: - desc = controller.get_hidden_service_descriptor('m4cfuk6qp4lpu2g3') - self.fail("Didn't expect m4cfuk6qp4lpu2g3.onion to exist, but provided: %s" % desc) - except stem.DescriptorUnavailable as exc: - self.assertEqual('No running hidden service at m4cfuk6qp4lpu2g3.onion', str(exc)) + exc_msg = 'No running hidden service at m4cfuk6qp4lpu2g3.onion' + self.assertRaisesRegexp(stem.DescriptorUnavailable, exc_msg, controller.get_hidden_service_descriptor, 'm4cfuk6qp4lpu2g3')
# ... but shouldn't fail if we have a default argument or aren't awaiting the descriptor
diff --git a/test/integ/process.py b/test/integ/process.py index 19d6750..3f7ac65 100644 --- a/test/integ/process.py +++ b/test/integ/process.py @@ -356,18 +356,17 @@ class TestProcess(unittest.TestCase): # [warn] Failed to parse/validate config: Failed to bind one of the listener ports. # [err] Reading config failed--see warnings above.
- try: - stem.process.launch_tor_with_config( - tor_cmd = test.runner.get_runner().get_tor_command(), - config = { - 'SocksPort': '2777', - 'ControlPort': '2777', - 'DataDirectory': self.data_directory, - }, - ) - self.fail("We should abort when there's an identical SocksPort and ControlPort") - except OSError as exc: - self.assertEqual('Process terminated: Failed to bind one of the listener ports.', str(exc)) + self.assertRaisesRegexp( + OSError, + 'Process terminated: Failed to bind one of the listener ports.', + stem.process.launch_tor_with_config, + tor_cmd = test.runner.get_runner().get_tor_command(), + config = { + 'SocksPort': '2777', + 'ControlPort': '2777', + 'DataDirectory': self.data_directory, + }, + )
@only_run_once def test_launch_tor_with_timeout(self): diff --git a/test/integ/util/system.py b/test/integ/util/system.py index b6e66a0..be04393 100644 --- a/test/integ/util/system.py +++ b/test/integ/util/system.py @@ -564,11 +564,7 @@ class TestSystem(unittest.TestCase): self.assertEqual(os.path.join(home_dir, 'foo'), stem.util.system.expand_path('~%s/foo' % username))
def test_call_timeout(self): - try: - stem.util.system.call('sleep 1', timeout = 0.001) - self.fail("sleep should've timed out") - except stem.util.system.CallTimeoutError as exc: - self.assertEqual("Process didn't finish after 0.0 seconds", str(exc)) + self.assertRaisesRegexp(stem.util.system.CallTimeoutError, "Process didn't finish after 0.0 seconds", stem.util.system.call, 'sleep 1', timeout = 0.001)
def test_call_time_tracked(self): """ diff --git a/test/unit/control/controller.py b/test/unit/control/controller.py index 0c82a94..47ac9d2 100644 --- a/test/unit/control/controller.py +++ b/test/unit/control/controller.py @@ -442,12 +442,8 @@ class TestControl(unittest.TestCase):
get_info_mock.side_effect = ControllerError('nope, too bad')
- try: - self.controller.get_network_status() - self.fail("We should've raised an exception") - except ControllerError as exc: - self.assertEqual('Unable to determine our own fingerprint: nope, too bad', str(exc)) - + exc_msg = 'Unable to determine our own fingerprint: nope, too bad' + self.assertRaisesRegexp(ControllerError, exc_msg, self.controller.get_network_status) self.assertEqual('boom', self.controller.get_network_status(default = 'boom'))
# successful request @@ -469,11 +465,8 @@ class TestControl(unittest.TestCase):
get_info_mock.side_effect = InvalidArguments(None, 'GETINFO request contained unrecognized keywords: ns/id/5AC9C5AA75BA1F18D8459B326B4B8111A856D290')
- try: - self.controller.get_network_status('5AC9C5AA75BA1F18D8459B326B4B8111A856D290') - self.fail("We should've raised an exception") - except DescriptorUnavailable as exc: - self.assertEqual("Tor was unable to provide the descriptor for '5AC9C5AA75BA1F18D8459B326B4B8111A856D290'", str(exc)) + exc_msg = "Tor was unable to provide the descriptor for '5AC9C5AA75BA1F18D8459B326B4B8111A856D290'" + self.assertRaisesRegexp(DescriptorUnavailable, exc_msg, self.controller.get_network_status, '5AC9C5AA75BA1F18D8459B326B4B8111A856D290')
@patch('stem.control.Controller.get_info') def test_get_network_status(self, get_info_mock): diff --git a/test/unit/descriptor/extrainfo_descriptor.py b/test/unit/descriptor/extrainfo_descriptor.py index 79d0b5c..cab3440 100644 --- a/test/unit/descriptor/extrainfo_descriptor.py +++ b/test/unit/descriptor/extrainfo_descriptor.py @@ -3,6 +3,7 @@ Unit tests for stem.descriptor.extrainfo_descriptor. """
import datetime +import re import unittest
import stem.descriptor @@ -172,12 +173,9 @@ k0d2aofcVbHr4fPQOSST0LXDrhFl5Fqo5um296zpJGvRUeO6S44U/EfJAGShtqWw """
with open(get_resource('unparseable/extrainfo_nonascii_v3_reqs'), 'rb') as descriptor_file: - try: - next(stem.descriptor.parse_file(descriptor_file, 'extra-info 1.0', validate = True)) - self.fail("validation should've raised an exception") - except ValueError as exc: - expected = "'dirreq-v3-reqs' line had non-ascii content: S?=4026597208,S?=4026597208,S?=4026597208,S?=4026597208,S?=4026597208,S?=4026597208,??=4026591624,6?=4026537520,6?=4026537520,6?=4026537520,us=8" - self.assertEqual(expected, str(exc)) + desc_generator = stem.descriptor.parse_file(descriptor_file, 'extra-info 1.0', validate = True) + exc_msg = "'dirreq-v3-reqs' line had non-ascii content: S?=4026597208,S?=4026597208,S?=4026597208,S?=4026597208,S?=4026597208,S?=4026597208,??=4026591624,6?=4026537520,6?=4026537520,6?=4026537520,us=8" + self.assertRaisesRegexp(ValueError, re.escape(exc_msg), next, desc_generator)
def test_minimal_extrainfo_descriptor(self): """ diff --git a/test/unit/descriptor/microdescriptor.py b/test/unit/descriptor/microdescriptor.py index 9b3fb2d..f9350d2 100644 --- a/test/unit/descriptor/microdescriptor.py +++ b/test/unit/descriptor/microdescriptor.py @@ -204,8 +204,5 @@ class TestMicrodescriptor(unittest.TestCase): desc = Microdescriptor(desc_text) self.assertEqual({}, desc.identifiers)
- try: - Microdescriptor(desc_text, validate = True) - self.fail('constructor validation should fail') - except ValueError as exc: - self.assertEqual("There can only be one 'id' line per a key type, but 'rsa1024' appeared multiple times", str(exc)) + exc_msg = "There can only be one 'id' line per a key type, but 'rsa1024' appeared multiple times" + self.assertRaisesRegexp(ValueError, exc_msg, Microdescriptor, desc_text, validate = True) diff --git a/test/unit/descriptor/networkstatus/document_v3.py b/test/unit/descriptor/networkstatus/document_v3.py index e6e5d76..6a2e784 100644 --- a/test/unit/descriptor/networkstatus/document_v3.py +++ b/test/unit/descriptor/networkstatus/document_v3.py @@ -4,6 +4,7 @@ Unit tests for the NetworkStatusDocumentV3 of stem.descriptor.networkstatus.
import datetime import io +import re import unittest
import stem.descriptor @@ -1239,15 +1240,9 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
for attr, expected_exception in test_values: content = get_directory_authority(attr, content = True) - - try: - DirectoryAuthority(content, True) - self.fail("validation should've rejected malformed shared randomness attribute") - except ValueError as exc: - self.assertEqual(expected_exception, str(exc)) + self.assertRaisesRegexp(ValueError, re.escape(expected_exception), DirectoryAuthority, content, True)
authority = DirectoryAuthority(content, False) - self.assertEqual([], authority.shared_randomness_commitments) self.assertEqual(None, authority.shared_randomness_previous_reveal_count) self.assertEqual(None, authority.shared_randomness_previous_value) diff --git a/test/unit/descriptor/server_descriptor.py b/test/unit/descriptor/server_descriptor.py index 8170532..b43a6f3 100644 --- a/test/unit/descriptor/server_descriptor.py +++ b/test/unit/descriptor/server_descriptor.py @@ -681,22 +681,16 @@ Qlx9HNCqCY877ztFRC624ja2ql6A2hBcuoYMbkHjcQ4= Checks a 'proto' line when it's not key=value pairs. """
- try: - get_relay_server_descriptor({'proto': 'Desc Link=1-4'}) - self.fail('Did not raise expected exception') - except ValueError as exc: - self.assertEqual("Protocol entires are expected to be a series of 'key=value' pairs but was: proto Desc Link=1-4", str(exc)) + exc_msg = "Protocol entires are expected to be a series of 'key=value' pairs but was: proto Desc Link=1-4" + self.assertRaisesRegexp(ValueError, exc_msg, get_relay_server_descriptor, {'proto': 'Desc Link=1-4'})
def test_parse_with_non_int_version(self): """ Checks a 'proto' line with non-numeric content. """
- try: - get_relay_server_descriptor({'proto': 'Desc=hi Link=1-4'}) - self.fail('Did not raise expected exception') - except ValueError as exc: - self.assertEqual('Protocol values should be a number or number range, but was: proto Desc=hi Link=1-4', str(exc)) + exc_msg = 'Protocol values should be a number or number range, but was: proto Desc=hi Link=1-4' + self.assertRaisesRegexp(ValueError, exc_msg, get_relay_server_descriptor, {'proto': 'Desc=hi Link=1-4'})
def test_ntor_onion_key(self): """ diff --git a/test/unit/manual.py b/test/unit/manual.py index 671ed93..06e0071 100644 --- a/test/unit/manual.py +++ b/test/unit/manual.py @@ -4,6 +4,7 @@ Unit testing for the stem.manual module.
import io import os +import re import tempfile import unittest
@@ -237,30 +238,21 @@ class TestManual(unittest.TestCase): self.assertTrue(len(manual.config_options) > 200)
def test_download_man_page_without_arguments(self): - try: - stem.manual.download_man_page() - self.fail('we should fail without a path or file handler') - except ValueError as exc: - self.assertEqual("Either the path or file_handle we're saving to must be provided", str(exc)) + exc_msg = "Either the path or file_handle we're saving to must be provided" + self.assertRaisesRegexp(ValueError, exc_msg, stem.manual.download_man_page)
@patch('stem.util.system.is_available', Mock(return_value = False)) def test_download_man_page_requires_a2x(self): - try: - stem.manual.download_man_page('/tmp/no_such_file') - self.fail('we should require a2x to be available') - except IOError as exc: - self.assertEqual('We require a2x from asciidoc to provide a man page', str(exc)) + exc_msg = 'We require a2x from asciidoc to provide a man page' + self.assertRaisesRegexp(IOError, exc_msg, stem.manual.download_man_page, '/tmp/no_such_file')
@patch('tempfile.mkdtemp', Mock(return_value = '/no/such/path')) @patch('shutil.rmtree', Mock()) @patch('stem.manual.open', Mock(side_effect = IOError('unable to write to file')), create = True) @patch('stem.util.system.is_available', Mock(return_value = True)) def test_download_man_page_when_unable_to_write(self): - try: - stem.manual.download_man_page('/tmp/no_such_file') - self.fail("we shouldn't be able to write to /no/such/path") - except IOError as exc: - self.assertEqual("Unable to download tor's manual from https://gitweb.torproject.org/tor.git/plain/doc/tor.1.txt to /no/such/path/tor.1.txt: unable to write to file", str(exc)) + exc_msg = "Unable to download tor's manual from https://gitweb.torproject.org/tor.git/plain/doc/tor.1.txt to /no/such/path/tor.1.txt: unable to write to file" + self.assertRaisesRegexp(IOError, re.escape(exc_msg), stem.manual.download_man_page, '/tmp/no_such_file')
@patch('tempfile.mkdtemp', Mock(return_value = '/no/such/path')) @patch('shutil.rmtree', Mock()) @@ -268,11 +260,8 @@ class TestManual(unittest.TestCase): @patch('stem.util.system.is_available', Mock(return_value = True)) @patch(URL_OPEN, Mock(side_effect = urllib.URLError('<urlopen error [Errno -2] Name or service not known>'))) def test_download_man_page_when_download_fails(self): - try: - stem.manual.download_man_page('/tmp/no_such_file', url = 'https://www.atagar.com/foo/bar') - self.fail("downloading from test_invalid_url.org shouldn't work") - except IOError as exc: - self.assertEqual("Unable to download tor's manual from https://www.atagar.com/foo/bar to /no/such/path/tor.1.txt: <urlopen error <urlopen error [Errno -2] Name or service not known>>", str(exc)) + exc_msg = "Unable to download tor's manual from https://www.atagar.com/foo/bar to /no/such/path/tor.1.txt: <urlopen error <urlopen error [Errno -2] Name or service not known>>" + self.assertRaisesRegexp(IOError, re.escape(exc_msg), stem.manual.download_man_page, '/tmp/no_such_file', url = 'https://www.atagar.com/foo/bar')
@patch('tempfile.mkdtemp', Mock(return_value = '/no/such/path')) @patch('shutil.rmtree', Mock()) @@ -281,11 +270,8 @@ class TestManual(unittest.TestCase): @patch('stem.util.system.is_available', Mock(return_value = True)) @patch(URL_OPEN, Mock(return_value = io.BytesIO(b'test content'))) def test_download_man_page_when_a2x_fails(self): - try: - stem.manual.download_man_page('/tmp/no_such_file', url = 'https://www.atagar.com/foo/bar') - self.fail("downloading from test_invalid_url.org shouldn't work") - except IOError as exc: - self.assertEqual("Unable to run 'a2x -f manpage /no/such/path/tor.1.txt': call failed", str(exc)) + exc_msg = "Unable to run 'a2x -f manpage /no/such/path/tor.1.txt': call failed" + self.assertRaisesRegexp(IOError, exc_msg, stem.manual.download_man_page, '/tmp/no_such_file', url = 'https://www.atagar.com/foo/bar')
@patch('tempfile.mkdtemp', Mock(return_value = '/no/such/path')) @patch('shutil.rmtree', Mock()) @@ -310,11 +296,8 @@ class TestManual(unittest.TestCase): @patch('stem.util.system.is_mac', Mock(return_value = False)) @patch('stem.util.system.call', Mock(side_effect = OSError('man --encoding=ascii -P cat tor returned exit status 16'))) def test_from_man_when_manual_is_unavailable(self): - try: - stem.manual.Manual.from_man() - self.fail("fetching the manual should fail when it's unavailable") - except IOError as exc: - self.assertEqual("Unable to run 'man --encoding=ascii -P cat tor': man --encoding=ascii -P cat tor returned exit status 16", str(exc)) + exc_msg = "Unable to run 'man --encoding=ascii -P cat tor': man --encoding=ascii -P cat tor returned exit status 16" + self.assertRaisesRegexp(IOError, exc_msg, stem.manual.Manual.from_man)
@patch('stem.util.system.call', Mock(return_value = [])) def test_when_man_is_empty(self): diff --git a/test/unit/response/add_onion.py b/test/unit/response/add_onion.py index 64e3688..1213f0c 100644 --- a/test/unit/response/add_onion.py +++ b/test/unit/response/add_onion.py @@ -95,21 +95,13 @@ class TestAddOnionResponse(unittest.TestCase): Checks a response that lack an initial service id. """
- try: - response = mocking.get_message(WRONG_FIRST_KEY) - stem.response.convert('ADD_ONION', response) - self.fail("we should've raised a ProtocolError") - except stem.ProtocolError as exc: - self.assertTrue(str(exc).startswith('ADD_ONION response should start with')) + response = mocking.get_message(WRONG_FIRST_KEY) + self.assertRaisesRegexp(stem.ProtocolError, 'ADD_ONION response should start with', stem.response.convert, 'ADD_ONION', response)
def test_no_key_type(self): """ Checks a response that's missing the private key type. """
- try: - response = mocking.get_message(MISSING_KEY_TYPE) - stem.response.convert('ADD_ONION', response) - self.fail("we should've raised a ProtocolError") - except stem.ProtocolError as exc: - self.assertTrue(str(exc).startswith('ADD_ONION PrivateKey lines should be of the form')) + response = mocking.get_message(MISSING_KEY_TYPE) + self.assertRaisesRegexp(stem.ProtocolError, 'ADD_ONION PrivateKey lines should be of the form', stem.response.convert, 'ADD_ONION', response) diff --git a/test/unit/util/proc.py b/test/unit/util/proc.py index 72b7131..5f65212 100644 --- a/test/unit/util/proc.py +++ b/test/unit/util/proc.py @@ -3,6 +3,7 @@ Unit testing code for the stem.util.proc functions. """
import io +import re import unittest
from stem.util import proc @@ -174,12 +175,8 @@ class TestProc(unittest.TestCase): error_msg = "OSError: [Errno 2] No such file or directory: '/proc/2118/fd'" listdir_mock.side_effect = OSError(error_msg)
- try: - proc.file_descriptors_used(2118) - self.fail('We should raise when listdir() fails') - except IOError as exc: - expected = 'Unable to check number of file descriptors used: %s' % error_msg - self.assertEqual(expected, str(exc)) + exc_msg = 'Unable to check number of file descriptors used: %s' % error_msg + self.assertRaisesRegexp(IOError, re.escape(exc_msg), proc.file_descriptors_used, 2118)
# successful calls