This commit is contained in:
Mai Gillmann
2019-12-17 14:09:10 +01:00
parent 66e908fc8a
commit 4791d00a43
2122 changed files with 423791 additions and 0 deletions
@@ -0,0 +1 @@
"Words tests"
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,440 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Tests for L{twisted.words.protocols.jabber.component}
"""
from hashlib import sha1
from zope.interface.verify import verifyObject
from twisted.python import failure
from twisted.python.compat import unicode
from twisted.trial import unittest
from twisted.words.protocols.jabber import component, ijabber, xmlstream
from twisted.words.protocols.jabber.jid import JID
from twisted.words.xish import domish
from twisted.words.xish.utility import XmlPipe
class DummyTransport:
def __init__(self, list):
self.list = list
def write(self, bytes):
self.list.append(bytes)
class ComponentInitiatingInitializerTests(unittest.TestCase):
def setUp(self):
self.output = []
self.authenticator = xmlstream.Authenticator()
self.authenticator.password = u'secret'
self.xmlstream = xmlstream.XmlStream(self.authenticator)
self.xmlstream.namespace = 'test:component'
self.xmlstream.send = self.output.append
self.xmlstream.connectionMade()
self.xmlstream.dataReceived(
"<stream:stream xmlns='test:component' "
"xmlns:stream='http://etherx.jabber.org/streams' "
"from='example.com' id='12345' version='1.0'>")
self.xmlstream.sid = u'12345'
self.init = component.ComponentInitiatingInitializer(self.xmlstream)
def testHandshake(self):
"""
Test basic operations of component handshake.
"""
d = self.init.initialize()
# the initializer should have sent the handshake request
handshake = self.output[-1]
self.assertEqual('handshake', handshake.name)
self.assertEqual('test:component', handshake.uri)
self.assertEqual(sha1(b'12345' + b'secret').hexdigest(),
unicode(handshake))
# successful authentication
handshake.children = []
self.xmlstream.dataReceived(handshake.toXml())
return d
class ComponentAuthTests(unittest.TestCase):
def authPassed(self, stream):
self.authComplete = True
def testAuth(self):
self.authComplete = False
outlist = []
ca = component.ConnectComponentAuthenticator(u"cjid", u"secret")
xs = xmlstream.XmlStream(ca)
xs.transport = DummyTransport(outlist)
xs.addObserver(xmlstream.STREAM_AUTHD_EVENT,
self.authPassed)
# Go...
xs.connectionMade()
xs.dataReceived(b"<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='cjid' id='12345'>")
# Calculate what we expect the handshake value to be
hv = sha1(b"12345" + b"secret").hexdigest().encode('ascii')
self.assertEqual(outlist[1], b"<handshake>" + hv + b"</handshake>")
xs.dataReceived("<handshake/>")
self.assertEqual(self.authComplete, True)
class ServiceTests(unittest.TestCase):
"""
Tests for L{component.Service}.
"""
def test_interface(self):
"""
L{component.Service} implements L{ijabber.IService}.
"""
service = component.Service()
verifyObject(ijabber.IService, service)
class JabberServiceHarness(component.Service):
def __init__(self):
self.componentConnectedFlag = False
self.componentDisconnectedFlag = False
self.transportConnectedFlag = False
def componentConnected(self, xmlstream):
self.componentConnectedFlag = True
def componentDisconnected(self):
self.componentDisconnectedFlag = True
def transportConnected(self, xmlstream):
self.transportConnectedFlag = True
class JabberServiceManagerTests(unittest.TestCase):
def testSM(self):
# Setup service manager and test harnes
sm = component.ServiceManager("foo", "password")
svc = JabberServiceHarness()
svc.setServiceParent(sm)
# Create a write list
wlist = []
# Setup a XmlStream
xs = sm.getFactory().buildProtocol(None)
xs.transport = self
xs.transport.write = wlist.append
# Indicate that it's connected
xs.connectionMade()
# Ensure the test service harness got notified
self.assertEqual(True, svc.transportConnectedFlag)
# Jump ahead and pretend like the stream got auth'd
xs.dispatch(xs, xmlstream.STREAM_AUTHD_EVENT)
# Ensure the test service harness got notified
self.assertEqual(True, svc.componentConnectedFlag)
# Pretend to drop the connection
xs.connectionLost(None)
# Ensure the test service harness got notified
self.assertEqual(True, svc.componentDisconnectedFlag)
class RouterTests(unittest.TestCase):
"""
Tests for L{component.Router}.
"""
def test_addRoute(self):
"""
Test route registration and routing on incoming stanzas.
"""
router = component.Router()
routed = []
router.route = lambda element: routed.append(element)
pipe = XmlPipe()
router.addRoute('example.org', pipe.sink)
self.assertEqual(1, len(router.routes))
self.assertEqual(pipe.sink, router.routes['example.org'])
element = domish.Element(('testns', 'test'))
pipe.source.send(element)
self.assertEqual([element], routed)
def test_route(self):
"""
Test routing of a message.
"""
component1 = XmlPipe()
component2 = XmlPipe()
router = component.Router()
router.addRoute('component1.example.org', component1.sink)
router.addRoute('component2.example.org', component2.sink)
outgoing = []
component2.source.addObserver('/*',
lambda element: outgoing.append(element))
stanza = domish.Element((None, 'presence'))
stanza['from'] = 'component1.example.org'
stanza['to'] = 'component2.example.org'
component1.source.send(stanza)
self.assertEqual([stanza], outgoing)
def test_routeDefault(self):
"""
Test routing of a message using the default route.
The default route is the one with L{None} as its key in the
routing table. It is taken when there is no more specific route
in the routing table that matches the stanza's destination.
"""
component1 = XmlPipe()
s2s = XmlPipe()
router = component.Router()
router.addRoute('component1.example.org', component1.sink)
router.addRoute(None, s2s.sink)
outgoing = []
s2s.source.addObserver('/*', lambda element: outgoing.append(element))
stanza = domish.Element((None, 'presence'))
stanza['from'] = 'component1.example.org'
stanza['to'] = 'example.com'
component1.source.send(stanza)
self.assertEqual([stanza], outgoing)
class ListenComponentAuthenticatorTests(unittest.TestCase):
"""
Tests for L{component.ListenComponentAuthenticator}.
"""
def setUp(self):
self.output = []
authenticator = component.ListenComponentAuthenticator('secret')
self.xmlstream = xmlstream.XmlStream(authenticator)
self.xmlstream.send = self.output.append
def loseConnection(self):
"""
Stub loseConnection because we are a transport.
"""
self.xmlstream.connectionLost("no reason")
def test_streamStarted(self):
"""
The received stream header should set several attributes.
"""
observers = []
def addOnetimeObserver(event, observerfn):
observers.append((event, observerfn))
xs = self.xmlstream
xs.addOnetimeObserver = addOnetimeObserver
xs.makeConnection(self)
self.assertIdentical(None, xs.sid)
self.assertFalse(xs._headerSent)
xs.dataReceived("<stream:stream xmlns='jabber:component:accept' "
"xmlns:stream='http://etherx.jabber.org/streams' "
"to='component.example.org'>")
self.assertEqual((0, 0), xs.version)
self.assertNotIdentical(None, xs.sid)
self.assertTrue(xs._headerSent)
self.assertEqual(('/*', xs.authenticator.onElement), observers[-1])
def test_streamStartedWrongNamespace(self):
"""
The received stream header should have a correct namespace.
"""
streamErrors = []
xs = self.xmlstream
xs.sendStreamError = streamErrors.append
xs.makeConnection(self)
xs.dataReceived("<stream:stream xmlns='jabber:client' "
"xmlns:stream='http://etherx.jabber.org/streams' "
"to='component.example.org'>")
self.assertEqual(1, len(streamErrors))
self.assertEqual('invalid-namespace', streamErrors[-1].condition)
def test_streamStartedNoTo(self):
"""
The received stream header should have a 'to' attribute.
"""
streamErrors = []
xs = self.xmlstream
xs.sendStreamError = streamErrors.append
xs.makeConnection(self)
xs.dataReceived("<stream:stream xmlns='jabber:component:accept' "
"xmlns:stream='http://etherx.jabber.org/streams'>")
self.assertEqual(1, len(streamErrors))
self.assertEqual('improper-addressing', streamErrors[-1].condition)
def test_onElement(self):
"""
We expect a handshake element with a hash.
"""
handshakes = []
xs = self.xmlstream
xs.authenticator.onHandshake = handshakes.append
handshake = domish.Element(('jabber:component:accept', 'handshake'))
handshake.addContent(u'1234')
xs.authenticator.onElement(handshake)
self.assertEqual('1234', handshakes[-1])
def test_onElementNotHandshake(self):
"""
Reject elements that are not handshakes
"""
handshakes = []
streamErrors = []
xs = self.xmlstream
xs.authenticator.onHandshake = handshakes.append
xs.sendStreamError = streamErrors.append
element = domish.Element(('jabber:component:accept', 'message'))
xs.authenticator.onElement(element)
self.assertFalse(handshakes)
self.assertEqual('not-authorized', streamErrors[-1].condition)
def test_onHandshake(self):
"""
Receiving a handshake matching the secret authenticates the stream.
"""
authd = []
def authenticated(xs):
authd.append(xs)
xs = self.xmlstream
xs.addOnetimeObserver(xmlstream.STREAM_AUTHD_EVENT, authenticated)
xs.sid = u'1234'
theHash = '32532c0f7dbf1253c095b18b18e36d38d94c1256'
xs.authenticator.onHandshake(theHash)
self.assertEqual('<handshake/>', self.output[-1])
self.assertEqual(1, len(authd))
def test_onHandshakeWrongHash(self):
"""
Receiving a bad handshake should yield a stream error.
"""
streamErrors = []
authd = []
def authenticated(xs):
authd.append(xs)
xs = self.xmlstream
xs.addOnetimeObserver(xmlstream.STREAM_AUTHD_EVENT, authenticated)
xs.sendStreamError = streamErrors.append
xs.sid = u'1234'
theHash = '1234'
xs.authenticator.onHandshake(theHash)
self.assertEqual('not-authorized', streamErrors[-1].condition)
self.assertEqual(0, len(authd))
class XMPPComponentServerFactoryTests(unittest.TestCase):
"""
Tests for L{component.XMPPComponentServerFactory}.
"""
def setUp(self):
self.router = component.Router()
self.factory = component.XMPPComponentServerFactory(self.router,
'secret')
self.xmlstream = self.factory.buildProtocol(None)
self.xmlstream.thisEntity = JID('component.example.org')
def test_makeConnection(self):
"""
A new connection increases the stream serial count. No logs by default.
"""
self.xmlstream.dispatch(self.xmlstream,
xmlstream.STREAM_CONNECTED_EVENT)
self.assertEqual(0, self.xmlstream.serial)
self.assertEqual(1, self.factory.serial)
self.assertIdentical(None, self.xmlstream.rawDataInFn)
self.assertIdentical(None, self.xmlstream.rawDataOutFn)
def test_makeConnectionLogTraffic(self):
"""
Setting logTraffic should set up raw data loggers.
"""
self.factory.logTraffic = True
self.xmlstream.dispatch(self.xmlstream,
xmlstream.STREAM_CONNECTED_EVENT)
self.assertNotIdentical(None, self.xmlstream.rawDataInFn)
self.assertNotIdentical(None, self.xmlstream.rawDataOutFn)
def test_onError(self):
"""
An observer for stream errors should trigger onError to log it.
"""
self.xmlstream.dispatch(self.xmlstream,
xmlstream.STREAM_CONNECTED_EVENT)
class TestError(Exception):
pass
reason = failure.Failure(TestError())
self.xmlstream.dispatch(reason, xmlstream.STREAM_ERROR_EVENT)
self.assertEqual(1, len(self.flushLoggedErrors(TestError)))
def test_connectionInitialized(self):
"""
Make sure a new stream is added to the routing table.
"""
self.xmlstream.dispatch(self.xmlstream, xmlstream.STREAM_AUTHD_EVENT)
self.assertIn('component.example.org', self.router.routes)
self.assertIdentical(self.xmlstream,
self.router.routes['component.example.org'])
def test_connectionLost(self):
"""
Make sure a stream is removed from the routing table on disconnect.
"""
self.xmlstream.dispatch(self.xmlstream, xmlstream.STREAM_AUTHD_EVENT)
self.xmlstream.dispatch(None, xmlstream.STREAM_END_EVENT)
self.assertNotIn('component.example.org', self.router.routes)
@@ -0,0 +1,36 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Tests for L{twisted.words.protocols.jabber.jstrports}.
"""
from __future__ import absolute_import, division
from twisted.trial import unittest
from twisted.words.protocols.jabber import jstrports
from twisted.application.internet import TCPClient
class JabberStrPortsPlaceHolderTests(unittest.TestCase):
"""
Tests for L{jstrports}
"""
def test_parse(self):
"""
L{jstrports.parse} accepts an endpoint description string and returns a
tuple and dict of parsed endpoint arguments.
"""
expected = ('TCP', ('DOMAIN', 65535, 'Factory'), {})
got = jstrports.parse("tcp:DOMAIN:65535", "Factory")
self.assertEqual(expected, got)
def test_client(self):
"""
L{jstrports.client} returns a L{TCPClient} service.
"""
got = jstrports.client("tcp:DOMAIN:65535", "Factory")
self.assertIsInstance(got, TCPClient)
@@ -0,0 +1,115 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
from twisted.trial import unittest
from twisted.words.protocols.jabber.xmpp_stringprep import (
nodeprep, resourceprep, nameprep)
class DeprecationTests(unittest.TestCase):
"""
Deprecations in L{twisted.words.protocols.jabber.xmpp_stringprep}.
"""
def test_crippled(self):
"""
L{xmpp_stringprep.crippled} is deprecated and always returns C{False}.
"""
from twisted.words.protocols.jabber.xmpp_stringprep import crippled
warnings = self.flushWarnings(
offendingFunctions=[self.test_crippled])
self.assertEqual(DeprecationWarning, warnings[0]['category'])
self.assertEqual(
"twisted.words.protocols.jabber.xmpp_stringprep.crippled was "
"deprecated in Twisted 13.1.0: crippled is always False",
warnings[0]['message'])
self.assertEqual(1, len(warnings))
self.assertEqual(crippled, False)
class XMPPStringPrepTests(unittest.TestCase):
"""
The nodeprep stringprep profile is similar to the resourceprep profile,
but does an extra mapping of characters (table B.2) and disallows
more characters (table C.1.1 and eight extra punctuation characters).
Due to this similarity, the resourceprep tests are more extensive, and
the nodeprep tests only address the mappings additional restrictions.
The nameprep profile is nearly identical to the nameprep implementation in
L{encodings.idna}, but that implementation assumes the C{UseSTD4ASCIIRules}
flag to be false. This implementation assumes it to be true, and restricts
the allowed set of characters. The tests here only check for the
differences.
"""
def testResourcePrep(self):
self.assertEqual(resourceprep.prepare(u'resource'), u'resource')
self.assertNotEqual(resourceprep.prepare(u'Resource'), u'resource')
self.assertEqual(resourceprep.prepare(u' '), u' ')
self.assertEqual(resourceprep.prepare(u'Henry \u2163'), u'Henry IV')
self.assertEqual(resourceprep.prepare(u'foo\xad\u034f\u1806\u180b'
u'bar\u200b\u2060'
u'baz\ufe00\ufe08\ufe0f\ufeff'),
u'foobarbaz')
self.assertEqual(resourceprep.prepare(u'\u00a0'), u' ')
self.assertRaises(UnicodeError, resourceprep.prepare, u'\u1680')
self.assertEqual(resourceprep.prepare(u'\u2000'), u' ')
self.assertEqual(resourceprep.prepare(u'\u200b'), u'')
self.assertRaises(UnicodeError, resourceprep.prepare, u'\u0010\u007f')
self.assertRaises(UnicodeError, resourceprep.prepare, u'\u0085')
self.assertRaises(UnicodeError, resourceprep.prepare, u'\u180e')
self.assertEqual(resourceprep.prepare(u'\ufeff'), u'')
self.assertRaises(UnicodeError, resourceprep.prepare, u'\uf123')
self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000f1234')
self.assertRaises(UnicodeError, resourceprep.prepare, u'\U0010f234')
self.assertRaises(UnicodeError, resourceprep.prepare, u'\U0008fffe')
self.assertRaises(UnicodeError, resourceprep.prepare, u'\U0010ffff')
self.assertRaises(UnicodeError, resourceprep.prepare, u'\udf42')
self.assertRaises(UnicodeError, resourceprep.prepare, u'\ufffd')
self.assertRaises(UnicodeError, resourceprep.prepare, u'\u2ff5')
self.assertEqual(resourceprep.prepare(u'\u0341'), u'\u0301')
self.assertRaises(UnicodeError, resourceprep.prepare, u'\u200e')
self.assertRaises(UnicodeError, resourceprep.prepare, u'\u202a')
self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000e0001')
self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000e0042')
self.assertRaises(UnicodeError, resourceprep.prepare, u'foo\u05bebar')
self.assertRaises(UnicodeError, resourceprep.prepare, u'foo\ufd50bar')
#self.assertEqual(resourceprep.prepare(u'foo\ufb38bar'),
# u'foo\u064ebar')
self.assertRaises(UnicodeError, resourceprep.prepare, u'\u06271')
self.assertEqual(resourceprep.prepare(u'\u06271\u0628'),
u'\u06271\u0628')
self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000e0002')
def testNodePrep(self):
self.assertEqual(nodeprep.prepare(u'user'), u'user')
self.assertEqual(nodeprep.prepare(u'User'), u'user')
self.assertRaises(UnicodeError, nodeprep.prepare, u'us&er')
def test_nodeprepUnassignedInUnicode32(self):
"""
Make sure unassigned code points from Unicode 3.2 are rejected.
"""
self.assertRaises(UnicodeError, nodeprep.prepare, u'\u1d39')
def testNamePrep(self):
self.assertEqual(nameprep.prepare(u'example.com'), u'example.com')
self.assertEqual(nameprep.prepare(u'Example.com'), u'example.com')
self.assertRaises(UnicodeError, nameprep.prepare, u'ex@mple.com')
self.assertRaises(UnicodeError, nameprep.prepare, u'-example.com')
self.assertRaises(UnicodeError, nameprep.prepare, u'example-.com')
self.assertEqual(nameprep.prepare(u'stra\u00dfe.example.com'),
u'strasse.example.com')
def test_nameprepTrailingDot(self):
"""
A trailing dot in domain names is preserved.
"""
self.assertEqual(nameprep.prepare(u'example.com.'), u'example.com.')
@@ -0,0 +1,78 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
from twisted.cred import credentials, error
from twisted.words import tap
from twisted.trial import unittest
class WordsTapTests(unittest.TestCase):
"""
Ensures that the twisted.words.tap API works.
"""
PASSWD_TEXT = b"admin:admin\njoe:foo\n"
admin = credentials.UsernamePassword(b'admin', b'admin')
joeWrong = credentials.UsernamePassword(b'joe', b'bar')
def setUp(self):
"""
Create a file with two users.
"""
self.filename = self.mktemp()
self.file = open(self.filename, 'wb')
self.file.write(self.PASSWD_TEXT)
self.file.flush()
def tearDown(self):
"""
Close the dummy user database.
"""
self.file.close()
def test_hostname(self):
"""
Tests that the --hostname parameter gets passed to Options.
"""
opt = tap.Options()
opt.parseOptions(['--hostname', 'myhost'])
self.assertEqual(opt['hostname'], 'myhost')
def test_passwd(self):
"""
Tests the --passwd command for backwards-compatibility.
"""
opt = tap.Options()
opt.parseOptions(['--passwd', self.file.name])
self._loginTest(opt)
def test_auth(self):
"""
Tests that the --auth command generates a checker.
"""
opt = tap.Options()
opt.parseOptions(['--auth', 'file:'+self.file.name])
self._loginTest(opt)
def _loginTest(self, opt):
"""
This method executes both positive and negative authentication
tests against whatever credentials checker has been stored in
the Options class.
@param opt: An instance of L{tap.Options}.
"""
self.assertEqual(len(opt['credCheckers']), 1)
checker = opt['credCheckers'][0]
self.assertFailure(checker.requestAvatarId(self.joeWrong),
error.UnauthorizedLogin)
def _gotAvatar(username):
self.assertEqual(username, self.admin.username)
return checker.requestAvatarId(self.admin).addCallback(_gotAvatar)
@@ -0,0 +1,348 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Test cases for twisted.words.xish.utility
"""
from __future__ import absolute_import, division
from collections import OrderedDict
from twisted.trial import unittest
from twisted.words.xish import utility
from twisted.words.xish.domish import Element
from twisted.words.xish.utility import EventDispatcher
class CallbackTracker:
"""
Test helper for tracking callbacks.
Increases a counter on each call to L{call} and stores the object
passed in the call.
"""
def __init__(self):
self.called = 0
self.obj = None
def call(self, obj):
self.called = self.called + 1
self.obj = obj
class OrderedCallbackTracker:
"""
Test helper for tracking callbacks and their order.
"""
def __init__(self):
self.callList = []
def call1(self, object):
self.callList.append(self.call1)
def call2(self, object):
self.callList.append(self.call2)
def call3(self, object):
self.callList.append(self.call3)
class EventDispatcherTests(unittest.TestCase):
"""
Tests for L{EventDispatcher}.
"""
def testStuff(self):
d = EventDispatcher()
cb1 = CallbackTracker()
cb2 = CallbackTracker()
cb3 = CallbackTracker()
d.addObserver("/message/body", cb1.call)
d.addObserver("/message", cb1.call)
d.addObserver("/presence", cb2.call)
d.addObserver("//event/testevent", cb3.call)
msg = Element(("ns", "message"))
msg.addElement("body")
pres = Element(("ns", "presence"))
pres.addElement("presence")
d.dispatch(msg)
self.assertEqual(cb1.called, 2)
self.assertEqual(cb1.obj, msg)
self.assertEqual(cb2.called, 0)
d.dispatch(pres)
self.assertEqual(cb1.called, 2)
self.assertEqual(cb2.called, 1)
self.assertEqual(cb2.obj, pres)
self.assertEqual(cb3.called, 0)
d.dispatch(d, "//event/testevent")
self.assertEqual(cb3.called, 1)
self.assertEqual(cb3.obj, d)
d.removeObserver("/presence", cb2.call)
d.dispatch(pres)
self.assertEqual(cb2.called, 1)
def test_addObserverTwice(self):
"""
Test adding two observers for the same query.
When the event is dispatched both of the observers need to be called.
"""
d = EventDispatcher()
cb1 = CallbackTracker()
cb2 = CallbackTracker()
d.addObserver("//event/testevent", cb1.call)
d.addObserver("//event/testevent", cb2.call)
d.dispatch(d, "//event/testevent")
self.assertEqual(cb1.called, 1)
self.assertEqual(cb1.obj, d)
self.assertEqual(cb2.called, 1)
self.assertEqual(cb2.obj, d)
def test_addObserverInDispatch(self):
"""
Test for registration of an observer during dispatch.
"""
d = EventDispatcher()
msg = Element(("ns", "message"))
cb = CallbackTracker()
def onMessage(_):
d.addObserver("/message", cb.call)
d.addOnetimeObserver("/message", onMessage)
d.dispatch(msg)
self.assertEqual(cb.called, 0)
d.dispatch(msg)
self.assertEqual(cb.called, 1)
d.dispatch(msg)
self.assertEqual(cb.called, 2)
def test_addOnetimeObserverInDispatch(self):
"""
Test for registration of a onetime observer during dispatch.
"""
d = EventDispatcher()
msg = Element(("ns", "message"))
cb = CallbackTracker()
def onMessage(msg):
d.addOnetimeObserver("/message", cb.call)
d.addOnetimeObserver("/message", onMessage)
d.dispatch(msg)
self.assertEqual(cb.called, 0)
d.dispatch(msg)
self.assertEqual(cb.called, 1)
d.dispatch(msg)
self.assertEqual(cb.called, 1)
def testOnetimeDispatch(self):
d = EventDispatcher()
msg = Element(("ns", "message"))
cb = CallbackTracker()
d.addOnetimeObserver("/message", cb.call)
d.dispatch(msg)
self.assertEqual(cb.called, 1)
d.dispatch(msg)
self.assertEqual(cb.called, 1)
def testDispatcherResult(self):
d = EventDispatcher()
msg = Element(("ns", "message"))
pres = Element(("ns", "presence"))
cb = CallbackTracker()
d.addObserver("/presence", cb.call)
result = d.dispatch(msg)
self.assertEqual(False, result)
result = d.dispatch(pres)
self.assertEqual(True, result)
def testOrderedXPathDispatch(self):
d = EventDispatcher()
cb = OrderedCallbackTracker()
d.addObserver("/message/body", cb.call2)
d.addObserver("/message", cb.call3, -1)
d.addObserver("/message/body", cb.call1, 1)
msg = Element(("ns", "message"))
msg.addElement("body")
d.dispatch(msg)
self.assertEqual(cb.callList, [cb.call1, cb.call2, cb.call3],
"Calls out of order: %s" %
repr([c.__name__ for c in cb.callList]))
# Observers are put into CallbackLists that are then put into dictionaries
# keyed by the event trigger. Upon removal of the last observer for a
# particular event trigger, the (now empty) CallbackList and corresponding
# event trigger should be removed from those dictionaries to prevent
# slowdown and memory leakage.
def test_cleanUpRemoveEventObserver(self):
"""
Test observer clean-up after removeObserver for named events.
"""
d = EventDispatcher()
cb = CallbackTracker()
d.addObserver('//event/test', cb.call)
d.dispatch(None, '//event/test')
self.assertEqual(1, cb.called)
d.removeObserver('//event/test', cb.call)
self.assertEqual(0, len(d._eventObservers.pop(0)))
def test_cleanUpRemoveXPathObserver(self):
"""
Test observer clean-up after removeObserver for XPath events.
"""
d = EventDispatcher()
cb = CallbackTracker()
msg = Element((None, "message"))
d.addObserver('/message', cb.call)
d.dispatch(msg)
self.assertEqual(1, cb.called)
d.removeObserver('/message', cb.call)
self.assertEqual(0, len(d._xpathObservers.pop(0)))
def test_cleanUpOnetimeEventObserver(self):
"""
Test observer clean-up after onetime named events.
"""
d = EventDispatcher()
cb = CallbackTracker()
d.addOnetimeObserver('//event/test', cb.call)
d.dispatch(None, '//event/test')
self.assertEqual(1, cb.called)
self.assertEqual(0, len(d._eventObservers.pop(0)))
def test_cleanUpOnetimeXPathObserver(self):
"""
Test observer clean-up after onetime XPath events.
"""
d = EventDispatcher()
cb = CallbackTracker()
msg = Element((None, "message"))
d.addOnetimeObserver('/message', cb.call)
d.dispatch(msg)
self.assertEqual(1, cb.called)
self.assertEqual(0, len(d._xpathObservers.pop(0)))
def test_observerRaisingException(self):
"""
Test that exceptions in observers do not bubble up to dispatch.
The exceptions raised in observers should be logged and other
observers should be called as if nothing happened.
"""
class OrderedCallbackList(utility.CallbackList):
def __init__(self):
self.callbacks = OrderedDict()
class TestError(Exception):
pass
def raiseError(_):
raise TestError()
d = EventDispatcher()
cb = CallbackTracker()
originalCallbackList = utility.CallbackList
try:
utility.CallbackList = OrderedCallbackList
d.addObserver('//event/test', raiseError)
d.addObserver('//event/test', cb.call)
try:
d.dispatch(None, '//event/test')
except TestError:
self.fail("TestError raised. Should have been logged instead.")
self.assertEqual(1, len(self.flushLoggedErrors(TestError)))
self.assertEqual(1, cb.called)
finally:
utility.CallbackList = originalCallbackList
class XmlPipeTests(unittest.TestCase):
"""
Tests for L{twisted.words.xish.utility.XmlPipe}.
"""
def setUp(self):
self.pipe = utility.XmlPipe()
def test_sendFromSource(self):
"""
Send an element from the source and observe it from the sink.
"""
def cb(obj):
called.append(obj)
called = []
self.pipe.sink.addObserver('/test[@xmlns="testns"]', cb)
element = Element(('testns', 'test'))
self.pipe.source.send(element)
self.assertEqual([element], called)
def test_sendFromSink(self):
"""
Send an element from the sink and observe it from the source.
"""
def cb(obj):
called.append(obj)
called = []
self.pipe.source.addObserver('/test[@xmlns="testns"]', cb)
element = Element(('testns', 'test'))
self.pipe.sink.send(element)
self.assertEqual([element], called)
@@ -0,0 +1,84 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Tests for L{twisted.words.xmpproutertap}.
"""
from twisted.application import internet
from twisted.trial import unittest
from twisted.words import xmpproutertap as tap
from twisted.words.protocols.jabber import component
class XMPPRouterTapTests(unittest.TestCase):
def test_port(self):
"""
The port option is recognised as a parameter.
"""
opt = tap.Options()
opt.parseOptions(['--port', '7001'])
self.assertEqual(opt['port'], '7001')
def test_portDefault(self):
"""
The port option has '5347' as default value
"""
opt = tap.Options()
opt.parseOptions([])
self.assertEqual(opt['port'], 'tcp:5347:interface=127.0.0.1')
def test_secret(self):
"""
The secret option is recognised as a parameter.
"""
opt = tap.Options()
opt.parseOptions(['--secret', 'hushhush'])
self.assertEqual(opt['secret'], 'hushhush')
def test_secretDefault(self):
"""
The secret option has 'secret' as default value
"""
opt = tap.Options()
opt.parseOptions([])
self.assertEqual(opt['secret'], 'secret')
def test_verbose(self):
"""
The verbose option is recognised as a flag.
"""
opt = tap.Options()
opt.parseOptions(['--verbose'])
self.assertTrue(opt['verbose'])
def test_makeService(self):
"""
The service gets set up with a router and factory.
"""
opt = tap.Options()
opt.parseOptions([])
s = tap.makeService(opt)
self.assertIsInstance(s, internet.StreamServerEndpointService)
self.assertEqual('127.0.0.1', s.endpoint._interface)
self.assertEqual(5347, s.endpoint._port)
factory = s.factory
self.assertIsInstance(factory, component.XMPPComponentServerFactory)
self.assertIsInstance(factory.router, component.Router)
self.assertEqual('secret', factory.secret)
self.assertFalse(factory.logTraffic)
def test_makeServiceVerbose(self):
"""
The verbose flag enables traffic logging.
"""
opt = tap.Options()
opt.parseOptions(['--verbose'])
s = tap.makeService(opt)
self.assertTrue(s.factory.logTraffic)