[tor-commits] [stem/master] Using mocking module for protocolinfo unit tests

atagar at torproject.org atagar at torproject.org
Sun Jan 29 08:54:42 UTC 2012


commit 9a2b50138356f317220819b2351f666bd45564e1
Author: Damian Johnson <atagar at torproject.org>
Date:   Fri Jan 27 18:53:39 2012 -0800

    Using mocking module for protocolinfo unit tests
    
    Expanding the mocking module to provide a ControlMessage (very frequently
    needed in tests) and using the module to simplify the protocolinfo unit tests.
---
 test/mocking.py                      |   38 +++++++++++++++++++----
 test/unit/connection/protocolinfo.py |   54 +++++++++++++++-------------------
 2 files changed, 55 insertions(+), 37 deletions(-)

diff --git a/test/mocking.py b/test/mocking.py
index f6bf98c..0d01a60 100644
--- a/test/mocking.py
+++ b/test/mocking.py
@@ -1,6 +1,11 @@
 """
 Helper functions for creating mock objects and monkey patching to help with
-testing.
+testing. With python's builtin unit testing framework the setUp and test
+functions set up mocking, which is then reverted in the tearDown method by
+calling 'revert_mocking'.
+
+mock - replaces a function with an alternative implementation
+revert_mocking - reverts any changes made by the mock function
 
 Mocking Functions
   no_op           - does nothing
@@ -10,10 +15,9 @@ Mocking Functions
   return_none     - returns None
   raise_exception - raises an exception when called
 
-mock - replaces a function with an alternative implementation
-revert_mocking - reverts any changes made by the mock function
-
-get_protocolinfo_response - provides a ProtocolInfoResponse instance
+Instance Constructors
+  get_message               - stem.socket.ControlMessage
+  get_protocolinfo_response - stem.connection.ProtocolInfoResponse
 """
 
 import inspect
@@ -94,6 +98,27 @@ def revert_mocking():
   
   MOCK_STATE.clear()
 
+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 carrage return and newline pair
+  
+  Arguments:
+    content (str)  - base content for the controller message
+    reformat (str) - modifies content to be more accomidateing to being parsed
+  
+  Returns:
+    stem.socket.ControlMessage instance
+  """
+  
+  if reformat:
+    if not content.endswith("\n"): content += "\n"
+    content = content.replace("\n", "\r\n")
+  
+  return stem.socket.recv_message(StringIO.StringIO(content))
+
 def get_protocolinfo_response(**attributes):
   """
   Provides a ProtocolInfoResponse, customized with the given attributes. The
@@ -107,8 +132,7 @@ def get_protocolinfo_response(**attributes):
     stem.connection.ProtocolInfoResponse instance
   """
   
-  control_message = "250-PROTOCOLINFO 1\r\n250 OK\r\n"
-  protocolinfo_response = stem.socket.recv_message(StringIO.StringIO(control_message))
+  protocolinfo_response = get_message("250-PROTOCOLINFO 1\n250 OK")
   stem.connection.ProtocolInfoResponse.convert(protocolinfo_response)
   
   for attr in attributes:
diff --git a/test/unit/connection/protocolinfo.py b/test/unit/connection/protocolinfo.py
index bc0fef3..0f47fe1 100644
--- a/test/unit/connection/protocolinfo.py
+++ b/test/unit/connection/protocolinfo.py
@@ -3,51 +3,44 @@ Unit tests for the stem.connection.ProtocolInfoResponse class.
 """
 
 import unittest
-import StringIO
 
 import stem.connection
 import stem.socket
 import stem.version
+import test.mocking as mocking
 
 NO_AUTH = """250-PROTOCOLINFO 1
 250-AUTH METHODS=NULL
 250-VERSION Tor="0.2.1.30"
-250 OK
-""".replace("\n", "\r\n")
+250 OK"""
 
 PASSWORD_AUTH = """250-PROTOCOLINFO 1
 250-AUTH METHODS=HASHEDPASSWORD
 250-VERSION Tor="0.2.1.30"
