mirror of
https://github.com/correl/SleekXMPP.git
synced 2024-11-24 03:00:15 +00:00
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!
This commit is contained in:
parent
2eff35cc7a
commit
5bdcd9ef9d
4 changed files with 145 additions and 10 deletions
|
@ -38,6 +38,9 @@ class XMPPError(Exception):
|
|||
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
|
||||
|
|
|
@ -786,6 +786,23 @@ class XMLStream(object):
|
|||
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 @@ class XMLStream(object):
|
|||
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
|
||||
|
|
110
tests/test_stream_exceptions.py
Normal file
110
tests/test_stream_exceptions.py
Normal file
|
@ -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'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'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)
|
|
@ -42,6 +42,7 @@ class TestStreamPresence(SleekTest):
|
|||
def testGotOffline(self):
|
||||
"""Test that got_offline is triggered properly."""
|
||||
events = []
|
||||
|
||||
def got_offline(presence):
|
||||
events.append('got_offline')
|
||||
|
||||
|
|
Loading…
Reference in a new issue