12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337 |
- # Copyright (c) Twisted Matrix Laboratories.
- # See LICENSE for details.
- """
- Tests for L{twisted.words.protocols.jabber.xmlstream}.
- """
- from __future__ import absolute_import, division
- from twisted.trial import unittest
- from zope.interface.verify import verifyObject
- from twisted.internet import defer, task
- from twisted.internet.error import ConnectionLost
- from twisted.internet.interfaces import IProtocolFactory
- from twisted.python import failure
- from twisted.python.compat import unicode
- from twisted.test import proto_helpers
- from twisted.words.test.test_xmlstream import GenericXmlStreamFactoryTestsMixin
- from twisted.words.xish import domish
- from twisted.words.protocols.jabber import error, ijabber, jid, xmlstream
- NS_XMPP_TLS = 'urn:ietf:params:xml:ns:xmpp-tls'
- class HashPasswordTests(unittest.TestCase):
- """
- Tests for L{xmlstream.hashPassword}.
- """
- def test_basic(self):
- """
- The sid and secret are concatenated to calculate sha1 hex digest.
- """
- hash = xmlstream.hashPassword(u"12345", u"secret")
- self.assertEqual('99567ee91b2c7cabf607f10cb9f4a3634fa820e0', hash)
- def test_sidNotUnicode(self):
- """
- The session identifier must be a unicode object.
- """
- self.assertRaises(TypeError, xmlstream.hashPassword, b"\xc2\xb92345",
- u"secret")
- def test_passwordNotUnicode(self):
- """
- The password must be a unicode object.
- """
- self.assertRaises(TypeError, xmlstream.hashPassword, u"12345",
- b"secr\xc3\xa9t")
- def test_unicodeSecret(self):
- """
- The concatenated sid and password must be encoded to UTF-8 before hashing.
- """
- hash = xmlstream.hashPassword(u"12345", u"secr\u00e9t")
- self.assertEqual('659bf88d8f8e179081f7f3b4a8e7d224652d2853', hash)
- class IQTests(unittest.TestCase):
- """
- Tests both IQ and the associated IIQResponseTracker callback.
- """
- def setUp(self):
- authenticator = xmlstream.ConnectAuthenticator('otherhost')
- authenticator.namespace = 'testns'
- self.xmlstream = xmlstream.XmlStream(authenticator)
- self.clock = task.Clock()
- self.xmlstream._callLater = self.clock.callLater
- self.xmlstream.makeConnection(proto_helpers.StringTransport())
- self.xmlstream.dataReceived(
- "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "
- "xmlns='testns' from='otherhost' version='1.0'>")
- self.iq = xmlstream.IQ(self.xmlstream, 'get')
- def testBasic(self):
- self.assertEqual(self.iq['type'], 'get')
- self.assertTrue(self.iq['id'])
- def testSend(self):
- self.xmlstream.transport.clear()
- self.iq.send()
- idBytes = self.iq['id'].encode('utf-8')
- self.assertIn(self.xmlstream.transport.value(), [
- b"<iq type='get' id='" + idBytes + b"'/>",
- b"<iq id='" + idBytes + b"' type='get'/>"
- ])
- def testResultResponse(self):
- def cb(result):
- self.assertEqual(result['type'], 'result')
- d = self.iq.send()
- d.addCallback(cb)
- xs = self.xmlstream
- xs.dataReceived("<iq type='result' id='%s'/>" % self.iq['id'])
- return d
- def testErrorResponse(self):
- d = self.iq.send()
- self.assertFailure(d, error.StanzaError)
- xs = self.xmlstream
- xs.dataReceived("<iq type='error' id='%s'/>" % self.iq['id'])
- return d
- def testNonTrackedResponse(self):
- """
- Test that untracked iq responses don't trigger any action.
- Untracked means that the id of the incoming response iq is not
- in the stream's C{iqDeferreds} dictionary.
- """
- xs = self.xmlstream
- xmlstream.upgradeWithIQResponseTracker(xs)
- # Make sure we aren't tracking any iq's.
- self.assertFalse(xs.iqDeferreds)
- # Set up a fallback handler that checks the stanza's handled attribute.
- # If that is set to True, the iq tracker claims to have handled the
- # response.
- def cb(iq):
- self.assertFalse(getattr(iq, 'handled', False))
- xs.addObserver("/iq", cb, -1)
- # Receive an untracked iq response
- xs.dataReceived("<iq type='result' id='test'/>")
- def testCleanup(self):
- """
- Test if the deferred associated with an iq request is removed
- from the list kept in the L{XmlStream} object after it has
- been fired.
- """
- d = self.iq.send()
- xs = self.xmlstream
- xs.dataReceived("<iq type='result' id='%s'/>" % self.iq['id'])
- self.assertNotIn(self.iq['id'], xs.iqDeferreds)
- return d
- def testDisconnectCleanup(self):
- """
- Test if deferreds for iq's that haven't yet received a response
- have their errback called on stream disconnect.
- """
- d = self.iq.send()
- xs = self.xmlstream
- xs.connectionLost("Closed by peer")
- self.assertFailure(d, ConnectionLost)
- return d
- def testNoModifyingDict(self):
- """
- Test to make sure the errbacks cannot cause the iteration of the
- iqDeferreds to blow up in our face.
- """
- def eb(failure):
- d = xmlstream.IQ(self.xmlstream).send()
- d.addErrback(eb)
- d = self.iq.send()
- d.addErrback(eb)
- self.xmlstream.connectionLost("Closed by peer")
- return d
- def testRequestTimingOut(self):
- """
- Test that an iq request with a defined timeout times out.
- """
- self.iq.timeout = 60
- d = self.iq.send()
- self.assertFailure(d, xmlstream.TimeoutError)
- self.clock.pump([1, 60])
- self.assertFalse(self.clock.calls)
- self.assertFalse(self.xmlstream.iqDeferreds)
- return d
- def testRequestNotTimingOut(self):
- """
- Test that an iq request with a defined timeout does not time out
- when a response was received before the timeout period elapsed.
- """
- self.iq.timeout = 60
- d = self.iq.send()
- self.clock.callLater(1, self.xmlstream.dataReceived,
- "<iq type='result' id='%s'/>" % self.iq['id'])
- self.clock.pump([1, 1])
- self.assertFalse(self.clock.calls)
- return d
- def testDisconnectTimeoutCancellation(self):
- """
- Test if timeouts for iq's that haven't yet received a response
- are cancelled on stream disconnect.
- """
- self.iq.timeout = 60
- d = self.iq.send()
- xs = self.xmlstream
- xs.connectionLost("Closed by peer")
- self.assertFailure(d, ConnectionLost)
- self.assertFalse(self.clock.calls)
- return d
- class XmlStreamTests(unittest.TestCase):
- def onStreamStart(self, obj):
- self.gotStreamStart = True
- def onStreamEnd(self, obj):
- self.gotStreamEnd = True
- def onStreamError(self, obj):
- self.gotStreamError = True
- def setUp(self):
- """
- Set up XmlStream and several observers.
- """
- self.gotStreamStart = False
- self.gotStreamEnd = False
- self.gotStreamError = False
- xs = xmlstream.XmlStream(xmlstream.Authenticator())
- xs.addObserver('//event/stream/start', self.onStreamStart)
- xs.addObserver('//event/stream/end', self.onStreamEnd)
- xs.addObserver('//event/stream/error', self.onStreamError)
- xs.makeConnection(proto_helpers.StringTransportWithDisconnection())
- xs.transport.protocol = xs
- xs.namespace = 'testns'
- xs.version = (1, 0)
- self.xmlstream = xs
- def test_sendHeaderBasic(self):
- """
- Basic test on the header sent by sendHeader.
- """
- xs = self.xmlstream
- xs.sendHeader()
- splitHeader = self.xmlstream.transport.value()[0:-1].split(b' ')
- self.assertIn(b"<stream:stream", splitHeader)
- self.assertIn(b"xmlns:stream='http://etherx.jabber.org/streams'",
- splitHeader)
- self.assertIn(b"xmlns='testns'", splitHeader)
- self.assertIn(b"version='1.0'", splitHeader)
- self.assertTrue(xs._headerSent)
- def test_sendHeaderAdditionalNamespaces(self):
- """
- Test for additional namespace declarations.
- """
- xs = self.xmlstream
- xs.prefixes['jabber:server:dialback'] = 'db'
- xs.sendHeader()
- splitHeader = self.xmlstream.transport.value()[0:-1].split(b' ')
- self.assertIn(b"<stream:stream", splitHeader)
- self.assertIn(b"xmlns:stream='http://etherx.jabber.org/streams'",
- splitHeader)
- self.assertIn(b"xmlns:db='jabber:server:dialback'", splitHeader)
- self.assertIn(b"xmlns='testns'", splitHeader)
- self.assertIn(b"version='1.0'", splitHeader)
- self.assertTrue(xs._headerSent)
- def test_sendHeaderInitiating(self):
- """
- Test addressing when initiating a stream.
- """
- xs = self.xmlstream
- xs.thisEntity = jid.JID('thisHost')
- xs.otherEntity = jid.JID('otherHost')
- xs.initiating = True
- xs.sendHeader()
- splitHeader = xs.transport.value()[0:-1].split(b' ')
- self.assertIn(b"to='otherhost'", splitHeader)
- self.assertIn(b"from='thishost'", splitHeader)
- def test_sendHeaderReceiving(self):
- """
- Test addressing when receiving a stream.
- """
- xs = self.xmlstream
- xs.thisEntity = jid.JID('thisHost')
- xs.otherEntity = jid.JID('otherHost')
- xs.initiating = False
- xs.sid = 'session01'
- xs.sendHeader()
- splitHeader = xs.transport.value()[0:-1].split(b' ')
- self.assertIn(b"to='otherhost'", splitHeader)
- self.assertIn(b"from='thishost'", splitHeader)
- self.assertIn(b"id='session01'", splitHeader)
- def test_receiveStreamError(self):
- """
- Test events when a stream error is received.
- """
- xs = self.xmlstream
- xs.dataReceived("<stream:stream xmlns='jabber:client' "
- "xmlns:stream='http://etherx.jabber.org/streams' "
- "from='example.com' id='12345' version='1.0'>")
- xs.dataReceived("<stream:error/>")
- self.assertTrue(self.gotStreamError)
- self.assertTrue(self.gotStreamEnd)
- def test_sendStreamErrorInitiating(self):
- """
- Test sendStreamError on an initiating xmlstream with a header sent.
- An error should be sent out and the connection lost.
- """
- xs = self.xmlstream
- xs.initiating = True
- xs.sendHeader()
- xs.transport.clear()
- xs.sendStreamError(error.StreamError('version-unsupported'))
- self.assertNotEqual(b'', xs.transport.value())
- self.assertTrue(self.gotStreamEnd)
- def test_sendStreamErrorInitiatingNoHeader(self):
- """
- Test sendStreamError on an initiating xmlstream without having sent a
- header.
- In this case, no header should be generated. Also, the error should
- not be sent out on the stream. Just closing the connection.
- """
- xs = self.xmlstream
- xs.initiating = True
- xs.transport.clear()
- xs.sendStreamError(error.StreamError('version-unsupported'))
- self.assertNot(xs._headerSent)
- self.assertEqual(b'', xs.transport.value())
- self.assertTrue(self.gotStreamEnd)
- def test_sendStreamErrorReceiving(self):
- """
- Test sendStreamError on a receiving xmlstream with a header sent.
- An error should be sent out and the connection lost.
- """
- xs = self.xmlstream
- xs.initiating = False
- xs.sendHeader()
- xs.transport.clear()
- xs.sendStreamError(error.StreamError('version-unsupported'))
- self.assertNotEqual(b'', xs.transport.value())
- self.assertTrue(self.gotStreamEnd)
- def test_sendStreamErrorReceivingNoHeader(self):
- """
- Test sendStreamError on a receiving xmlstream without having sent a
- header.
- In this case, a header should be generated. Then, the error should
- be sent out on the stream followed by closing the connection.
- """
- xs = self.xmlstream
- xs.initiating = False
- xs.transport.clear()
- xs.sendStreamError(error.StreamError('version-unsupported'))
- self.assertTrue(xs._headerSent)
- self.assertNotEqual(b'', xs.transport.value())
- self.assertTrue(self.gotStreamEnd)
- def test_reset(self):
- """
- Test resetting the XML stream to start a new layer.
- """
- xs = self.xmlstream
- xs.sendHeader()
- stream = xs.stream
- xs.reset()
- self.assertNotEqual(stream, xs.stream)
- self.assertNot(xs._headerSent)
- def test_send(self):
- """
- Test send with various types of objects.
- """
- xs = self.xmlstream
- xs.send('<presence/>')
- self.assertEqual(xs.transport.value(), b'<presence/>')
- xs.transport.clear()
- el = domish.Element(('testns', 'presence'))
- xs.send(el)
- self.assertEqual(xs.transport.value(), b'<presence/>')
- xs.transport.clear()
- el = domish.Element(('http://etherx.jabber.org/streams', 'features'))
- xs.send(el)
- self.assertEqual(xs.transport.value(), b'<stream:features/>')
- def test_authenticator(self):
- """
- Test that the associated authenticator is correctly called.
- """
- connectionMadeCalls = []
- streamStartedCalls = []
- associateWithStreamCalls = []
- class TestAuthenticator:
- def connectionMade(self):
- connectionMadeCalls.append(None)
- def streamStarted(self, rootElement):
- streamStartedCalls.append(rootElement)
- def associateWithStream(self, xs):
- associateWithStreamCalls.append(xs)
- a = TestAuthenticator()
- xs = xmlstream.XmlStream(a)
- self.assertEqual([xs], associateWithStreamCalls)
- xs.connectionMade()
- self.assertEqual([None], connectionMadeCalls)
- xs.dataReceived("<stream:stream xmlns='jabber:client' "
- "xmlns:stream='http://etherx.jabber.org/streams' "
- "from='example.com' id='12345'>")
- self.assertEqual(1, len(streamStartedCalls))
- xs.reset()
- self.assertEqual([None], connectionMadeCalls)
- class TestError(Exception):
- pass
- class AuthenticatorTests(unittest.TestCase):
- def setUp(self):
- self.authenticator = xmlstream.Authenticator()
- self.xmlstream = xmlstream.XmlStream(self.authenticator)
- def test_streamStart(self):
- """
- Test streamStart to fill the appropriate attributes from the
- stream header.
- """
- xs = self.xmlstream
- xs.makeConnection(proto_helpers.StringTransport())
- xs.dataReceived("<stream:stream xmlns='jabber:client' "
- "xmlns:stream='http://etherx.jabber.org/streams' "
- "from='example.org' to='example.com' id='12345' "
- "version='1.0'>")
- self.assertEqual((1, 0), xs.version)
- self.assertIdentical(None, xs.sid)
- self.assertEqual('invalid', xs.namespace)
- self.assertIdentical(None, xs.otherEntity)
- self.assertEqual(None, xs.thisEntity)
- def test_streamStartLegacy(self):
- """
- Test streamStart to fill the appropriate attributes from the
- stream header for a pre-XMPP-1.0 header.
- """
- xs = self.xmlstream
- xs.makeConnection(proto_helpers.StringTransport())
- xs.dataReceived("<stream:stream xmlns='jabber:client' "
- "xmlns:stream='http://etherx.jabber.org/streams' "
- "from='example.com' id='12345'>")
- self.assertEqual((0, 0), xs.version)
- def test_streamBadVersionOneDigit(self):
- """
- Test streamStart to fill the appropriate attributes from the
- stream header for a version with only one digit.
- """
- xs = self.xmlstream
- xs.makeConnection(proto_helpers.StringTransport())
- xs.dataReceived("<stream:stream xmlns='jabber:client' "
- "xmlns:stream='http://etherx.jabber.org/streams' "
- "from='example.com' id='12345' version='1'>")
- self.assertEqual((0, 0), xs.version)
- def test_streamBadVersionNoNumber(self):
- """
- Test streamStart to fill the appropriate attributes from the
- stream header for a malformed version.
- """
- xs = self.xmlstream
- xs.makeConnection(proto_helpers.StringTransport())
- xs.dataReceived("<stream:stream xmlns='jabber:client' "
- "xmlns:stream='http://etherx.jabber.org/streams' "
- "from='example.com' id='12345' version='blah'>")
- self.assertEqual((0, 0), xs.version)
- class ConnectAuthenticatorTests(unittest.TestCase):
- def setUp(self):
- self.gotAuthenticated = False
- self.initFailure = None
- self.authenticator = xmlstream.ConnectAuthenticator('otherHost')
- self.xmlstream = xmlstream.XmlStream(self.authenticator)
- self.xmlstream.addObserver('//event/stream/authd', self.onAuthenticated)
- self.xmlstream.addObserver('//event/xmpp/initfailed', self.onInitFailed)
- def onAuthenticated(self, obj):
- self.gotAuthenticated = True
- def onInitFailed(self, failure):
- self.initFailure = failure
- def testSucces(self):
- """
- Test successful completion of an initialization step.
- """
- class Initializer:
- def initialize(self):
- pass
- init = Initializer()
- self.xmlstream.initializers = [init]
- self.authenticator.initializeStream()
- self.assertEqual([], self.xmlstream.initializers)
- self.assertTrue(self.gotAuthenticated)
- def testFailure(self):
- """
- Test failure of an initialization step.
- """
- class Initializer:
- def initialize(self):
- raise TestError
- init = Initializer()
- self.xmlstream.initializers = [init]
- self.authenticator.initializeStream()
- self.assertEqual([init], self.xmlstream.initializers)
- self.assertFalse(self.gotAuthenticated)
- self.assertNotIdentical(None, self.initFailure)
- self.assertTrue(self.initFailure.check(TestError))
- def test_streamStart(self):
- """
- Test streamStart to fill the appropriate attributes from the
- stream header.
- """
- self.authenticator.namespace = 'testns'
- xs = self.xmlstream
- xs.makeConnection(proto_helpers.StringTransport())
- xs.dataReceived("<stream:stream xmlns='jabber:client' "
- "xmlns:stream='http://etherx.jabber.org/streams' "
- "from='example.com' to='example.org' id='12345' "
- "version='1.0'>")
- self.assertEqual((1, 0), xs.version)
- self.assertEqual('12345', xs.sid)
- self.assertEqual('testns', xs.namespace)
- self.assertEqual('example.com', xs.otherEntity.host)
- self.assertIdentical(None, xs.thisEntity)
- self.assertNot(self.gotAuthenticated)
- xs.dataReceived("<stream:features>"
- "<test xmlns='testns'/>"
- "</stream:features>")
- self.assertIn(('testns', 'test'), xs.features)
- self.assertTrue(self.gotAuthenticated)
- class ListenAuthenticatorTests(unittest.TestCase):
- """
- Tests for L{xmlstream.ListenAuthenticator}
- """
- def setUp(self):
- self.authenticator = xmlstream.ListenAuthenticator()
- self.xmlstream = xmlstream.XmlStream(self.authenticator)
- def test_streamStart(self):
- """
- Test streamStart to fill the appropriate attributes from the
- stream header.
- """
- xs = self.xmlstream
- xs.makeConnection(proto_helpers.StringTransport())
- self.assertIdentical(None, xs.sid)
- xs.dataReceived("<stream:stream xmlns='jabber:client' "
- "xmlns:stream='http://etherx.jabber.org/streams' "
- "from='example.org' to='example.com' id='12345' "
- "version='1.0'>")
- self.assertEqual((1, 0), xs.version)
- self.assertNotIdentical(None, xs.sid)
- self.assertNotEqual('12345', xs.sid)
- self.assertEqual('jabber:client', xs.namespace)
- self.assertIdentical(None, xs.otherEntity)
- self.assertEqual('example.com', xs.thisEntity.host)
- def test_streamStartUnicodeSessionID(self):
- """
- The generated session id must be a unicode object.
- """
- xs = self.xmlstream
- xs.makeConnection(proto_helpers.StringTransport())
- xs.dataReceived("<stream:stream xmlns='jabber:client' "
- "xmlns:stream='http://etherx.jabber.org/streams' "
- "from='example.org' to='example.com' id='12345' "
- "version='1.0'>")
- self.assertIsInstance(xs.sid, unicode)
- class TLSInitiatingInitializerTests(unittest.TestCase):
- def setUp(self):
- self.output = []
- self.done = []
- self.savedSSL = xmlstream.ssl
- self.authenticator = xmlstream.Authenticator()
- self.xmlstream = xmlstream.XmlStream(self.authenticator)
- self.xmlstream.send = self.output.append
- self.xmlstream.connectionMade()
- self.xmlstream.dataReceived("<stream:stream xmlns='jabber:client' "
- "xmlns:stream='http://etherx.jabber.org/streams' "
- "from='example.com' id='12345' version='1.0'>")
- self.init = xmlstream.TLSInitiatingInitializer(self.xmlstream)
- def tearDown(self):
- xmlstream.ssl = self.savedSSL
- def testWantedSupported(self):
- """
- Test start when TLS is wanted and the SSL library available.
- """
- self.xmlstream.transport = proto_helpers.StringTransport()
- self.xmlstream.transport.startTLS = lambda ctx: self.done.append('TLS')
- self.xmlstream.reset = lambda: self.done.append('reset')
- self.xmlstream.sendHeader = lambda: self.done.append('header')
- d = self.init.start()
- d.addCallback(self.assertEqual, xmlstream.Reset)
- starttls = self.output[0]
- self.assertEqual('starttls', starttls.name)
- self.assertEqual(NS_XMPP_TLS, starttls.uri)
- self.xmlstream.dataReceived("<proceed xmlns='%s'/>" % NS_XMPP_TLS)
- self.assertEqual(['TLS', 'reset', 'header'], self.done)
- return d
- if not xmlstream.ssl:
- testWantedSupported.skip = "SSL not available"
- def testWantedNotSupportedNotRequired(self):
- """
- Test start when TLS is wanted and the SSL library available.
- """
- xmlstream.ssl = None
- d = self.init.start()
- d.addCallback(self.assertEqual, None)
- self.assertEqual([], self.output)
- return d
- def testWantedNotSupportedRequired(self):
- """
- Test start when TLS is wanted and the SSL library available.
- """
- xmlstream.ssl = None
- self.init.required = True
- d = self.init.start()
- self.assertFailure(d, xmlstream.TLSNotSupported)
- self.assertEqual([], self.output)
- return d
- def testNotWantedRequired(self):
- """
- Test start when TLS is not wanted, but required by the server.
- """
- tls = domish.Element(('urn:ietf:params:xml:ns:xmpp-tls', 'starttls'))
- tls.addElement('required')
- self.xmlstream.features = {(tls.uri, tls.name): tls}
- self.init.wanted = False
- d = self.init.start()
- self.assertEqual([], self.output)
- self.assertFailure(d, xmlstream.TLSRequired)
- return d
- def testNotWantedNotRequired(self):
- """
- Test start when TLS is not wanted, but required by the server.
- """
- tls = domish.Element(('urn:ietf:params:xml:ns:xmpp-tls', 'starttls'))
- self.xmlstream.features = {(tls.uri, tls.name): tls}
- self.init.wanted = False
- d = self.init.start()
- d.addCallback(self.assertEqual, None)
- self.assertEqual([], self.output)
- return d
- def testFailed(self):
- """
- Test failed TLS negotiation.
- """
- # Pretend that ssl is supported, it isn't actually used when the
- # server starts out with a failure in response to our initial
- # C{starttls} stanza.
- xmlstream.ssl = 1
- d = self.init.start()
- self.assertFailure(d, xmlstream.TLSFailed)
- self.xmlstream.dataReceived("<failure xmlns='%s'/>" % NS_XMPP_TLS)
- return d
- class TestFeatureInitializer(xmlstream.BaseFeatureInitiatingInitializer):
- feature = ('testns', 'test')
- def start(self):
- return defer.succeed(None)
- class BaseFeatureInitiatingInitializerTests(unittest.TestCase):
- def setUp(self):
- self.xmlstream = xmlstream.XmlStream(xmlstream.Authenticator())
- self.init = TestFeatureInitializer(self.xmlstream)
- def testAdvertized(self):
- """
- Test that an advertized feature results in successful initialization.
- """
- self.xmlstream.features = {self.init.feature:
- domish.Element(self.init.feature)}
- return self.init.initialize()
- def testNotAdvertizedRequired(self):
- """
- Test that when the feature is not advertized, but required by the
- initializer, an exception is raised.
- """
- self.init.required = True
- self.assertRaises(xmlstream.FeatureNotAdvertized, self.init.initialize)
- def testNotAdvertizedNotRequired(self):
- """
- Test that when the feature is not advertized, and not required by the
- initializer, the initializer silently succeeds.
- """
- self.init.required = False
- self.assertIdentical(None, self.init.initialize())
- class ToResponseTests(unittest.TestCase):
- def test_toResponse(self):
- """
- Test that a response stanza is generated with addressing swapped.
- """
- stanza = domish.Element(('jabber:client', 'iq'))
- stanza['type'] = 'get'
- stanza['to'] = 'user1@example.com'
- stanza['from'] = 'user2@example.com/resource'
- stanza['id'] = 'stanza1'
- response = xmlstream.toResponse(stanza, 'result')
- self.assertNotIdentical(stanza, response)
- self.assertEqual(response['from'], 'user1@example.com')
- self.assertEqual(response['to'], 'user2@example.com/resource')
- self.assertEqual(response['type'], 'result')
- self.assertEqual(response['id'], 'stanza1')
- def test_toResponseNoFrom(self):
- """
- Test that a response is generated from a stanza without a from address.
- """
- stanza = domish.Element(('jabber:client', 'iq'))
- stanza['type'] = 'get'
- stanza['to'] = 'user1@example.com'
- response = xmlstream.toResponse(stanza)
- self.assertEqual(response['from'], 'user1@example.com')
- self.assertFalse(response.hasAttribute('to'))
- def test_toResponseNoTo(self):
- """
- Test that a response is generated from a stanza without a to address.
- """
- stanza = domish.Element(('jabber:client', 'iq'))
- stanza['type'] = 'get'
- stanza['from'] = 'user2@example.com/resource'
- response = xmlstream.toResponse(stanza)
- self.assertFalse(response.hasAttribute('from'))
- self.assertEqual(response['to'], 'user2@example.com/resource')
- def test_toResponseNoAddressing(self):
- """
- Test that a response is generated from a stanza without any addressing.
- """
- stanza = domish.Element(('jabber:client', 'message'))
- stanza['type'] = 'chat'
- response = xmlstream.toResponse(stanza)
- self.assertFalse(response.hasAttribute('to'))
- self.assertFalse(response.hasAttribute('from'))
- def test_noID(self):
- """
- Test that a proper response is generated without id attribute.
- """
- stanza = domish.Element(('jabber:client', 'message'))
- response = xmlstream.toResponse(stanza)
- self.assertFalse(response.hasAttribute('id'))
- def test_noType(self):
- """
- Test that a proper response is generated without type attribute.
- """
- stanza = domish.Element(('jabber:client', 'message'))
- response = xmlstream.toResponse(stanza)
- self.assertFalse(response.hasAttribute('type'))
- class DummyFactory(object):
- """
- Dummy XmlStream factory that only registers bootstrap observers.
- """
- def __init__(self):
- self.callbacks = {}
- def addBootstrap(self, event, callback):
- self.callbacks[event] = callback
- class DummyXMPPHandler(xmlstream.XMPPHandler):
- """
- Dummy XMPP subprotocol handler to count the methods are called on it.
- """
- def __init__(self):
- self.doneMade = 0
- self.doneInitialized = 0
- self.doneLost = 0
- def makeConnection(self, xs):
- self.connectionMade()
- def connectionMade(self):
- self.doneMade += 1
- def connectionInitialized(self):
- self.doneInitialized += 1
- def connectionLost(self, reason):
- self.doneLost += 1
- class FailureReasonXMPPHandler(xmlstream.XMPPHandler):
- """
- Dummy handler specifically for failure Reason tests.
- """
- def __init__(self):
- self.gotFailureReason = False
- def connectionLost(self, reason):
- if isinstance(reason, failure.Failure):
- self.gotFailureReason = True
- class XMPPHandlerTests(unittest.TestCase):
- """
- Tests for L{xmlstream.XMPPHandler}.
- """
- def test_interface(self):
- """
- L{xmlstream.XMPPHandler} implements L{ijabber.IXMPPHandler}.
- """
- verifyObject(ijabber.IXMPPHandler, xmlstream.XMPPHandler())
- def test_send(self):
- """
- Test that data is passed on for sending by the stream manager.
- """
- class DummyStreamManager(object):
- def __init__(self):
- self.outlist = []
- def send(self, data):
- self.outlist.append(data)
- handler = xmlstream.XMPPHandler()
- handler.parent = DummyStreamManager()
- handler.send('<presence/>')
- self.assertEqual(['<presence/>'], handler.parent.outlist)
- def test_makeConnection(self):
- """
- Test that makeConnection saves the XML stream and calls connectionMade.
- """
- class TestXMPPHandler(xmlstream.XMPPHandler):
- def connectionMade(self):
- self.doneMade = True
- handler = TestXMPPHandler()
- xs = xmlstream.XmlStream(xmlstream.Authenticator())
- handler.makeConnection(xs)
- self.assertTrue(handler.doneMade)
- self.assertIdentical(xs, handler.xmlstream)
- def test_connectionLost(self):
- """
- Test that connectionLost forgets the XML stream.
- """
- handler = xmlstream.XMPPHandler()
- xs = xmlstream.XmlStream(xmlstream.Authenticator())
- handler.makeConnection(xs)
- handler.connectionLost(Exception())
- self.assertIdentical(None, handler.xmlstream)
- class XMPPHandlerCollectionTests(unittest.TestCase):
- """
- Tests for L{xmlstream.XMPPHandlerCollection}.
- """
- def setUp(self):
- self.collection = xmlstream.XMPPHandlerCollection()
- def test_interface(self):
- """
- L{xmlstream.StreamManager} implements L{ijabber.IXMPPHandlerCollection}.
- """
- verifyObject(ijabber.IXMPPHandlerCollection, self.collection)
- def test_addHandler(self):
- """
- Test the addition of a protocol handler.
- """
- handler = DummyXMPPHandler()
- handler.setHandlerParent(self.collection)
- self.assertIn(handler, self.collection)
- self.assertIdentical(self.collection, handler.parent)
- def test_removeHandler(self):
- """
- Test removal of a protocol handler.
- """
- handler = DummyXMPPHandler()
- handler.setHandlerParent(self.collection)
- handler.disownHandlerParent(self.collection)
- self.assertNotIn(handler, self.collection)
- self.assertIdentical(None, handler.parent)
- class StreamManagerTests(unittest.TestCase):
- """
- Tests for L{xmlstream.StreamManager}.
- """
- def setUp(self):
- factory = DummyFactory()
- self.streamManager = xmlstream.StreamManager(factory)
- def test_basic(self):
- """
- Test correct initialization and setup of factory observers.
- """
- sm = self.streamManager
- self.assertIdentical(None, sm.xmlstream)
- self.assertEqual([], sm.handlers)
- self.assertEqual(sm._connected,
- sm.factory.callbacks['//event/stream/connected'])
- self.assertEqual(sm._authd,
- sm.factory.callbacks['//event/stream/authd'])
- self.assertEqual(sm._disconnected,
- sm.factory.callbacks['//event/stream/end'])
- self.assertEqual(sm.initializationFailed,
- sm.factory.callbacks['//event/xmpp/initfailed'])
- def test_connected(self):
- """
- Test that protocol handlers have their connectionMade method called
- when the XML stream is connected.
- """
- sm = self.streamManager
- handler = DummyXMPPHandler()
- handler.setHandlerParent(sm)
- xs = xmlstream.XmlStream(xmlstream.Authenticator())
- sm._connected(xs)
- self.assertEqual(1, handler.doneMade)
- self.assertEqual(0, handler.doneInitialized)
- self.assertEqual(0, handler.doneLost)
- def test_connectedLogTrafficFalse(self):
- """
- Test raw data functions unset when logTraffic is set to False.
- """
- sm = self.streamManager
- handler = DummyXMPPHandler()
- handler.setHandlerParent(sm)
- xs = xmlstream.XmlStream(xmlstream.Authenticator())
- sm._connected(xs)
- self.assertIdentical(None, xs.rawDataInFn)
- self.assertIdentical(None, xs.rawDataOutFn)
- def test_connectedLogTrafficTrue(self):
- """
- Test raw data functions set when logTraffic is set to True.
- """
- sm = self.streamManager
- sm.logTraffic = True
- handler = DummyXMPPHandler()
- handler.setHandlerParent(sm)
- xs = xmlstream.XmlStream(xmlstream.Authenticator())
- sm._connected(xs)
- self.assertNotIdentical(None, xs.rawDataInFn)
- self.assertNotIdentical(None, xs.rawDataOutFn)
- def test_authd(self):
- """
- Test that protocol handlers have their connectionInitialized method
- called when the XML stream is initialized.
- """
- sm = self.streamManager
- handler = DummyXMPPHandler()
- handler.setHandlerParent(sm)
- xs = xmlstream.XmlStream(xmlstream.Authenticator())
- sm._authd(xs)
- self.assertEqual(0, handler.doneMade)
- self.assertEqual(1, handler.doneInitialized)
- self.assertEqual(0, handler.doneLost)
- def test_disconnected(self):
- """
- Test that protocol handlers have their connectionLost method
- called when the XML stream is disconnected.
- """
- sm = self.streamManager
- handler = DummyXMPPHandler()
- handler.setHandlerParent(sm)
- xs = xmlstream.XmlStream(xmlstream.Authenticator())
- sm._disconnected(xs)
- self.assertEqual(0, handler.doneMade)
- self.assertEqual(0, handler.doneInitialized)
- self.assertEqual(1, handler.doneLost)
- def test_disconnectedReason(self):
- """
- A L{STREAM_END_EVENT} results in L{StreamManager} firing the handlers
- L{connectionLost} methods, passing a L{failure.Failure} reason.
- """
- sm = self.streamManager
- handler = FailureReasonXMPPHandler()
- handler.setHandlerParent(sm)
- sm._disconnected(failure.Failure(Exception("no reason")))
- self.assertEqual(True, handler.gotFailureReason)
- def test_addHandler(self):
- """
- Test the addition of a protocol handler while not connected.
- """
- sm = self.streamManager
- handler = DummyXMPPHandler()
- handler.setHandlerParent(sm)
- self.assertEqual(0, handler.doneMade)
- self.assertEqual(0, handler.doneInitialized)
- self.assertEqual(0, handler.doneLost)
- def test_addHandlerInitialized(self):
- """
- Test the addition of a protocol handler after the stream
- have been initialized.
- Make sure that the handler will have the connected stream
- passed via C{makeConnection} and have C{connectionInitialized}
- called.
- """
- sm = self.streamManager
- xs = xmlstream.XmlStream(xmlstream.Authenticator())
- sm._connected(xs)
- sm._authd(xs)
- handler = DummyXMPPHandler()
- handler.setHandlerParent(sm)
- self.assertEqual(1, handler.doneMade)
- self.assertEqual(1, handler.doneInitialized)
- self.assertEqual(0, handler.doneLost)
- def test_sendInitialized(self):
- """
- Test send when the stream has been initialized.
- The data should be sent directly over the XML stream.
- """
- factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator())
- sm = xmlstream.StreamManager(factory)
- xs = factory.buildProtocol(None)
- xs.transport = proto_helpers.StringTransport()
- xs.connectionMade()
- xs.dataReceived("<stream:stream xmlns='jabber:client' "
- "xmlns:stream='http://etherx.jabber.org/streams' "
- "from='example.com' id='12345'>")
- xs.dispatch(xs, "//event/stream/authd")
- sm.send("<presence/>")
- self.assertEqual(b"<presence/>", xs.transport.value())
- def test_sendNotConnected(self):
- """
- Test send when there is no established XML stream.
- The data should be cached until an XML stream has been established and
- initialized.
- """
- factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator())
- sm = xmlstream.StreamManager(factory)
- handler = DummyXMPPHandler()
- sm.addHandler(handler)
- xs = factory.buildProtocol(None)
- xs.transport = proto_helpers.StringTransport()
- sm.send("<presence/>")
- self.assertEqual(b"", xs.transport.value())
- self.assertEqual("<presence/>", sm._packetQueue[0])
- xs.connectionMade()
- self.assertEqual(b"", xs.transport.value())
- self.assertEqual("<presence/>", sm._packetQueue[0])
- xs.dataReceived("<stream:stream xmlns='jabber:client' "
- "xmlns:stream='http://etherx.jabber.org/streams' "
- "from='example.com' id='12345'>")
- xs.dispatch(xs, "//event/stream/authd")
- self.assertEqual(b"<presence/>", xs.transport.value())
- self.assertFalse(sm._packetQueue)
- def test_sendNotInitialized(self):
- """
- Test send when the stream is connected but not yet initialized.
- The data should be cached until the XML stream has been initialized.
- """
- factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator())
- sm = xmlstream.StreamManager(factory)
- xs = factory.buildProtocol(None)
- xs.transport = proto_helpers.StringTransport()
- xs.connectionMade()
- xs.dataReceived("<stream:stream xmlns='jabber:client' "
- "xmlns:stream='http://etherx.jabber.org/streams' "
- "from='example.com' id='12345'>")
- sm.send("<presence/>")
- self.assertEqual(b"", xs.transport.value())
- self.assertEqual("<presence/>", sm._packetQueue[0])
- def test_sendDisconnected(self):
- """
- Test send after XML stream disconnection.
- The data should be cached until a new XML stream has been established
- and initialized.
- """
- factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator())
- sm = xmlstream.StreamManager(factory)
- handler = DummyXMPPHandler()
- sm.addHandler(handler)
- xs = factory.buildProtocol(None)
- xs.connectionMade()
- xs.transport = proto_helpers.StringTransport()
- xs.connectionLost(None)
- sm.send("<presence/>")
- self.assertEqual(b"", xs.transport.value())
- self.assertEqual("<presence/>", sm._packetQueue[0])
- class XmlStreamServerFactoryTests(GenericXmlStreamFactoryTestsMixin):
- """
- Tests for L{xmlstream.XmlStreamServerFactory}.
- """
- def setUp(self):
- """
- Set up a server factory with an authenticator factory function.
- """
- class TestAuthenticator(object):
- def __init__(self):
- self.xmlstreams = []
- def associateWithStream(self, xs):
- self.xmlstreams.append(xs)
- def authenticatorFactory():
- return TestAuthenticator()
- self.factory = xmlstream.XmlStreamServerFactory(authenticatorFactory)
- def test_interface(self):
- """
- L{XmlStreamServerFactory} is a L{Factory}.
- """
- verifyObject(IProtocolFactory, self.factory)
- def test_buildProtocolAuthenticatorInstantiation(self):
- """
- The authenticator factory should be used to instantiate the
- authenticator and pass it to the protocol.
- The default protocol, L{XmlStream} stores the authenticator it is
- passed, and calls its C{associateWithStream} method. so we use that to
- check whether our authenticator factory is used and the protocol
- instance gets an authenticator.
- """
- xs = self.factory.buildProtocol(None)
- self.assertEqual([xs], xs.authenticator.xmlstreams)
- def test_buildProtocolXmlStream(self):
- """
- The protocol factory creates Jabber XML Stream protocols by default.
- """
- xs = self.factory.buildProtocol(None)
- self.assertIsInstance(xs, xmlstream.XmlStream)
- def test_buildProtocolTwice(self):
- """
- Subsequent calls to buildProtocol should result in different instances
- of the protocol, as well as their authenticators.
- """
- xs1 = self.factory.buildProtocol(None)
- xs2 = self.factory.buildProtocol(None)
- self.assertNotIdentical(xs1, xs2)
- self.assertNotIdentical(xs1.authenticator, xs2.authenticator)
|