[tor-commits] [stem/master] Testing for STATUS_* events

atagar at torproject.org atagar at torproject.org
Mon Dec 3 02:35:44 UTC 2012


commit e59de80010d1894c5eecb7d4b9d953ee195a5259
Author: Damian Johnson <atagar at torproject.org>
Date:   Sun Dec 2 03:00:51 2012 -0800

    Testing for STATUS_* events
    
    I had grand plans to have a StatusEvent subclass for each of the causes.
    However, on reflection that would encompass a bundle of work that's almost as
    large as all of the other events put together. It might still be a neat thing
    to do someday, but there's plenty of higher priority things to do first.
    
    Adding tests for all of the event examples that I collected earlier. This
    includes a bit of a hack to make quoted key/value mappings work. Previously
    we've only parsed quoted mappings if they belonged to the _QUOTED listing, but
    STATUS_* events sprinkle them all around so for forward compatability we can't
    simply enumerate them.
---
 stem/response/events.py      |   31 ++++++--
 test/unit/response/events.py |  159 +++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 182 insertions(+), 8 deletions(-)

diff --git a/stem/response/events.py b/stem/response/events.py
index d580829..96764a0 100644
--- a/stem/response/events.py
+++ b/stem/response/events.py
@@ -34,6 +34,11 @@ class Event(stem.response.ControlMessage):
   _QUOTED = ()
   _SKIP_PARSING = False
   
+  # If set then we'll parse anything that looks like a quoted key/value
+  # mapping, reguardless of if it shows up in _QUOTED.
+  
+  _PERMISSIVE_QUOTED_MAPPINGS = False
+  
   def _parse_message(self, arrived_at):
     if not str(self).strip():
       raise stem.ProtocolError("Received a blank tor event. Events must at the very least have a type.")
@@ -73,13 +78,24 @@ class Event(stem.response.ControlMessage):
     
     content = str(self)
     
-    for keyword in set(self._QUOTED).intersection(set(self._KEYWORD_ARGS.keys())):
-      match = re.match("^(.*) %s=\"(.*)\"(.*)$" % keyword, content)
-      
-      if match:
-        prefix, value, suffix = match.groups()
-        content = prefix + suffix
-        self.keyword_args[keyword] = value
+    if self._PERMISSIVE_QUOTED_MAPPINGS:
+      while True:
+        match = re.match("^(.*) (\S*)=\"(.*)\"(.*)$", content)
+        
+        if match:
+          prefix, keyword, value, suffix = match.groups()
+          content = prefix + suffix
+          self.keyword_args[keyword] = value
+        else:
+          break
+    else:
+      for keyword in set(self._QUOTED).intersection(set(self._KEYWORD_ARGS.keys())):
+        match = re.match("^(.*) %s=\"(.*)\"(.*)$" % keyword, content)
+        
+        if match:
+          prefix, value, suffix = match.groups()
+          content = prefix + suffix
+          self.keyword_args[keyword] = value
     
     fields = content.split()[1:]
     