-250 OK
-""".replace("\n", "\r\n")
+250 OK"""
 
 COOKIE_AUTH = r"""250-PROTOCOLINFO 1
 250-AUTH METHODS=COOKIE COOKIEFILE="/tmp/my data\\\"dir//control_auth_cookie"
 250-VERSION Tor="0.2.1.30"
-250 OK
-""".replace("\n", "\r\n")
+250 OK"""
 
 MULTIPLE_AUTH = """250-PROTOCOLINFO 1
 250-AUTH METHODS=COOKIE,HASHEDPASSWORD COOKIEFILE="/home/atagar/.tor/control_auth_cookie"
 250-VERSION Tor="0.2.1.30"
-250 OK
-""".replace("\n", "\r\n")
+250 OK"""
 
 UNKNOWN_AUTH = """250-PROTOCOLINFO 1
 250-AUTH METHODS=MAGIC,HASHEDPASSWORD,PIXIE_DUST
 250-VERSION Tor="0.2.1.30"
-250 OK
-""".replace("\n", "\r\n")
+250 OK"""
 
 MINIMUM_RESPONSE = """250-PROTOCOLINFO 5
-250 OK
-""".replace("\n", "\r\n")
+250 OK"""
 
 RELATIVE_COOKIE_PATH = r"""250-PROTOCOLINFO 1
 250-AUTH METHODS=COOKIE COOKIEFILE="./tor-browser_en-US/Data/control_auth_cookie"
 250-VERSION Tor="0.2.1.30"
-250 OK
-""".replace("\n", "\r\n")
+250 OK"""
 
 class TestProtocolInfoResponse(unittest.TestCase):
   """
@@ -61,7 +54,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
     """
     
     # working case
-    control_message = stem.socket.recv_message(StringIO.StringIO(NO_AUTH))
+    control_message = mocking.get_message(NO_AUTH)
     stem.connection.ProtocolInfoResponse.convert(control_message)
     
     # now this should be a ProtocolInfoResponse (ControlMessage subclass)
@@ -69,14 +62,15 @@ class TestProtocolInfoResponse(unittest.TestCase):
     self.assertTrue(isinstance(control_message, stem.connection.ProtocolInfoResponse))
     
     # exercise some of the ControlMessage functionality
+    raw_content = (NO_AUTH + "\n").replace("\n", "\r\n")
+    self.assertEquals(raw_content, control_message.raw_content())
     self.assertTrue(str(control_message).startswith("PROTOCOLINFO 1"))
-    self.assertEquals(NO_AUTH, control_message.raw_content())
     
     # attempt to convert the wrong type
     self.assertRaises(TypeError, stem.connection.ProtocolInfoResponse.convert, "hello world")
     
     # attempt to convert a different message type
-    bw_event_control_message = stem.socket.recv_message(StringIO.StringIO("650 BW 32326 2856\r\n"))
+    bw_event_control_message = mocking.get_message("650 BW 32326 2856")
     self.assertRaises(stem.socket.ProtocolError, stem.connection.ProtocolInfoResponse.convert, bw_event_control_message)
   
   def test_no_auth(self):
@@ -84,7 +78,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
     Checks a response when there's no authentication.
     """
     
-    control_message = stem.socket.recv_message(StringIO.StringIO(NO_AUTH))
+    control_message = mocking.get_message(NO_AUTH)
     stem.connection.ProtocolInfoResponse.convert(control_message)
     
     self.assertEquals(1, control_message.protocol_version)
@@ -98,7 +92,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
     Checks a response with password authentication.
     """
     
-    control_message = stem.socket.recv_message(StringIO.StringIO(PASSWORD_AUTH))
+    control_message = mocking.get_message(PASSWORD_AUTH)
     stem.connection.ProtocolInfoResponse.convert(control_message)
     self.assertEquals((stem.connection.AuthMethod.PASSWORD, ), control_message.auth_methods)
   
@@ -108,7 +102,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
     characters.
     """
     
