mirror of
https://github.com/correl/SleekXMPP.git
synced 2024-11-27 19:19:54 +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
|
element. Same as the additional arguments to
|
||||||
the ET.Element constructor.
|
the ET.Element constructor.
|
||||||
"""
|
"""
|
||||||
|
if extension_args is None:
|
||||||
|
extension_args = {}
|
||||||
|
|
||||||
self.condition = condition
|
self.condition = condition
|
||||||
self.text = text
|
self.text = text
|
||||||
self.etype = etype
|
self.etype = etype
|
||||||
|
|
|
@ -786,6 +786,23 @@ class XMLStream(object):
|
||||||
if unhandled:
|
if unhandled:
|
||||||
stanza.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):
|
def _event_runner(self):
|
||||||
"""
|
"""
|
||||||
Process the event queue and execute handlers.
|
Process the event queue and execute handlers.
|
||||||
|
@ -825,14 +842,18 @@ class XMLStream(object):
|
||||||
func, threaded, disposable = handler
|
func, threaded, disposable = handler
|
||||||
try:
|
try:
|
||||||
if threaded:
|
if threaded:
|
||||||
x = threading.Thread(name="Event_%s" % str(func),
|
x = threading.Thread(
|
||||||
target=func,
|
name="Event_%s" % str(func),
|
||||||
args=args)
|
target=self._threaded_event_wrapper,
|
||||||
|
args=(func, args))
|
||||||
x.start()
|
x.start()
|
||||||
else:
|
else:
|
||||||
func(*args)
|
func(*args)
|
||||||
except:
|
except Exception as e:
|
||||||
logging.exception('Error processing event handler: %s')
|
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':
|
elif etype == 'quit':
|
||||||
logging.debug("Quitting event runner thread")
|
logging.debug("Quitting event runner thread")
|
||||||
return False
|
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):
|
def testGotOffline(self):
|
||||||
"""Test that got_offline is triggered properly."""
|
"""Test that got_offline is triggered properly."""
|
||||||
events = []
|
events = []
|
||||||
|
|
||||||
def got_offline(presence):
|
def got_offline(presence):
|
||||||
events.append('got_offline')
|
events.append('got_offline')
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue