commit 8303c8d99ac6728367dabec3f6b2c9e43bb68c69
Author: Damian Johnson <atagar(a)torproject.org>
Date: Tue Jun 11 08:43:05 2013 -0700
Using mock for controller unit tests
Another heavy mock user. Nice improvements, I'm really liking this library!
---
test/unit/control/controller.py | 217 ++++++++++++++++++++-------------------
1 file changed, 113 insertions(+), 104 deletions(-)
diff --git a/test/unit/control/controller.py b/test/unit/control/controller.py
index a0deaf1..ce25d30 100644
--- a/test/unit/control/controller.py
+++ b/test/unit/control/controller.py
@@ -13,10 +13,11 @@ import stem.socket
import stem.util.system
import stem.version
+from mock import Mock, patch
+
from stem import InvalidArguments, InvalidRequest, ProtocolError, UnsatisfiableRequest
from stem.control import _parse_circ_path, Controller, EventType
from stem.exit_policy import ExitPolicy
-from stem.socket import ControlSocket
from test import mocking
@@ -24,14 +25,11 @@ class TestControl(unittest.TestCase):
def setUp(self):
socket = stem.socket.ControlSocket()
- mocking.mock_method(Controller, "add_event_listener", mocking.no_op())
- self.controller = Controller(socket)
- mocking.revert_mocking()
-
- def tearDown(self):
- mocking.revert_mocking()
+ with patch('stem.control.Controller.add_event_listener', Mock()):
+ self.controller = Controller(socket)
- def test_get_version(self):
+ @patch('stem.control.Controller.get_info')
+ def test_get_version(self, get_info_mock):
"""
Exercises the get_version() method.
"""
@@ -40,7 +38,7 @@ class TestControl(unittest.TestCase):
# Use one version for first check.
version_2_1 = "0.2.1.32"
version_2_1_object = stem.version.Version(version_2_1)
- mocking.mock_method(Controller, "get_info", mocking.return_value(version_2_1))
+ get_info_mock.return_value = version_2_1
# Return a version with a cold cache.
self.assertEqual(version_2_1_object, self.controller.get_version())
@@ -48,7 +46,7 @@ class TestControl(unittest.TestCase):
# Use a different version for second check.
version_2_2 = "0.2.2.39"
version_2_2_object = stem.version.Version(version_2_2)
- mocking.mock_method(Controller, "get_info", mocking.return_value(version_2_2))
+ get_info_mock.return_value = version_2_2
# Return a version with a hot cache, so it will be the old version.
self.assertEqual(version_2_1_object, self.controller.get_version())
@@ -59,7 +57,7 @@ class TestControl(unittest.TestCase):
self.assertEqual(version_2_2_object, self.controller.get_version())
# Raise an exception in the get_info() call.
- mocking.mock_method(Controller, "get_info", mocking.raise_exception(InvalidArguments))
+ get_info_mock.side_effect = InvalidArguments
# Get a default value when the call fails.
self.assertEqual(
@@ -72,26 +70,29 @@ class TestControl(unittest.TestCase):
# Give a bad version. The stem.version.Version ValueError should bubble up.
version_A_42 = "0.A.42.spam"
- mocking.mock_method(Controller, "get_info", mocking.return_value(version_A_42))
+ get_info_mock.return_value = version_A_42
+ get_info_mock.side_effect = None
self.assertRaises(ValueError, self.controller.get_version)
finally:
# Turn caching back on before we leave.
self.controller._is_caching_enabled = True
- def test_get_exit_policy(self):
+ @patch('stem.control.Controller.get_info')
+ @patch('stem.control.Controller.get_conf')
+ def test_get_exit_policy(self, get_conf_mock, get_info_mock):
"""
Exercises the get_exit_policy() method.
"""
- mocking.mock_method(Controller, "get_conf", mocking.return_for_args({
- ("ExitPolicyRejectPrivate",): "1",
- ("ExitPolicy", "multiple=True"): ["accept *:80, accept *:443", "accept 43.5.5.5,reject *:22"]
- }, is_method = True))
+ get_conf_mock.side_effect = lambda param, **kwargs: {
+ "ExitPolicyRejectPrivate": "1",
+ "ExitPolicy": ["accept *:80, accept *:443", "accept 43.5.5.5,reject *:22"],
+ }[param]
- mocking.mock_method(Controller, "get_info", mocking.return_for_args({
- ("address", None): "123.45.67.89",
- ("exit-policy/default",): "reject *:25,reject *:119,reject *:135-139,reject *:445,reject *:563,reject *:1214,reject *:4661-4666,reject *:6346-6429,reject *:6699,reject *:6881-6999,accept *:*"
- }, is_method = True))
+ get_info_mock.side_effect = lambda param, default = None: {
+ "address": "123.45.67.89",
+ "exit-policy/default": "reject *:25,reject *:119,reject *:135-139,reject *:445,reject *:563,reject *:1214,reject *:4661-4666,reject *:6346-6429,reject *:6699,reject *:6881-6999,accept *:*",
+ }[param]
expected = ExitPolicy(
'reject 0.0.0.0/8:*', # private entries
@@ -120,7 +121,9 @@ class TestControl(unittest.TestCase):
self.assertEqual(expected, self.controller.get_exit_policy())
- def test_get_socks_listeners_old(self):
+ @patch('stem.control.Controller.get_info')
+ @patch('stem.control.Controller.get_conf')
+ def test_get_socks_listeners_old(self, get_conf_mock, get_info_mock):
"""
Exercises the get_socks_listeners() method as though talking to an old tor
instance.
@@ -129,68 +132,75 @@ class TestControl(unittest.TestCase):
# An old tor raises stem.InvalidArguments for get_info about socks, but
# get_socks_listeners should work anyway.
- mocking.mock_method(Controller, "get_info", mocking.raise_exception(InvalidArguments))
+ get_info_mock.side_effect = InvalidArguments
+
+ get_conf_mock.side_effect = lambda param, **kwargs: {
+ "SocksPort": "9050",
+ "SocksListenAddress": ["127.0.0.1"],
+ }[param]
- mocking.mock_method(Controller, "get_conf", mocking.return_for_args({
- ("SocksPort",): "9050",
- ("SocksListenAddress", "multiple=True"): ["127.0.0.1"]
- }, is_method = True))
self.assertEqual([('127.0.0.1', 9050)], self.controller.get_socks_listeners())
# Again, an old tor, but SocksListenAddress overrides the port number.
- mocking.mock_method(Controller, "get_conf", mocking.return_for_args({
- ("SocksPort",): "9050",
- ("SocksListenAddress", "multiple=True"): ["127.0.0.1:1112"]
- }, is_method = True))
+ get_conf_mock.side_effect = lambda param, **kwargs: {
+ "SocksPort": "9050",
+ "SocksListenAddress": ["127.0.0.1:1112"],
+ }[param]
+
self.assertEqual([('127.0.0.1', 1112)], self.controller.get_socks_listeners())
# Again, an old tor, but multiple listeners
- mocking.mock_method(Controller, "get_conf", mocking.return_for_args({
- ("SocksPort",): "9050",
- ("SocksListenAddress", "multiple=True"): ["127.0.0.1:1112", "127.0.0.1:1114"]
- }, is_method = True))
+ get_conf_mock.side_effect = lambda param, **kwargs: {
+ "SocksPort": "9050",
+ "SocksListenAddress": ["127.0.0.1:1112", "127.0.0.1:1114"],
+ }[param]
+
self.assertEqual([('127.0.0.1', 1112), ('127.0.0.1', 1114)], self.controller.get_socks_listeners())
# Again, an old tor, but no SOCKS listeners
- mocking.mock_method(Controller, "get_conf", mocking.return_for_args({
- ("SocksPort",): "0",
- ("SocksListenAddress", "multiple=True"): []
- }, is_method = True))
+ get_conf_mock.side_effect = lambda param, **kwargs: {
+ "SocksPort": "0",
+ "SocksListenAddress": [],
+ }[param]
+
self.assertEqual([], self.controller.get_socks_listeners())
# Where tor provides invalid ports or addresses
- mocking.mock_method(Controller, "get_conf", mocking.return_for_args({
- ("SocksPort",): "blarg",
- ("SocksListenAddress", "multiple=True"): ["127.0.0.1"]
- }, is_method = True))
+ get_conf_mock.side_effect = lambda param, **kwargs: {
+ "SocksPort": "blarg",
+ "SocksListenAddress": ["127.0.0.1"],
+ }[param]
+
self.assertRaises(stem.ProtocolError, self.controller.get_socks_listeners)
- mocking.mock_method(Controller, "get_conf", mocking.return_for_args({
- ("SocksPort",): "0",
- ("SocksListenAddress", "multiple=True"): ["127.0.0.1:abc"]
- }, is_method = True))
+ get_conf_mock.side_effect = lambda param, **kwargs: {
+ "SocksPort": "0",
+ "SocksListenAddress": ["127.0.0.1:abc"],
+ }[param]
+
self.assertRaises(stem.ProtocolError, self.controller.get_socks_listeners)
- mocking.mock_method(Controller, "get_conf", mocking.return_for_args({
- ("SocksPort",): "40",
- ("SocksListenAddress", "multiple=True"): ["500.0.0.1"]
- }, is_method = True))
+ get_conf_mock.side_effect = lambda param, **kwargs: {
+ "SocksPort": "40",
+ "SocksListenAddress": ["500.0.0.1"],
+ }[param]
+
self.assertRaises(stem.ProtocolError, self.controller.get_socks_listeners)
- def test_get_socks_listeners_new(self):
+ @patch('stem.control.Controller.get_info')
+ def test_get_socks_listeners_new(self, get_info_mock):
"""
Exercises the get_socks_listeners() method as if talking to a newer tor
instance.
"""
# multiple SOCKS listeners
- mocking.mock_method(Controller, "get_info", mocking.return_value(
- '"127.0.0.1:1112" "127.0.0.1:1114"'
- ))
+
+ get_info_mock.return_value = '"127.0.0.1:1112" "127.0.0.1:1114"'
self.assertEqual(
[('127.0.0.1', 1112), ('127.0.0.1', 1114)],
@@ -198,7 +208,8 @@ class TestControl(unittest.TestCase):
)
# no SOCKS listeners
- mocking.mock_method(Controller, "get_info", mocking.return_value(""))
+
+ get_info_mock.return_value = ''
self.assertEqual([], self.controller.get_socks_listeners())
# check where GETINFO provides malformed content
@@ -211,19 +222,18 @@ class TestControl(unittest.TestCase):
)
for response in invalid_responses:
- mocking.mock_method(Controller, "get_info", mocking.return_value(response))
+ get_info_mock.return_value = response
self.assertRaises(stem.ProtocolError, self.controller.get_socks_listeners)
- def test_get_protocolinfo(self):
+ @patch('stem.connection.get_protocolinfo')
+ def test_get_protocolinfo(self, get_protocolinfo_mock):
"""
Exercises the get_protocolinfo() method.
"""
# use the handy mocked protocolinfo response
- mocking.mock(stem.connection.get_protocolinfo, mocking.return_value(
- mocking.get_protocolinfo_response()
- ))
+ get_protocolinfo_mock.return_value = mocking.get_protocolinfo_response()
# compare the str representation of these object, because the class
# does not have, nor need, a direct comparison operator
@@ -235,7 +245,7 @@ class TestControl(unittest.TestCase):
# raise an exception in the stem.connection.get_protocolinfo() call
- mocking.mock(stem.connection.get_protocolinfo, mocking.raise_exception(ProtocolError))
+ get_protocolinfo_mock.side_effect = ProtocolError
# get a default value when the call fails
@@ -248,54 +258,53 @@ class TestControl(unittest.TestCase):
self.assertRaises(ProtocolError, self.controller.get_protocolinfo)
+ @patch('stem.socket.ControlSocket.is_localhost', Mock(return_value = False))
def test_get_user_remote(self):
"""
Exercise the get_user() method for a non-local socket.
"""
- mocking.mock_method(ControlSocket, "is_localhost", mocking.return_false())
-
self.assertRaises(ValueError, self.controller.get_user)
self.assertEqual(123, self.controller.get_user(123))
+ @patch('stem.socket.ControlSocket.is_localhost', Mock(return_value = True))
+ @patch('stem.control.Controller.get_info', Mock(return_value = 'atagar'))
def test_get_user_by_getinfo(self):
"""
Exercise the get_user() resolution via its getinfo option.
"""
- mocking.mock_method(ControlSocket, "is_localhost", mocking.return_true())
- mocking.mock_method(Controller, "get_info", mocking.return_value('atagar'))
self.assertEqual('atagar', self.controller.get_user())
+ @patch('stem.socket.ControlSocket.is_localhost', Mock(return_value = True))
+ @patch('stem.util.system.get_pid_by_name', Mock(return_value = 432))
+ @patch('stem.util.system.get_user', Mock(return_value = 'atagar'))
def test_get_user_by_system(self):
"""
Exercise the get_user() resolution via the system module.
"""
- mocking.mock_method(ControlSocket, "is_localhost", mocking.return_true())
- mocking.mock(stem.util.system.get_pid_by_name, mocking.return_value(432))
- mocking.mock(stem.util.system.get_user, mocking.return_value('atagar'))
self.assertEqual('atagar', self.controller.get_user())
+ @patch('stem.socket.ControlSocket.is_localhost', Mock(return_value = False))
def test_get_pid_remote(self):
"""
Exercise the get_pid() method for a non-local socket.
"""
- mocking.mock_method(ControlSocket, "is_localhost", mocking.return_false())
-
self.assertRaises(ValueError, self.controller.get_pid)
self.assertEqual(123, self.controller.get_pid(123))
+ @patch('stem.socket.ControlSocket.is_localhost', Mock(return_value = True))
+ @patch('stem.control.Controller.get_info', Mock(return_value = '321'))
def test_get_pid_by_getinfo(self):
"""
Exercise the get_pid() resolution via its getinfo option.
"""
- mocking.mock_method(ControlSocket, "is_localhost", mocking.return_true())
- mocking.mock_method(Controller, "get_info", mocking.return_value('321'))
self.assertEqual(321, self.controller.get_pid())
+ @patch('stem.socket.ControlSocket.is_localhost', Mock(return_value = True))
def test_get_pid_by_pid_file(self):
"""
Exercise the get_pid() resolution via a PidFile.
@@ -304,29 +313,28 @@ class TestControl(unittest.TestCase):
# It's a little inappropriate for us to be using tempfile in unit tests,
# but this is more reliable than trying to mock open().
- mocking.mock_method(ControlSocket, "is_localhost", mocking.return_true())
-
pid_file_path = tempfile.mkstemp()[1]
try:
with open(pid_file_path, 'w') as pid_file:
pid_file.write('432')
- mocking.mock_method(Controller, "get_conf", mocking.return_value(pid_file_path))
- self.assertEqual(432, self.controller.get_pid())
+ with patch('stem.control.Controller.get_conf', Mock(return_value = pid_file_path)):
+ self.assertEqual(432, self.controller.get_pid())
finally:
os.remove(pid_file_path)
+ @patch('stem.socket.ControlSocket.is_localhost', Mock(return_value = True))
+ @patch('stem.util.system.get_pid_by_name', Mock(return_value = 432))
def test_get_pid_by_name(self):
"""
Exercise the get_pid() resolution via the process name.
"""
- mocking.mock_method(ControlSocket, "is_localhost", mocking.return_true())
- mocking.mock(stem.util.system.get_pid_by_name, mocking.return_value(432))
self.assertEqual(432, self.controller.get_pid())
- def test_get_network_status(self):
+ @patch('stem.control.Controller.get_info')
+ def test_get_network_status(self, get_info_mock):
"""
Exercises the get_network_status() method.
"""
@@ -340,7 +348,7 @@ class TestControl(unittest.TestCase):
# always return the same router status entry
- mocking.mock_method(Controller, "get_info", mocking.return_value(desc))
+ get_info_mock.return_value = desc
# pretend to get the router status entry with its name
@@ -358,7 +366,7 @@ class TestControl(unittest.TestCase):
# raise an exception in the get_info() call
- mocking.mock_method(Controller, "get_info", mocking.raise_exception(InvalidArguments))
+ get_info_mock.side_effect = InvalidArguments
# get a default value when the call fails
@@ -371,25 +379,29 @@ class TestControl(unittest.TestCase):
self.assertRaises(InvalidArguments, self.controller.get_network_status, nickname)
- def test_event_listening(self):
+ @patch('stem.control.Controller.is_authenticated', Mock(return_value = True))
+ @patch('stem.control.Controller._attach_listeners', Mock(return_value = ([], [])))
+ @patch('stem.control.Controller.get_version')
+ def test_event_listening(self, get_version_mock):
"""
Exercises the add_event_listener and remove_event_listener methods.
"""
# set up for failure to create any events
- mocking.mock_method(Controller, "is_authenticated", mocking.return_true())
- mocking.mock_method(Controller, "_attach_listeners", mocking.return_value(([], [])))
- mocking.mock_method(Controller, "get_version", mocking.return_value(stem.version.Version('0.1.0.14')))
- self.assertRaises(InvalidRequest, self.controller.add_event_listener, mocking.no_op(), EventType.BW)
+
+ get_version_mock.return_value = stem.version.Version('0.1.0.14')
+ self.assertRaises(InvalidRequest, self.controller.add_event_listener, Mock(), EventType.BW)
# set up to only fail newer events
- mocking.mock_method(Controller, "get_version", mocking.return_value(stem.version.Version('0.2.0.35')))
+
+ get_version_mock.return_value = stem.version.Version('0.2.0.35')
# EventType.BW is one of the earliest events
- self.controller.add_event_listener(mocking.no_op(), EventType.BW)
+
+ self.controller.add_event_listener(Mock(), EventType.BW)
# EventType.SIGNAL was added in tor version 0.2.3.1-alpha
- self.assertRaises(InvalidRequest, self.controller.add_event_listener, mocking.no_op(), EventType.SIGNAL)
+ self.assertRaises(InvalidRequest, self.controller.add_event_listener, Mock(), EventType.SIGNAL)
def test_get_streams(self):
"""
@@ -403,20 +415,17 @@ class TestControl(unittest.TestCase):
("3", "SUCCEEDED", "4", "10.10.10.1:80")
)
- responses = ["%s\r\n" % " ".join(entry) for entry in valid_streams]
-
- mocking.mock_method(Controller, "get_info", mocking.return_value(
- "".join(responses)
- ))
+ response = "".join(["%s\r\n" % " ".join(entry) for entry in valid_streams])
- streams = self.controller.get_streams()
- self.assertEqual(len(valid_streams), len(streams))
+ with patch('stem.control.Controller.get_info', Mock(return_value = response)):
+ streams = self.controller.get_streams()
+ self.assertEqual(len(valid_streams), len(streams))
- for index, stream in enumerate(streams):
- self.assertEqual(valid_streams[index][0], stream.id)
- self.assertEqual(valid_streams[index][1], stream.status)
- self.assertEqual(valid_streams[index][2], stream.circ_id)
- self.assertEqual(valid_streams[index][3], stream.target)
+ for index, stream in enumerate(streams):
+ self.assertEqual(valid_streams[index][0], stream.id)
+ self.assertEqual(valid_streams[index][1], stream.status)
+ self.assertEqual(valid_streams[index][2], stream.circ_id)
+ self.assertEqual(valid_streams[index][3], stream.target)
def test_attach_stream(self):
"""
@@ -427,9 +436,9 @@ class TestControl(unittest.TestCase):
# instance, it's already open).
response = stem.response.ControlMessage.from_str("555 Connection is not managed by controller.\r\n")
- mocking.mock_method(Controller, "msg", mocking.return_value(response))
- self.assertRaises(UnsatisfiableRequest, self.controller.attach_stream, 'stream_id', 'circ_id')
+ with patch('stem.control.Controller.msg', Mock(return_value = response)):
+ self.assertRaises(UnsatisfiableRequest, self.controller.attach_stream, 'stream_id', 'circ_id')
def test_parse_circ_path(self):
"""