-    control_message = stem.socket.recv_message(StringIO.StringIO(COOKIE_AUTH))
+    control_message = mocking.get_message(COOKIE_AUTH)
     stem.connection.ProtocolInfoResponse.convert(control_message)
     self.assertEquals((stem.connection.AuthMethod.COOKIE, ), control_message.auth_methods)
     self.assertEquals("/tmp/my data\\\"dir//control_auth_cookie", control_message.cookie_path)
@@ -118,7 +112,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
     Checks a response with multiple authentication methods.
     """
     
-    control_message = stem.socket.recv_message(StringIO.StringIO(MULTIPLE_AUTH))
+    control_message = mocking.get_message(MULTIPLE_AUTH)
     stem.connection.ProtocolInfoResponse.convert(control_message)
     self.assertEquals((stem.connection.AuthMethod.COOKIE, stem.connection.AuthMethod.PASSWORD), control_message.auth_methods)
     self.assertEquals("/home/atagar/.tor/control_auth_cookie", control_message.cookie_path)
@@ -128,7 +122,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
     Checks a response with an unrecognized authtentication method.
     """
     
-    control_message = stem.socket.recv_message(StringIO.StringIO(UNKNOWN_AUTH))
+    control_message = mocking.get_message(UNKNOWN_AUTH)
     stem.connection.ProtocolInfoResponse.convert(control_message)
     self.assertEquals((stem.connection.AuthMethod.UNKNOWN, stem.connection.AuthMethod.PASSWORD), control_message.auth_methods)
     self.assertEquals(("MAGIC", "PIXIE_DUST"), control_message.unknown_auth_methods)
@@ -139,7 +133,7 @@ class TestProtocolInfoResponse(unittest.TestCase):
     information to be a valid response.
     """
     
-    control_message = stem.socket.recv_message(StringIO.StringIO(MINIMUM_RESPONSE))
+    control_message = mocking.get_message(MINIMUM_RESPONSE)
     stem.connection.ProtocolInfoResponse.convert(control_message)
     
     self.assertEquals(5, control_message.protocol_version)
@@ -162,23 +156,23 @@ class TestProtocolInfoResponse(unittest.TestCase):
     def call_mocking(command):
       if command == stem.util.system.GET_PID_BY_NAME_PGREP % "tor":
         return ["10"]
-      if command == stem.util.system.GET_CWD_PWDX % 10:
+      elif command == stem.util.system.GET_CWD_PWDX % 10:
         return ["10: /tmp/foo"]
     
-    stem.util.system.CALL_MOCKING = call_mocking
+    mocking.mock(stem.util.system.call, call_mocking)
     
-    control_message = stem.socket.recv_message(StringIO.StringIO(RELATIVE_COOKIE_PATH))
+    control_message = mocking.get_message(RELATIVE_COOKIE_PATH)
     stem.connection.ProtocolInfoResponse.convert(control_message)
     self.assertEquals("/tmp/foo/tor-browser_en-US/Data/control_auth_cookie", control_message.cookie_path)
     
     # exercise cookie expansion where both calls fail (should work, just
     # leaving the path unexpanded)
     
-    stem.util.system.CALL_MOCKING = lambda cmd: None
-    control_message = stem.socket.recv_message(StringIO.StringIO(RELATIVE_COOKIE_PATH))
+    mocking.mock(stem.util.system.call, mocking.return_none())
+    control_message = mocking.get_message(RELATIVE_COOKIE_PATH)
     stem.connection.ProtocolInfoResponse.convert(control_message)
     self.assertEquals("./tor-browser_en-US/Data/control_auth_cookie", control_message.cookie_path)
     
     # reset system call mocking
-    stem.util.system.CALL_MOCKING = None
+    mocking.revert_mocking()
 





More information about the tor-commits mailing list