@@ -423,6 +439,7 @@ class StatusEvent(Event):
   """
   
   _POSITIONAL_ARGS = ("runlevel", "action")
+  _PERMISSIVE_QUOTED_MAPPINGS = True
   
   def _parse(self):
     if self.type == 'STATUS_GENERAL':
diff --git a/test/unit/response/events.py b/test/unit/response/events.py
index fc796a2..54d4777 100644
--- a/test/unit/response/events.py
+++ b/test/unit/response/events.py
@@ -378,7 +378,7 @@ class TestEvents(unittest.TestCase):
     self.assertEqual(ORClosureReason.DONE, event.reason)
     self.assertEqual(None, event.circ_count)
   
-  def test_status_event(self):
+  def test_status_event_consensus_arrived(self):
     event = _get_event(STATUS_CLIENT_CONSENSUS_ARRIVED)
     
     self.assertTrue(isinstance(event, stem.response.events.StatusEvent))
@@ -387,6 +387,163 @@ class TestEvents(unittest.TestCase):
     self.assertEqual(Runlevel.NOTICE, event.runlevel)
     self.assertEqual("CONSENSUS_ARRIVED", event.action)
   
+  def test_status_event_enough_dir_info(self):
+    event = _get_event(STATUS_CLIENT_ENOUGH_DIR_INFO)
+    
+    self.assertEqual(StatusType.CLIENT, event.status_type)
+    self.assertEqual(Runlevel.NOTICE, event.runlevel)
+    self.assertEqual("ENOUGH_DIR_INFO", event.action)
+  
+  def test_status_event_circuit_established(self):
+    event = _get_event(STATUS_CLIENT_CIRC_ESTABLISHED)
+    
+    self.assertEqual(StatusType.CLIENT, event.status_type)
+    self.assertEqual(Runlevel.NOTICE, event.runlevel)
+    self.assertEqual("CIRCUIT_ESTABLISHED", event.action)
+  
+  def test_status_event_bootstrap_descriptors(self):
+    event = _get_event(STATUS_CLIENT_BOOTSTRAP_DESCRIPTORS)
+    
+    self.assertEqual(StatusType.CLIENT, event.status_type)
+    self.assertEqual(Runlevel.NOTICE, event.runlevel)
+    self.assertEqual("BOOTSTRAP", event.action)
+    
+    expected_attr = {
+      'PROGRESS': '53',
+      'TAG': 'loading_descriptors',
+      'SUMMARY': 'Loading relay descriptors',
+    }
+    
+    self.assertEqual(expected_attr, event.keyword_args)
+  
+  def test_status_event_bootstrap_stuck(self):
+    event = _get_event(STATUS_CLIENT_BOOTSTRAP_STUCK)
+    
+    self.assertEqual(StatusType.CLIENT, event.status_type)
+    self.assertEqual(Runlevel.WARN, event.runlevel)
+    self.assertEqual("BOOTSTRAP", event.action)
+    
+    expected_attr = {
+      'PROGRESS': '80',
+      'TAG': 'conn_or',
+      'SUMMARY': 'Connecting to the Tor network',
+      'WARNING': 'Network is unreachable',
+      'REASON': 'NOROUTE',
+      'COUNT': '5',
+      'RECOMMENDATION': 'warn',
+    }
+    
+    self.assertEqual(expected_attr, event.keyword_args)
+  
+  def test_status_event_bootstrap_connecting(self):
+    event = _get_event(STATUS_CLIENT_BOOTSTRAP_CONNECTING)
+    
+    self.assertEqual(StatusType.CLIENT, event.status_type)
+    self.assertEqual(Runlevel.NOTICE, event.runlevel)
+    self.assertEqual("BOOTSTRAP", event.action)
+    
+    expected_attr = {
+      'PROGRESS': '80',
+      'TAG': 'conn_or',
+      'SUMMARY': 'Connecting to the Tor network',
+    }
+    
+    self.assertEqual(expected_attr, event.keyword_args)
+  
+  def test_status_event_bootstrap_first_handshake(self):
+    event = _get_event(STATUS_CLIENT_BOOTSTRAP_FIRST_HANDSHAKE)
+    
+    self.assertEqual(StatusType.CLIENT, event.status_type)
+    self.assertEqual(Runlevel.NOTICE, event.runlevel)
+    self.assertEqual("BOOTSTRAP", event.action)
+    
+    expected_attr = {
+      'PROGRESS': '85',
+      'TAG': 'handshake_or',
+      'SUMMARY': 'Finishing handshake with first hop',
+    }
+    
+    self.assertEqual(expected_attr, event.keyword_args)
+  
+  def test_status_event_bootstrap_established(self):
+    event = _get_event(STATUS_CLIENT_BOOTSTRAP_ESTABLISHED)
+    
+    self.assertEqual(StatusType.CLIENT, event.status_type)
+    self.assertEqual(Runlevel.NOTICE, event.runlevel)
+    self.assertEqual("BOOTSTRAP", event.action)
+    
+    expected_attr = {
+      'PROGRESS': '90',
+      'TAG': 'circuit_create',
+      'SUMMARY': 'Establishing a Tor circuit',
+    }
+    
+    self.assertEqual(expected_attr, event.keyword_args)
+  
+  def test_status_event_bootstrap_done(self):
+    event = _get_event(STATUS_CLIENT_BOOTSTRAP_DONE)
+    
+    self.assertEqual(StatusType.CLIENT, event.status_type)
+    self.assertEqual(Runlevel.NOTICE, event.runlevel)
+    self.assertEqual("BOOTSTRAP", event.action)
+    
+    expected_attr = {
+      'PROGRESS': '100',
+      'TAG': 'done',
+      'SUMMARY': 'Done',
+    }
+    
+    self.assertEqual(expected_attr, event.keyword_args)
+  
+  def test_status_event_bootstrap_check_reachability(self):
+    event = _get_event(STATUS_SERVER_CHECK_REACHABILITY)
+    
+    self.assertEqual(StatusType.SERVER, event.status_type)
+    self.assertEqual(Runlevel.NOTICE, event.runlevel)
+    self.assertEqual("CHECKING_REACHABILITY", event.action)
+    
+    expected_attr = {
+      'ORADDRESS': '71.35.143.230:9050',
+    }
+    
+    self.assertEqual(expected_attr, event.keyword_args)
+  
+  def test_status_event_dns_timeout(self):
+    event = _get_event(STATUS_SERVER_DNS_TIMEOUT)
+    
+    self.assertEqual(StatusType.SERVER, event.status_type)
+    self.assertEqual(Runlevel.NOTICE, event.runlevel)
+    self.assertEqual("NAMESERVER_STATUS", event.action)
+    
+    expected_attr = {
+      'NS': '205.171.3.25',
+      'STATUS': 'DOWN',
+      'ERR': 'request timed out.',
+    }
+    
+    self.assertEqual(expected_attr, event.keyword_args)
+  
+  def test_status_event_dns_down(self):
+    event = _get_event(STATUS_SERVER_DNS_DOWN)
+    
+    self.assertEqual(StatusType.SERVER, event.status_type)
+    self.assertEqual(Runlevel.WARN, event.runlevel)
+    self.assertEqual("NAMESERVER_ALL_DOWN", event.action)
+  
+  def test_status_event_dns_up(self):
+    event = _get_event(STATUS_SERVER_DNS_UP)
+    
+    self.assertEqual(StatusType.SERVER, event.status_type)
+    self.assertEqual(Runlevel.NOTICE, event.runlevel)
+    self.assertEqual("NAMESERVER_STATUS", event.action)
+    
+    expected_attr = {
+      'NS': '205.171.3.25',
+      'STATUS': 'UP',
+    }
+    
+    self.assertEqual(expected_attr, event.keyword_args)
+  
   def test_stream_event(self):
     event = _get_event(STREAM_NEW)
     





More information about the tor-commits mailing list