Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Made exceptions work.

Raising an XMPPError exception from an event handler now works, even if
from a threaded handler.

Added stream tests to verify.

We should start using XMPPError, it really makes things simple!
  • Loading branch information...
commit 5bdcd9ef9d74d7921f5579086e6c6d94c0ac7deb 1 parent 2eff35c
@legastero legastero authored
View
3  sleekxmpp/exceptions.py
@@ -38,6 +38,9 @@ def __init__(self, condition='undefined-condition', text=None, etype=None,
element. Same as the additional arguments to
the ET.Element constructor.
"""
+ if extension_args is None:
+ extension_args = {}
+
self.condition = condition
self.text = text
self.etype = etype
View
31 sleekxmpp/xmlstream/xmlstream.py
@@ -786,6 +786,23 @@ def __spawn_event(self, xml):
if unhandled:
stanza.unhandled()
+ def _threaded_event_wrapper(self, func, args):
+ """
+ Capture exceptions for event handlers that run
+ in individual threads.
+
+ Arguments:
+ func -- The event handler to execute.
+ args -- Arguments to the event handler.
+ """
+ try:
+ func(*args)
+ except Exception as e:
+ error_msg = 'Error processing event handler: %s'
+ logging.exception(error_msg % str(func))
+ if hasattr(args[0], 'exception'):
+ args[0].exception(e)
+
def _event_runner(self):
"""
Process the event queue and execute handlers.
@@ -825,14 +842,18 @@ def _event_runner(self):
func, threaded, disposable = handler
try:
if threaded:
- x = threading.Thread(name="Event_%s" % str(func),
- target=func,
- args=args)
+ x = threading.Thread(
+ name="Event_%s" % str(func),
+ target=self._threaded_event_wrapper,
+ args=(func, args))
x.start()
else:
func(*args)
- except:
- logging.exception('Error processing event handler: %s')
+ except Exception as e:
+ error_msg = 'Error processing event handler: %s'
+ logging.exception(error_msg % str(func))
+ if hasattr(args[0], 'exception'):
+ args[0].exception(e)
elif etype == 'quit':
logging.debug("Quitting event runner thread")
return False
View
110 tests/test_stream_exceptions.py
@@ -0,0 +1,110 @@
+import sys
+import sleekxmpp
+from sleekxmpp.exceptions import XMPPError
+from sleekxmpp.test import *
+
+
+class TestStreamExceptions(SleekTest):
+ """
+ Test handling roster updates.
+ """
+
+ def tearDown(self):
+ self.stream_close()
+
+ def testXMPPErrorException(self):
+ """Test raising an XMPPError exception."""
+
+ def message(msg):
+ raise XMPPError(condition='feature-not-implemented',
+ text="We don't do things that way here.",
+ etype='cancel',
+ extension='foo',
+ extension_ns='foo:error',
+ extension_args={'test': 'true'})
+
+ self.stream_start()
+ self.xmpp.add_event_handler('message', message)
+
+ self.stream_recv("""
+ <message>
+ <body>This is going to cause an error.</body>
+ </message>
+ """)
+
+ self.stream_send_message("""
+ <message type="error">
+ <error type="cancel">
+ <feature-not-implemented
+ xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" />
+ <text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">
+ We don&apos;t do things that way here.
+ </text>
+ <foo xmlns="foo:error" test="true" />
+ </error>
+ </message>
+ """, use_values=False)
+
+ def testThreadedXMPPErrorException(self):
+ """Test raising an XMPPError exception in a threaded handler."""
+
+ def message(msg):
+ raise XMPPError(condition='feature-not-implemented',
+ text="We don't do things that way here.",
+ etype='cancel')
+
+ self.stream_start()
+ self.xmpp.add_event_handler('message', message,
+ threaded=True)
+
+ self.stream_recv("""
+ <message>
+ <body>This is going to cause an error.</body>
+ </message>
+ """)
+
+ self.stream_send_message("""
+ <message type="error">
+ <error type="cancel">
+ <feature-not-implemented
+ xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" />
+ <text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">
+ We don&apos;t do things that way here.
+ </text>
+ </error>
+ </message>
+ """)
+
+ def testUnknownException(self):
+ """Test raising an generic exception in a threaded handler."""
+
+ def message(msg):
+ raise ValueError("Did something wrong")
+
+ self.stream_start()
+ self.xmpp.add_event_handler('message', message)
+
+ self.stream_recv("""
+ <message>
+ <body>This is going to cause an error.</body>
+ </message>
+ """)
+
+ if sys.version_info < (3, 0):
+ self.stream_send_message("""
+ <message type="error">
+ <error type="cancel">
+ <undefined-condition
+ xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" />
+ <text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">
+ SleekXMPP got into trouble.
+ </text>
+ </error>
+ </message>
+ """)
+ else:
+ # Unfortunately, tracebacks do not make for very portable tests.
+ pass
+
+
+suite = unittest.TestLoader().loadTestsFromTestCase(TestStreamExceptions)
View
11 tests/test_stream_presence.py
@@ -42,6 +42,7 @@ def unavailable(presence):
def testGotOffline(self):
"""Test that got_offline is triggered properly."""
events = []
+
def got_offline(presence):
events.append('got_offline')
@@ -124,7 +125,7 @@ def changed_subscription(p):
self.stream_start(jid='tester@localhost')
- self.xmpp.add_event_handler('changed_subscription',
+ self.xmpp.add_event_handler('changed_subscription',
changed_subscription)
self.xmpp.add_event_handler('presence_subscribe',
presence_subscribe)
@@ -147,7 +148,7 @@ def changed_subscription(p):
""")
expected = set(('presence_subscribe', 'changed_subscription'))
- self.assertEqual(events, expected,
+ self.assertEqual(events, expected,
"Incorrect events triggered: %s" % events)
def testNoAutoAuthorize(self):
@@ -160,10 +161,10 @@ def presence_subscribe(p):
def changed_subscription(p):
events.add('changed_subscription')
-
+
self.stream_start(jid='tester@localhost')
- self.xmpp.add_event_handler('changed_subscription',
+ self.xmpp.add_event_handler('changed_subscription',
changed_subscription)
self.xmpp.add_event_handler('presence_subscribe',
presence_subscribe)
@@ -180,7 +181,7 @@ def changed_subscription(p):
""")
expected = set(('presence_subscribe', 'changed_subscription'))
- self.assertEqual(events, expected,
+ self.assertEqual(events, expected,
"Incorrect events triggered: %s" % events)
Please sign in to comment.
Something went wrong with that request. Please try again.