commit b164478ea9c0275bc668cef32e84f4026c05a246
Author: Damian Johnson <atagar(a)torproject.org>
Date: Tue May 2 09:37:47 2017 -0700
Merge remaining mocking module into util
Without descriptor creation there's really not much left. Merging the few
remaining helpers into the util module.
---
test/__init__.py | 3 +-
test/integ/control/base_controller.py | 4 +-
test/integ/control/controller.py | 10 +--
test/integ/socket/control_message.py | 4 +-
test/mocking.py | 118 --------------------------------
test/unit/connection/authentication.py | 9 +--
test/unit/control/controller.py | 7 +-
test/unit/doctest.py | 3 +-
test/unit/interpreter/commands.py | 11 +--
test/unit/response/add_onion.py | 14 ++--
test/unit/response/authchallenge.py | 6 +-
test/unit/response/events.py | 5 +-
test/unit/response/getconf.py | 14 ++--
test/unit/response/getinfo.py | 16 ++---
test/unit/response/mapaddress.py | 14 ++--
test/unit/response/protocolinfo.py | 25 +++----
test/unit/response/singleline.py | 12 ++--
test/unit/tutorial_examples.py | 5 +-
test/unit/util/proc.py | 5 +-
test/util.py | 120 ++++++++++++++++++++++++++++++---
20 files changed, 195 insertions(+), 210 deletions(-)
diff --git a/test/__init__.py b/test/__init__.py
index 7ab0853..8ea70d2 100644
--- a/test/__init__.py
+++ b/test/__init__.py
@@ -6,10 +6,9 @@ Unit and integration tests for the stem library.
"""
__all__ = [
- 'mocking',
'network',
'output',
'prompt',
'runner',
- 'utils',
+ 'util',
]
diff --git a/test/integ/control/base_controller.py b/test/integ/control/base_controller.py
index 0a51e1f..1e64445 100644
--- a/test/integ/control/base_controller.py
+++ b/test/integ/control/base_controller.py
@@ -11,8 +11,8 @@ import stem.control
import stem.socket
import stem.util.system
-import test.mocking
import test.runner
+import test.util
from test.util import require_controller
@@ -154,7 +154,7 @@ class TestBaseController(unittest.TestCase):
controller.msg('SETEVENTS CONF_CHANGED')
for i in range(10):
- controller.msg('SETCONF NodeFamily=%s' % test.mocking.random_fingerprint())
+ controller.msg('SETCONF NodeFamily=%s' % test.util.random_fingerprint())
test.runner.exercise_controller(self, controller)
controller.msg('SETEVENTS')
diff --git a/test/integ/control/controller.py b/test/integ/control/controller.py
index 48a50fe..895d435 100644
--- a/test/integ/control/controller.py
+++ b/test/integ/control/controller.py
@@ -18,7 +18,6 @@ import stem.response.protocolinfo
import stem.socket
import stem.util.str_tools
import stem.version
-import test.mocking
import test.network
import test.runner
@@ -29,6 +28,7 @@ from stem.version import Requirement
from test.util import (
register_new_capability,
+ random_fingerprint,
tor_version,
only_run_once,
require_controller,
@@ -150,7 +150,7 @@ class TestController(unittest.TestCase):
controller.add_event_listener(listener2, EventType.CONF_CHANGED, EventType.DEBUG)
# The NodeFamily is a harmless option we can toggle
- controller.set_conf('NodeFamily', test.mocking.random_fingerprint())
+ controller.set_conf('NodeFamily', random_fingerprint())
# Wait for the event. Assert that we get it within 10 seconds
event_notice1.wait(10)
@@ -167,7 +167,7 @@ class TestController(unittest.TestCase):
buffer2_size = len(event_buffer2)
- controller.set_conf('NodeFamily', test.mocking.random_fingerprint())
+ controller.set_conf('NodeFamily', random_fingerprint())
event_notice1.wait(10)
self.assertEqual(len(event_buffer1), 2)
event_notice1.clear()
@@ -204,7 +204,7 @@ class TestController(unittest.TestCase):
# trigger an event
- controller.set_conf('NodeFamily', test.mocking.random_fingerprint())
+ controller.set_conf('NodeFamily', random_fingerprint())
event_notice.wait(4)
self.assertTrue(len(event_buffer) >= 1)
@@ -217,7 +217,7 @@ class TestController(unittest.TestCase):
controller.connect()
controller.authenticate(password = test.runner.CONTROL_PASSWORD)
self.assertTrue(len(event_buffer) == 0)
- controller.set_conf('NodeFamily', test.mocking.random_fingerprint())
+ controller.set_conf('NodeFamily', random_fingerprint())
event_notice.wait(4)
self.assertTrue(len(event_buffer) >= 1)
diff --git a/test/integ/socket/control_message.py b/test/integ/socket/control_message.py
index 13075ca..646f732 100644
--- a/test/integ/socket/control_message.py
+++ b/test/integ/socket/control_message.py
@@ -7,12 +7,12 @@ import unittest
import stem.socket
import stem.version
-import test.mocking
import test.runner
from test.util import (
require_controller,
require_version,
+ random_fingerprint,
)
@@ -162,7 +162,7 @@ class TestControlMessage(unittest.TestCase):
# We'll receive both a CONF_CHANGED event and 'OK' response for the
# SETCONF, but not necessarily in any specific order.
- control_socket.send('SETCONF NodeFamily=%s' % test.mocking.random_fingerprint())
+ control_socket.send('SETCONF NodeFamily=%s' % random_fingerprint())
msg1 = control_socket.recv()
msg2 = control_socket.recv()
diff --git a/test/mocking.py b/test/mocking.py
deleted file mode 100644
index 6369598..0000000
--- a/test/mocking.py
+++ /dev/null
@@ -1,118 +0,0 @@
-# Copyright 2012-2017, Damian Johnson and The Tor Project
-# See LICENSE for licensing information
-
-"""
-Helper functions for creating mock objects.
-
-::
-
- get_all_combinations - provides all combinations of attributes
- random_fingerprint - provides a random relay fingerprint
-
- Instance Constructors
- get_message - stem.response.ControlMessage
- get_protocolinfo_response - stem.response.protocolinfo.ProtocolInfoResponse
-"""
-
-import hashlib
-import itertools
-import os
-import re
-
-import stem.descriptor.extrainfo_descriptor
-import stem.descriptor.hidden_service_descriptor
-import stem.descriptor.microdescriptor
-import stem.descriptor.networkstatus
-import stem.descriptor.router_status_entry
-import stem.descriptor.server_descriptor
-import stem.prereq
-import stem.response
-import stem.util.str_tools
-
-
-def get_all_combinations(attr, include_empty = False):
- """
- Provides an iterator for all combinations of a set of attributes. For
- instance...
-
- ::
-
- >>> list(test.mocking.get_all_combinations(['a', 'b', 'c']))
- [('a',), ('b',), ('c',), ('a', 'b'), ('a', 'c'), ('b', 'c'), ('a', 'b', 'c')]
-
- :param list attr: attributes to provide combinations for
- :param bool include_empty: includes an entry with zero items if True
- :returns: iterator for all combinations
- """
-
- # Makes an itertools.product() call for 'i' copies of attr...
- #
- # * itertools.product(attr) => all one-element combinations
- # * itertools.product(attr, attr) => all two-element combinations
- # * ... etc
-
- if include_empty:
- yield ()
-
- seen = set()
- for index in range(1, len(attr) + 1):
- product_arg = [attr for _ in range(index)]
-
- for item in itertools.product(*product_arg):
- # deduplicate, sort, and only provide if we haven't seen it yet
- item = tuple(sorted(set(item)))
-
- if item not in seen:
- seen.add(item)
- yield item
-
-
-def random_fingerprint():
- """
- Provides a random relay fingerprint.
- """
-
- return hashlib.sha1(os.urandom(20)).hexdigest().upper()
-
-
-def get_message(content, reformat = True):
- """
- Provides a ControlMessage with content modified to be parsable. This makes
- the following changes unless 'reformat' is false...
-
- * ensures the content ends with a newline
- * newlines are replaced with a carriage return and newline pair
-
- :param str content: base content for the controller message
- :param str reformat: modifies content to be more accommodating to being parsed
-
- :returns: stem.response.ControlMessage instance
- """
-
- if reformat:
- if not content.endswith('\n'):
- content += '\n'
-
- content = re.sub('([\r]?)\n', '\r\n', content)
-
- return stem.response.ControlMessage.from_str(content)
-
-
-def get_protocolinfo_response(**attributes):
- """
- Provides a ProtocolInfoResponse, customized with the given attributes. The
- base instance is minimal, with its version set to one and everything else
- left with the default.
-
- :param dict attributes: attributes to customize the response with
-
- :returns: stem.response.protocolinfo.ProtocolInfoResponse instance
- """
-
- protocolinfo_response = get_message('250-PROTOCOLINFO 1\n250 OK')
- stem.response.convert('PROTOCOLINFO', protocolinfo_response)
-
- for attr in attributes:
- setattr(protocolinfo_response, attr, attributes[attr])
-
- return protocolinfo_response
diff --git a/test/unit/connection/authentication.py b/test/unit/connection/authentication.py
index b7ccc0d..044f163 100644
--- a/test/unit/connection/authentication.py
+++ b/test/unit/connection/authentication.py
@@ -13,8 +13,9 @@ import unittest
import stem.connection
+import test.util
+
from stem.util import log
-from test import mocking
try:
# added in python 3.3
@@ -33,7 +34,7 @@ class TestAuthenticate(unittest.TestCase):
# tests where get_protocolinfo succeeds
- get_protocolinfo_mock.return_value = mocking.get_protocolinfo_response(
+ get_protocolinfo_mock.return_value = test.util.get_protocolinfo_response(
auth_methods = (stem.connection.AuthMethod.NONE, ),
)
@@ -85,7 +86,7 @@ class TestAuthenticate(unittest.TestCase):
stem.connection.AuthChallengeFailed(None, None),
stem.ControllerError(None))
- auth_method_combinations = mocking.get_all_combinations([
+ auth_method_combinations = test.util.get_all_combinations([
stem.connection.AuthMethod.NONE,
stem.connection.AuthMethod.PASSWORD,
stem.connection.AuthMethod.COOKIE,
@@ -93,7 +94,7 @@ class TestAuthenticate(unittest.TestCase):
stem.connection.AuthMethod.UNKNOWN,
], include_empty = True)
- protocolinfo = mocking.get_protocolinfo_response(cookie_path = '/tmp/blah')
+ protocolinfo = test.util.get_protocolinfo_response(cookie_path = '/tmp/blah')
for auth_methods in auth_method_combinations:
for auth_none_exc in all_auth_none_exc:
diff --git a/test/unit/control/controller.py b/test/unit/control/controller.py
index 47ac9d2..2cf8b7e 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
+import test.util
+
from stem import ControllerError, DescriptorUnavailable, InvalidArguments, InvalidRequest, ProtocolError, UnsatisfiableRequest
from stem.control import _parse_circ_path, Listener, Controller, EventType
from stem.exit_policy import ExitPolicy
-from test import mocking
try:
# added in python 3.3
@@ -338,13 +339,13 @@ class TestControl(unittest.TestCase):
# use the handy mocked protocolinfo response
- get_protocolinfo_mock.return_value = mocking.get_protocolinfo_response()
+ get_protocolinfo_mock.return_value = test.util.get_protocolinfo_response()
# compare the str representation of these object, because the class
# does not have, nor need, a direct comparison operator
self.assertEqual(
- str(mocking.get_protocolinfo_response()),
+ str(test.util.get_protocolinfo_response()),
str(self.controller.get_protocolinfo())
)
diff --git a/test/unit/doctest.py b/test/unit/doctest.py
index 548831a..06a6eaa 100644
--- a/test/unit/doctest.py
+++ b/test/unit/doctest.py
@@ -14,7 +14,6 @@ import stem.util.str_tools
import stem.util.system
import stem.version
-import test.mocking
import test.util
try:
@@ -84,7 +83,7 @@ class TestDocumentation(unittest.TestCase):
'circuit-status': EXPECTED_CIRCUIT_STATUS,
}[arg]
- response = test.mocking.get_message(ADD_ONION_RESPONSE)
+ response = test.util.get_message(ADD_ONION_RESPONSE)
stem.response.convert('ADD_ONION', response)
controller.create_ephemeral_hidden_service.return_value = response
diff --git a/test/unit/interpreter/commands.py b/test/unit/interpreter/commands.py
index 63fedc5..c8cbc09 100644
--- a/test/unit/interpreter/commands.py
+++ b/test/unit/interpreter/commands.py
@@ -5,9 +5,10 @@ import stem
import stem.response
import stem.version
+import test.util
+
from stem.interpreter.commands import ControlInterpreter, _get_fingerprint
-from test import mocking
from test.unit.interpreter import CONTROLLER
try:
@@ -125,7 +126,7 @@ class TestInterpreterCommands(unittest.TestCase):
)
for content in event_contents:
- event = mocking.get_message(content)
+ event = test.util.get_message(content)
stem.response.convert('EVENT', event)
interpreter._received_events.append(event)
@@ -170,7 +171,7 @@ class TestInterpreterCommands(unittest.TestCase):
response = '250-version=0.2.5.1-alpha-dev (git-245ecfff36c0cecc)\r\n250 OK'
controller = Mock()
- controller.msg.return_value = mocking.get_message(response)
+ controller.msg.return_value = test.util.get_message(response)
interpreter = ControlInterpreter(controller)
@@ -185,7 +186,7 @@ class TestInterpreterCommands(unittest.TestCase):
response = '250-Log=notice stdout\r\n250 Address'
controller = Mock()
- controller.msg.return_value = mocking.get_message(response)
+ controller.msg.return_value = test.util.get_message(response)
interpreter = ControlInterpreter(controller)
@@ -194,7 +195,7 @@ class TestInterpreterCommands(unittest.TestCase):
def test_setevents(self):
controller = Mock()
- controller.msg.return_value = mocking.get_message('250 OK')
+ controller.msg.return_value = test.util.get_message('250 OK')
interpreter = ControlInterpreter(controller)
diff --git a/test/unit/response/add_onion.py b/test/unit/response/add_onion.py
index 1213f0c..048ca67 100644
--- a/test/unit/response/add_onion.py
+++ b/test/unit/response/add_onion.py
@@ -8,7 +8,7 @@ import stem
import stem.response
import stem.response.add_onion
-from test import mocking
+import test.util
WITH_PRIVATE_KEY = """250-ServiceID=gfzprpioee3hoppz
250-PrivateKey=RSA1024:MIICXgIBAAKBgQDZvYVxvKPTWhId/8Ss9fVxjAoFDsrJ3pk6HjHrEFRm3ypkK/vArbG9BrupzzYcyms+lO06O8b/iOSHuZI5mUEGkrYqQ+hpB2SkPUEzW7vcp8SQQivna3+LfkWH4JDqfiwZutU6MMEvU6g1OqK4Hll6uHbLpsfxkS/mGjyu1C9a9wIDAQABAoGBAJxsC3a25xZJqaRFfxwmIiptSTFy+/nj4T4gPQo6k/fHMKP/+P7liT9bm+uUwbITNNIjmPzxvrcKt+pNRR/92fizxr8QXr8l0ciVOLerbvdqvVUaQ/K1IVsblOLbactMvXcHactmqqLFUaZU9PPSDla7YkzikLDIUtHXQBEt4HEhAkEA/c4n+kpwi4odCaF49ESPbZC/Qejh7U9Tq10vAHzfrrGgQjnLw2UGDxJQXc9P12fGTvD2q3Q3VaMI8TKKFqZXsQJBANufh1zfP+xX/UfxJ4QzDUCHCu2gnyTDj3nG9Bc80E5g7NwR2VBXF1R+QQCK9GZcXd2y6vBYgrHOSUiLbVjGrycCQQDpOcs0zbjUEUuTsQUT+fiO50dJSrZpus6ZFxz85sMppeItWSzsVeYWbW7adYnZ2Gu72OPjM/0xPYsXEakhHSRRAkAxlVauNQjthv/72god4pi/VL224GiNmEkwKSa6iFRPHbrcBHuXk9IElWx/ft+mrHvUraw1DwaStgv9gNzzCghJAkEA08RegCRnIzuGvgeejLk4suIeCMD/11AvmSvxbRWS5rq1leSVo7uGLSnqDbwlzE4dGb5kH15NNAp14/l2Fu/yZg==
@@ -40,7 +40,7 @@ class TestAddOnionResponse(unittest.TestCase):
"""
# working case
- response = mocking.get_message(WITH_PRIVATE_KEY)
+ response = test.util.get_message(WITH_PRIVATE_KEY)
stem.response.convert('ADD_ONION', response)
# now this should be a AddOnionResponse (ControlMessage subclass)
@@ -57,7 +57,7 @@ class TestAddOnionResponse(unittest.TestCase):
Checks a response when there's a private key.
"""
- response = mocking.get_message(WITH_PRIVATE_KEY)
+ response = test.util.get_message(WITH_PRIVATE_KEY)
stem.response.convert('ADD_ONION', response)
self.assertEqual('gfzprpioee3hoppz', response.service_id)
@@ -70,7 +70,7 @@ class TestAddOnionResponse(unittest.TestCase):
Checks a response when there's client credentials.
"""
- response = mocking.get_message(WITH_CLIENT_AUTH)
+ response = test.util.get_message(WITH_CLIENT_AUTH)
stem.response.convert('ADD_ONION', response)
self.assertEqual('oekn5sqrvcu4wote', response.service_id)
@@ -83,7 +83,7 @@ class TestAddOnionResponse(unittest.TestCase):
Checks a response without a private key.
"""
- response = mocking.get_message(WITHOUT_PRIVATE_KEY)
+ response = test.util.get_message(WITHOUT_PRIVATE_KEY)
stem.response.convert('ADD_ONION', response)
self.assertEqual('gfzprpioee3hoppz', response.service_id)
@@ -95,7 +95,7 @@ class TestAddOnionResponse(unittest.TestCase):
Checks a response that lack an initial service id.
"""
- response = mocking.get_message(WRONG_FIRST_KEY)
+ response = test.util.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):
@@ -103,5 +103,5 @@ class TestAddOnionResponse(unittest.TestCase):
Checks a response that's missing the private key type.
"""
- response = mocking.get_message(MISSING_KEY_TYPE)
+ response = test.util.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/response/authchallenge.py b/test/unit/response/authchallenge.py
index 2185ea8..6a6533c 100644
--- a/test/unit/response/authchallenge.py
+++ b/test/unit/response/authchallenge.py
@@ -8,7 +8,7 @@ import stem.response
import stem.response.authchallenge
import stem.socket
-from test import mocking
+import test.util
VALID_RESPONSE = '250 AUTHCHALLENGE \
SERVERHASH=B16F72DACD4B5ED1531F3FCC04B593D46A1E30267E636EA7C7F8DD7A2B7BAA05 \
@@ -27,7 +27,7 @@ class TestAuthChallengeResponse(unittest.TestCase):
Parses valid AUTHCHALLENGE responses.
"""
- control_message = mocking.get_message(VALID_RESPONSE)
+ control_message = test.util.get_message(VALID_RESPONSE)
stem.response.convert('AUTHCHALLENGE', control_message)
# now this should be a AuthChallengeResponse (ControlMessage subclass)
@@ -51,5 +51,5 @@ class TestAuthChallengeResponse(unittest.TestCase):
# constructed.
remaining_comp = auth_challenge_comp[:index] + auth_challenge_comp[index + 1:]
- control_message = mocking.get_message(' '.join(remaining_comp))
+ control_message = test.util.get_message(' '.join(remaining_comp))
self.assertRaises(stem.ProtocolError, stem.response.convert, 'AUTHCHALLENGE', control_message)
diff --git a/test/unit/response/events.py b/test/unit/response/events.py
index 6023db6..b14b739 100644
--- a/test/unit/response/events.py
+++ b/test/unit/response/events.py
@@ -10,9 +10,10 @@ import stem.response
import stem.response.events
import stem.util.log
+import test.util
+
from stem import * # enums and exceptions
from stem.descriptor.router_status_entry import RouterStatusEntryV3
-from test import mocking
try:
# added in python 3.3
@@ -456,7 +457,7 @@ TB_EMPTY_BAD_2 = '650 TB_EMPTY GLOBAL READ=93 WRITTEN=93 LAST=-100'
def _get_event(content):
- controller_event = mocking.get_message(content)
+ controller_event = test.util.get_message(content)
stem.response.convert('EVENT', controller_event)
return controller_event
diff --git a/test/unit/response/getconf.py b/test/unit/response/getconf.py
index 07c89fd..fb72ffc 100644
--- a/test/unit/response/getconf.py
+++ b/test/unit/response/getconf.py
@@ -8,7 +8,7 @@ import stem.response
import stem.response.getconf
import stem.socket
-from test import mocking
+import test.util
EMPTY_RESPONSE = '250 OK'
@@ -42,7 +42,7 @@ class TestGetConfResponse(unittest.TestCase):
Parses a GETCONF reply without options (just calling "GETCONF").
"""
- control_message = mocking.get_message(EMPTY_RESPONSE)
+ control_message = test.util.get_message(EMPTY_RESPONSE)
stem.response.convert('GETCONF', control_message)
# now this should be a GetConfResponse (ControlMessage subclass)
@@ -56,7 +56,7 @@ class TestGetConfResponse(unittest.TestCase):
Parses a GETCONF reply response for a single parameter.
"""
- control_message = mocking.get_message(SINGLE_RESPONSE)
+ control_message = test.util.get_message(SINGLE_RESPONSE)
stem.response.convert('GETCONF', control_message)
self.assertEqual({'DataDirectory': ['/home/neena/.tor']}, control_message.entries)
@@ -65,7 +65,7 @@ class TestGetConfResponse(unittest.TestCase):
Parses a GETCONF reply for muiltiple parameters.
"""
- control_message = mocking.get_message(BATCH_RESPONSE)
+ control_message = test.util.get_message(BATCH_RESPONSE)
stem.response.convert('GETCONF', control_message)
expected = {
@@ -82,7 +82,7 @@ class TestGetConfResponse(unittest.TestCase):
Parses a GETCONF reply containing a single key with multiple parameters.
"""
- control_message = mocking.get_message(MULTIVALUE_RESPONSE)
+ control_message = test.util.get_message(MULTIVALUE_RESPONSE)
stem.response.convert('GETCONF', control_message)
expected = {
@@ -97,7 +97,7 @@ class TestGetConfResponse(unittest.TestCase):
Parses a GETCONF reply that contains an error code with an unrecognized key.
"""
- control_message = mocking.get_message(UNRECOGNIZED_KEY_RESPONSE)
+ control_message = test.util.get_message(UNRECOGNIZED_KEY_RESPONSE)
self.assertRaises(stem.InvalidArguments, stem.response.convert, 'GETCONF', control_message)
try:
@@ -112,5 +112,5 @@ class TestGetConfResponse(unittest.TestCase):
GETCONF's spec.
"""
- control_message = mocking.get_message(INVALID_RESPONSE)
+ control_message = test.util.get_message(INVALID_RESPONSE)
self.assertRaises(stem.ProtocolError, stem.response.convert, 'GETCONF', control_message)
diff --git a/test/unit/response/getinfo.py b/test/unit/response/getinfo.py
index afd0748..2054a03 100644
--- a/test/unit/response/getinfo.py
+++ b/test/unit/response/getinfo.py
@@ -9,7 +9,7 @@ import stem.response.getinfo
import stem.socket
import stem.util.str_tools
-from test import mocking
+import test.util
EMPTY_RESPONSE = '250 OK'
@@ -57,7 +57,7 @@ class TestGetInfoResponse(unittest.TestCase):
Parses a GETINFO reply without options (just calling "GETINFO").
"""
- control_message = mocking.get_message(EMPTY_RESPONSE)
+ control_message = test.util.get_message(EMPTY_RESPONSE)
stem.response.convert('GETINFO', control_message)
# now this should be a GetInfoResponse (ControlMessage subclass)
@@ -71,7 +71,7 @@ class TestGetInfoResponse(unittest.TestCase):
Parses a GETINFO reply response for a single parameter.
"""
- control_message = mocking.get_message(SINGLE_RESPONSE)
+ control_message = test.util.get_message(SINGLE_RESPONSE)
stem.response.convert('GETINFO', control_message)
self.assertEqual({'version': b'0.2.3.11-alpha-dev'}, control_message.entries)
@@ -80,7 +80,7 @@ class TestGetInfoResponse(unittest.TestCase):
Parses a GETINFO reply for muiltiple parameters.
"""
- control_message = mocking.get_message(BATCH_RESPONSE)
+ control_message = test.util.get_message(BATCH_RESPONSE)
stem.response.convert('GETINFO', control_message)
expected = {
@@ -97,7 +97,7 @@ class TestGetInfoResponse(unittest.TestCase):
value.
"""
- control_message = mocking.get_message(MULTILINE_RESPONSE)
+ control_message = test.util.get_message(MULTILINE_RESPONSE)
stem.response.convert('GETINFO', control_message)
expected = {
@@ -113,7 +113,7 @@ class TestGetInfoResponse(unittest.TestCase):
entry.
"""
- control_message = mocking.get_message(NON_KEY_VALUE_ENTRY)
+ control_message = test.util.get_message(NON_KEY_VALUE_ENTRY)
self.assertRaises(stem.ProtocolError, stem.response.convert, 'GETINFO', control_message)
def test_unrecognized_key_response(self):
@@ -121,7 +121,7 @@ class TestGetInfoResponse(unittest.TestCase):
Parses a GETCONF reply that contains an error code with an unrecognized key.
"""
- control_message = mocking.get_message(UNRECOGNIZED_KEY_ENTRY)
+ control_message = test.util.get_message(UNRECOGNIZED_KEY_ENTRY)
self.assertRaises(stem.InvalidArguments, stem.response.convert, 'GETINFO', control_message)
try:
@@ -136,5 +136,5 @@ class TestGetInfoResponse(unittest.TestCase):
malformed according to the GETINFO's spec.
"""
- control_message = mocking.get_message(MISSING_MULTILINE_NEWLINE)
+ control_message = test.util.get_message(MISSING_MULTILINE_NEWLINE)
self.assertRaises(stem.ProtocolError, stem.response.convert, 'GETINFO', control_message)
diff --git a/test/unit/response/mapaddress.py b/test/unit/response/mapaddress.py
index 753f2e6..63813d4 100644
--- a/test/unit/response/mapaddress.py
+++ b/test/unit/response/mapaddress.py
@@ -8,7 +8,7 @@ import stem.response
import stem.response.mapaddress
import stem.socket
-from test import mocking
+import test.util
SINGLE_RESPONSE = """250 foo=bar"""
@@ -36,7 +36,7 @@ class TestMapAddressResponse(unittest.TestCase):
Parses a MAPADDRESS reply response with a single address mapping.
"""
- control_message = mocking.get_message(SINGLE_RESPONSE)
+ control_message = test.util.get_message(SINGLE_RESPONSE)
stem.response.convert('MAPADDRESS', control_message)
self.assertEqual({'foo': 'bar'}, control_message.entries)
@@ -45,7 +45,7 @@ class TestMapAddressResponse(unittest.TestCase):
Parses a MAPADDRESS reply with multiple address mappings
"""
- control_message = mocking.get_message(BATCH_RESPONSE)
+ control_message = test.util.get_message(BATCH_RESPONSE)
stem.response.convert('MAPADDRESS', control_message)
expected = {
@@ -62,11 +62,11 @@ class TestMapAddressResponse(unittest.TestCase):
Parses a MAPADDRESS replies that contain an error code due to hostname syntax errors.
"""
- control_message = mocking.get_message(UNRECOGNIZED_KEYS_RESPONSE)
+ control_message = test.util.get_message(UNRECOGNIZED_KEYS_RESPONSE)
self.assertRaises(stem.InvalidRequest, stem.response.convert, 'MAPADDRESS', control_message)
expected = {'23': '324'}
- control_message = mocking.get_message(PARTIAL_FAILURE_RESPONSE)
+ control_message = test.util.get_message(PARTIAL_FAILURE_RESPONSE)
stem.response.convert('MAPADDRESS', control_message)
self.assertEqual(expected, control_message.entries)
@@ -77,8 +77,8 @@ class TestMapAddressResponse(unittest.TestCase):
MAPADDRESS's spec.
"""
- control_message = mocking.get_message(INVALID_EMPTY_RESPONSE)
+ control_message = test.util.get_message(INVALID_EMPTY_RESPONSE)
self.assertRaises(stem.ProtocolError, stem.response.convert, 'MAPADDRESS', control_message)
- control_message = mocking.get_message(INVALID_RESPONSE)
+ control_message = test.util.get_message(INVALID_RESPONSE)
self.assertRaises(stem.ProtocolError, stem.response.convert, 'MAPADDRESS', control_message)
diff --git a/test/unit/response/protocolinfo.py b/test/unit/response/protocolinfo.py
index c95076a..d8fb762 100644
--- a/test/unit/response/protocolinfo.py
+++ b/test/unit/response/protocolinfo.py
@@ -12,8 +12,9 @@ import stem.util.proc
import stem.util.system
import stem.version
+import test.util
+
from stem.response.protocolinfo import AuthMethod
-from test import mocking
try:
# added in python 3.3
@@ -70,7 +71,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
"""
# working case
- control_message = mocking.get_message(NO_AUTH)
+ control_message = test.util.get_message(NO_AUTH)
stem.response.convert('PROTOCOLINFO', control_message)
# now this should be a ProtocolInfoResponse (ControlMessage subclass)
@@ -86,7 +87,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
self.assertRaises(TypeError, stem.response.convert, 'PROTOCOLINFO', 'hello world')
# attempt to convert a different message type
- bw_event_control_message = mocking.get_message('650 BW 32326 2856')
+ bw_event_control_message = test.util.get_message('650 BW 32326 2856')
self.assertRaises(stem.ProtocolError, stem.response.convert, 'PROTOCOLINFO', bw_event_control_message)
def test_no_auth(self):
@@ -94,7 +95,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
Checks a response when there's no authentication.
"""
- control_message = mocking.get_message(NO_AUTH)
+ control_message = test.util.get_message(NO_AUTH)
stem.response.convert('PROTOCOLINFO', control_message)
self.assertEqual(1, control_message.protocol_version)
@@ -108,7 +109,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
Checks a response with password authentication.
"""
- control_message = mocking.get_message(PASSWORD_AUTH)
+ control_message = test.util.get_message(PASSWORD_AUTH)
stem.response.convert('PROTOCOLINFO', control_message)
self.assertEqual((AuthMethod.PASSWORD, ), control_message.auth_methods)
@@ -118,7 +119,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
characters.
"""
- control_message = mocking.get_message(COOKIE_AUTH)
+ control_message = test.util.get_message(COOKIE_AUTH)
stem.response.convert('PROTOCOLINFO', control_message)
self.assertEqual((AuthMethod.COOKIE, ), control_message.auth_methods)
self.assertEqual('/tmp/my data\\"dir//control_auth_cookie', control_message.cookie_path)
@@ -128,7 +129,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
Checks a response with multiple authentication methods.
"""
- control_message = mocking.get_message(MULTIPLE_AUTH)
+ control_message = test.util.get_message(MULTIPLE_AUTH)
stem.response.convert('PROTOCOLINFO', control_message)
self.assertEqual((AuthMethod.COOKIE, AuthMethod.PASSWORD), control_message.auth_methods)
self.assertEqual('/home/atagar/.tor/control_auth_cookie', control_message.cookie_path)
@@ -138,7 +139,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
Checks a response with an unrecognized authtentication method.
"""
- control_message = mocking.get_message(UNKNOWN_AUTH)
+ control_message = test.util.get_message(UNKNOWN_AUTH)
stem.response.convert('PROTOCOLINFO', control_message)
self.assertEqual((AuthMethod.UNKNOWN, AuthMethod.PASSWORD), control_message.auth_methods)
self.assertEqual(('MAGIC', 'PIXIE_DUST'), control_message.unknown_auth_methods)
@@ -149,7 +150,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
information to be a valid response.
"""
- control_message = mocking.get_message(MINIMUM_RESPONSE)
+ control_message = test.util.get_message(MINIMUM_RESPONSE)
stem.response.convert('PROTOCOLINFO', control_message)
self.assertEqual(5, control_message.protocol_version)
@@ -164,7 +165,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
Checks an authentication cookie with a unicode path.
"""
- control_message = mocking.get_message(UNICODE_COOKIE_PATH)
+ control_message = test.util.get_message(UNICODE_COOKIE_PATH)
stem.response.convert('PROTOCOLINFO', control_message)
self.assertEqual(EXPECTED_UNICODE_PATH, control_message.cookie_path)
@@ -190,7 +191,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
with patch('stem.util.system.call') as call_mock:
call_mock.side_effect = call_function
- control_message = mocking.get_message(RELATIVE_COOKIE_PATH)
+ control_message = test.util.get_message(RELATIVE_COOKIE_PATH)
stem.response.convert('PROTOCOLINFO', control_message)
stem.connection._expand_cookie_path(control_message, stem.util.system.pid_by_name, 'tor')
@@ -201,6 +202,6 @@ class TestProtocolInfoResponse(unittest.TestCase):
# leaving the path unexpanded)
with patch('stem.util.system.call', Mock(return_value = None)):
- control_message = mocking.get_message(RELATIVE_COOKIE_PATH)
+ control_message = test.util.get_message(RELATIVE_COOKIE_PATH)
stem.response.convert('PROTOCOLINFO', control_message)
self.assertEqual('./tor-browser_en-US/Data/control_auth_cookie', control_message.cookie_path)
diff --git a/test/unit/response/singleline.py b/test/unit/response/singleline.py
index 3567d59..1c05aa5 100644
--- a/test/unit/response/singleline.py
+++ b/test/unit/response/singleline.py
@@ -7,7 +7,7 @@ import unittest
import stem.response
import stem.socket
-from test import mocking
+import test.util
MULTILINE_RESPONSE = """250-MULTI
250 LINE"""
@@ -15,22 +15,22 @@ MULTILINE_RESPONSE = """250-MULTI
class TestSingleLineResponse(unittest.TestCase):
def test_single_line_response(self):
- message = mocking.get_message('552 NOTOK')
+ message = test.util.get_message('552 NOTOK')
stem.response.convert('SINGLELINE', message)
self.assertEqual(False, message.is_ok())
- message = mocking.get_message('250 KK')
+ message = test.util.get_message('250 KK')
stem.response.convert('SINGLELINE', message)
self.assertEqual(True, message.is_ok())
- message = mocking.get_message('250 OK')
+ message = test.util.get_message('250 OK')
stem.response.convert('SINGLELINE', message)
self.assertEqual(True, message.is_ok(True))
- message = mocking.get_message('250 HMM')
+ message = test.util.get_message('250 HMM')
stem.response.convert('SINGLELINE', message)
self.assertEqual(False, message.is_ok(True))
def test_multi_line_response(self):
- message = mocking.get_message(MULTILINE_RESPONSE)
+ message = test.util.get_message(MULTILINE_RESPONSE)
self.assertRaises(stem.ProtocolError, stem.response.convert, 'SINGLELINE', message)
diff --git a/test/unit/tutorial_examples.py b/test/unit/tutorial_examples.py
index c979f07..2075bdf 100644
--- a/test/unit/tutorial_examples.py
+++ b/test/unit/tutorial_examples.py
@@ -15,6 +15,8 @@ import stem.response
import stem.descriptor.remote
import stem.prereq
+import test.util
+
from stem.control import Controller
from stem.util import str_type
from stem.descriptor.networkstatus import NetworkStatusDocumentV3
@@ -22,7 +24,6 @@ from stem.descriptor.remote import DIRECTORY_AUTHORITIES
from stem.descriptor.router_status_entry import ROUTER_STATUS_ENTRY_V3_HEADER, RouterStatusEntryV3
from stem.descriptor.server_descriptor import RelayDescriptor
-from test import mocking
from test.unit import exec_documentation_example
try:
@@ -99,7 +100,7 @@ A7569A83B5706AB1B1A9CB52EFF7D2D32E4553EB: caerSidi
def _get_event(content):
- controller_event = mocking.get_message(content)
+ controller_event = test.util.get_message(content)
stem.response.convert('EVENT', controller_event)
return controller_event
diff --git a/test/unit/util/proc.py b/test/unit/util/proc.py
index 5f65212..00f2af0 100644
--- a/test/unit/util/proc.py
+++ b/test/unit/util/proc.py
@@ -6,9 +6,10 @@ import io
import re
import unittest
+import test.util
+
from stem.util import proc
from stem.util.connection import Connection
-from test import mocking
try:
from unittest.mock import Mock, patch
@@ -105,7 +106,7 @@ class TestProc(unittest.TestCase):
"""
# list of all combinations of args with respective return values
- stat_combinations = mocking.get_all_combinations([
+ stat_combinations = test.util.get_all_combinations([
('command', 'test_program'),
('utime', '0.13'),
('stime', '0.14'),
diff --git a/test/util.py b/test/util.py
index 864baab..7b6f312 100644
--- a/test/util.py
+++ b/test/util.py
@@ -18,6 +18,21 @@ Tasks are...
::
+ Initialization
+ |- check_stem_version - checks our version of stem
+ |- check_tor_version - checks our version of tor
+ |- check_python_version - checks our version of python
+ |- check_cryptography_version - checks our version of cryptography
+ |- check_pynacl_version - checks our version of pynacl
+ |- check_pyflakes_version - checks our version of pyflakes
+ |- check_pycodestyle_version - checks our version of pycodestyle
+ |- clean_orphaned_pyc - removes any *.pyc without a corresponding *.py
+ +- check_for_unused_tests - checks to see if any tests are missing from our settings
+
+Lastly, this module provides generally useful test helpers...
+
+::
+
Test Requirements
|- only_run_once - skip test if it has been ran before
|- require - skips the test unless a requirement is met
@@ -32,20 +47,15 @@ Tasks are...
|- require_ptrace - requires 'DisableDebuggerAttachment' to be set
+- require_online - skips unless targets allow for online tests
- Initialization
- |- check_stem_version - checks our version of stem
- |- check_tor_version - checks our version of tor
- |- check_python_version - checks our version of python
- |- check_cryptography_version - checks our version of cryptography
- |- check_pynacl_version - checks our version of pynacl
- |- check_pyflakes_version - checks our version of pyflakes
- |- check_pycodestyle_version - checks our version of pycodestyle
- |- clean_orphaned_pyc - removes any *.pyc without a corresponding *.py
- +- check_for_unused_tests - checks to see if any tests are missing from our settings
-
+ get_message - provides a ControlMessage instance
+ get_protocolinfo_response - provides a ProtocolInfoResponse instance
+ get_all_combinations - provides all combinations of attributes
+ random_fingerprint - provides a random relay fingerprint
tor_version - provides the version of tor we're testing against
"""
+import hashlib
+import itertools
import re
import os
import sys
@@ -464,6 +474,94 @@ def run_tasks(category, *tasks):
println()
+def get_all_combinations(attr, include_empty = False):
+ """
+ Provides an iterator for all combinations of a set of attributes. For
+ instance...
+
+ ::
+
+ >>> list(test.mocking.get_all_combinations(['a', 'b', 'c']))
+ [('a',), ('b',), ('c',), ('a', 'b'), ('a', 'c'), ('b', 'c'), ('a', 'b', 'c')]
+
+ :param list attr: attributes to provide combinations for
+ :param bool include_empty: includes an entry with zero items if True
+ :returns: iterator for all combinations
+ """
+
+ # Makes an itertools.product() call for 'i' copies of attr...
+ #
+ # * itertools.product(attr) => all one-element combinations
+ # * itertools.product(attr, attr) => all two-element combinations
+ # * ... etc
+
+ if include_empty:
+ yield ()
+
+ seen = set()
+ for index in range(1, len(attr) + 1):
+ product_arg = [attr for _ in range(index)]
+
+ for item in itertools.product(*product_arg):
+ # deduplicate, sort, and only provide if we haven't seen it yet
+ item = tuple(sorted(set(item)))
+
+ if item not in seen:
+ seen.add(item)
+ yield item
+
+
+def random_fingerprint():
+ """
+ Provides a random relay fingerprint.
+ """
+
+ return hashlib.sha1(os.urandom(20)).hexdigest().upper()
+
+
+def get_message(content, reformat = True):
+ """
+ Provides a ControlMessage with content modified to be parsable. This makes
+ the following changes unless 'reformat' is false...
+
+ * ensures the content ends with a newline
+ * newlines are replaced with a carriage return and newline pair
+
+ :param str content: base content for the controller message
+ :param str reformat: modifies content to be more accommodating to being parsed
+
+ :returns: stem.response.ControlMessage instance
+ """
+
+ if reformat:
+ if not content.endswith('\n'):
+ content += '\n'
+
+ content = re.sub('([\r]?)\n', '\r\n', content)
+
+ return stem.response.ControlMessage.from_str(content)
+
+
+def get_protocolinfo_response(**attributes):
+ """
+ Provides a ProtocolInfoResponse, customized with the given attributes. The
+ base instance is minimal, with its version set to one and everything else
+ left with the default.
+
+ :param dict attributes: attributes to customize the response with
+
+ :returns: stem.response.protocolinfo.ProtocolInfoResponse instance
+ """
+
+ protocolinfo_response = get_message('250-PROTOCOLINFO 1\n250 OK')
+ stem.response.convert('PROTOCOLINFO', protocolinfo_response)
+
+ for attr in attributes:
+ setattr(protocolinfo_response, attr, attributes[attr])
+
+ return protocolinfo_response
+
+
def tor_version():
"""
Provides the version of tor we're testing against.