1
# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
2
# See LICENSE for details.
5
Tests for L{twisted.words.protocols.jabber.xmlstream}.
8
from twisted.trial import unittest
10
from zope.interface.verify import verifyObject
12
from twisted.internet import defer, task
13
from twisted.internet.error import ConnectionLost
14
from twisted.internet.interfaces import IProtocolFactory
15
from twisted.test import proto_helpers
16
from twisted.words.test.test_xmlstream import GenericXmlStreamFactoryTestsMixin
17
from twisted.words.xish import domish
18
from twisted.words.protocols.jabber import error, ijabber, jid, xmlstream
22
NS_XMPP_TLS = 'urn:ietf:params:xml:ns:xmpp-tls'
26
class HashPasswordTest(unittest.TestCase):
28
Tests for L{xmlstream.hashPassword}.
33
The sid and secret are concatenated to calculate sha1 hex digest.
35
hash = xmlstream.hashPassword(u"12345", u"secret")
36
self.assertEqual('99567ee91b2c7cabf607f10cb9f4a3634fa820e0', hash)
39
def test_sidNotUnicode(self):
41
The session identifier must be a unicode object.
43
self.assertRaises(TypeError, xmlstream.hashPassword, "\xc2\xb92345",
47
def test_passwordNotUnicode(self):
49
The password must be a unicode object.
51
self.assertRaises(TypeError, xmlstream.hashPassword, u"12345",
55
def test_unicodeSecret(self):
57
The concatenated sid and password must be encoded to UTF-8 before hashing.
59
hash = xmlstream.hashPassword(u"12345", u"secr\u00e9t")
60
self.assertEqual('659bf88d8f8e179081f7f3b4a8e7d224652d2853', hash)
64
class IQTest(unittest.TestCase):
66
Tests both IQ and the associated IIQResponseTracker callback.
70
authenticator = xmlstream.ConnectAuthenticator('otherhost')
71
authenticator.namespace = 'testns'
72
self.xmlstream = xmlstream.XmlStream(authenticator)
73
self.clock = task.Clock()
74
self.xmlstream._callLater = self.clock.callLater
75
self.xmlstream.makeConnection(proto_helpers.StringTransport())
76
self.xmlstream.dataReceived(
77
"<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "
78
"xmlns='testns' from='otherhost' version='1.0'>")
79
self.iq = xmlstream.IQ(self.xmlstream, 'get')
83
self.assertEquals(self.iq['type'], 'get')
84
self.assertTrue(self.iq['id'])
88
self.xmlstream.transport.clear()
90
self.assertEquals("<iq type='get' id='%s'/>" % self.iq['id'],
91
self.xmlstream.transport.value())
94
def testResultResponse(self):
96
self.assertEquals(result['type'], 'result')
102
xs.dataReceived("<iq type='result' id='%s'/>" % self.iq['id'])
106
def testErrorResponse(self):
108
self.assertFailure(d, error.StanzaError)
111
xs.dataReceived("<iq type='error' id='%s'/>" % self.iq['id'])
115
def testNonTrackedResponse(self):
117
Test that untracked iq responses don't trigger any action.
119
Untracked means that the id of the incoming response iq is not
120
in the stream's C{iqDeferreds} dictionary.
123
xmlstream.upgradeWithIQResponseTracker(xs)
125
# Make sure we aren't tracking any iq's.
126
self.assertFalse(xs.iqDeferreds)
128
# Set up a fallback handler that checks the stanza's handled attribute.
129
# If that is set to True, the iq tracker claims to have handled the
132
self.assertFalse(getattr(iq, 'handled', False))
134
xs.addObserver("/iq", cb, -1)
136
# Receive an untracked iq response
137
xs.dataReceived("<iq type='result' id='test'/>")
140
def testCleanup(self):
142
Test if the deferred associated with an iq request is removed
143
from the list kept in the L{XmlStream} object after it has
149
xs.dataReceived("<iq type='result' id='%s'/>" % self.iq['id'])
150
self.assertNotIn(self.iq['id'], xs.iqDeferreds)
154
def testDisconnectCleanup(self):
156
Test if deferreds for iq's that haven't yet received a response
157
have their errback called on stream disconnect.
162
xs.connectionLost("Closed by peer")
163
self.assertFailure(d, ConnectionLost)
167
def testNoModifyingDict(self):
169
Test to make sure the errbacks cannot cause the iteration of the
170
iqDeferreds to blow up in our face.
174
d = xmlstream.IQ(self.xmlstream).send()
179
self.xmlstream.connectionLost("Closed by peer")
183
def testRequestTimingOut(self):
185
Test that an iq request with a defined timeout times out.
189
self.assertFailure(d, xmlstream.TimeoutError)
191
self.clock.pump([1, 60])
192
self.assertFalse(self.clock.calls)
193
self.assertFalse(self.xmlstream.iqDeferreds)
197
def testRequestNotTimingOut(self):
199
Test that an iq request with a defined timeout does not time out
200
when a response was received before the timeout period elapsed.
204
self.clock.callLater(1, self.xmlstream.dataReceived,
205
"<iq type='result' id='%s'/>" % self.iq['id'])
206
self.clock.pump([1, 1])
207
self.assertFalse(self.clock.calls)
211
def testDisconnectTimeoutCancellation(self):
213
Test if timeouts for iq's that haven't yet received a response
214
are cancelled on stream disconnect.
221
xs.connectionLost("Closed by peer")
222
self.assertFailure(d, ConnectionLost)
223
self.assertFalse(self.clock.calls)
228
class XmlStreamTest(unittest.TestCase):
230
def onStreamStart(self, obj):
231
self.gotStreamStart = True
234
def onStreamEnd(self, obj):
235
self.gotStreamEnd = True
238
def onStreamError(self, obj):
239
self.gotStreamError = True
244
Set up XmlStream and several observers.
246
self.gotStreamStart = False
247
self.gotStreamEnd = False
248
self.gotStreamError = False
249
xs = xmlstream.XmlStream(xmlstream.Authenticator())
250
xs.addObserver('//event/stream/start', self.onStreamStart)
251
xs.addObserver('//event/stream/end', self.onStreamEnd)
252
xs.addObserver('//event/stream/error', self.onStreamError)
253
xs.makeConnection(proto_helpers.StringTransportWithDisconnection())
254
xs.transport.protocol = xs
255
xs.namespace = 'testns'
260
def test_sendHeaderBasic(self):
262
Basic test on the header sent by sendHeader.
266
splitHeader = self.xmlstream.transport.value()[0:-1].split(' ')
267
self.assertIn("<stream:stream", splitHeader)
268
self.assertIn("xmlns:stream='http://etherx.jabber.org/streams'",
270
self.assertIn("xmlns='testns'", splitHeader)
271
self.assertIn("version='1.0'", splitHeader)
272
self.assertTrue(xs._headerSent)
275
def test_sendHeaderAdditionalNamespaces(self):
277
Test for additional namespace declarations.
280
xs.prefixes['jabber:server:dialback'] = 'db'
282
splitHeader = self.xmlstream.transport.value()[0:-1].split(' ')
283
self.assertIn("<stream:stream", splitHeader)
284
self.assertIn("xmlns:stream='http://etherx.jabber.org/streams'",
286
self.assertIn("xmlns:db='jabber:server:dialback'", splitHeader)
287
self.assertIn("xmlns='testns'", splitHeader)
288
self.assertIn("version='1.0'", splitHeader)
289
self.assertTrue(xs._headerSent)
292
def test_sendHeaderInitiating(self):
294
Test addressing when initiating a stream.
297
xs.thisEntity = jid.JID('thisHost')
298
xs.otherEntity = jid.JID('otherHost')
301
splitHeader = xs.transport.value()[0:-1].split(' ')
302
self.assertIn("to='otherhost'", splitHeader)
303
self.assertIn("from='thishost'", splitHeader)
306
def test_sendHeaderReceiving(self):
308
Test addressing when receiving a stream.
311
xs.thisEntity = jid.JID('thisHost')
312
xs.otherEntity = jid.JID('otherHost')
313
xs.initiating = False
316
splitHeader = xs.transport.value()[0:-1].split(' ')
317
self.assertIn("to='otherhost'", splitHeader)
318
self.assertIn("from='thishost'", splitHeader)
319
self.assertIn("id='session01'", splitHeader)
322
def test_receiveStreamError(self):
324
Test events when a stream error is received.
327
xs.dataReceived("<stream:stream xmlns='jabber:client' "
328
"xmlns:stream='http://etherx.jabber.org/streams' "
329
"from='example.com' id='12345' version='1.0'>")
330
xs.dataReceived("<stream:error/>")
331
self.assertTrue(self.gotStreamError)
332
self.assertTrue(self.gotStreamEnd)
335
def test_sendStreamErrorInitiating(self):
337
Test sendStreamError on an initiating xmlstream with a header sent.
339
An error should be sent out and the connection lost.
345
xs.sendStreamError(error.StreamError('version-unsupported'))
346
self.assertNotEqual('', xs.transport.value())
347
self.assertTrue(self.gotStreamEnd)
350
def test_sendStreamErrorInitiatingNoHeader(self):
352
Test sendStreamError on an initiating xmlstream without having sent a
355
In this case, no header should be generated. Also, the error should
356
not be sent out on the stream. Just closing the connection.
361
xs.sendStreamError(error.StreamError('version-unsupported'))
362
self.assertNot(xs._headerSent)
363
self.assertEqual('', xs.transport.value())
364
self.assertTrue(self.gotStreamEnd)
367
def test_sendStreamErrorReceiving(self):
369
Test sendStreamError on a receiving xmlstream with a header sent.
371
An error should be sent out and the connection lost.
374
xs.initiating = False
377
xs.sendStreamError(error.StreamError('version-unsupported'))
378
self.assertNotEqual('', xs.transport.value())
379
self.assertTrue(self.gotStreamEnd)
382
def test_sendStreamErrorReceivingNoHeader(self):
384
Test sendStreamError on a receiving xmlstream without having sent a
387
In this case, a header should be generated. Then, the error should
388
be sent out on the stream followed by closing the connection.
391
xs.initiating = False
393
xs.sendStreamError(error.StreamError('version-unsupported'))
394
self.assertTrue(xs._headerSent)
395
self.assertNotEqual('', xs.transport.value())
396
self.assertTrue(self.gotStreamEnd)
399
def test_reset(self):
401
Test resetting the XML stream to start a new layer.
407
self.assertNotEqual(stream, xs.stream)
408
self.assertNot(xs._headerSent)
413
Test send with various types of objects.
416
xs.send('<presence/>')
417
self.assertEqual(xs.transport.value(), '<presence/>')
420
el = domish.Element(('testns', 'presence'))
422
self.assertEqual(xs.transport.value(), '<presence/>')
425
el = domish.Element(('http://etherx.jabber.org/streams', 'features'))
427
self.assertEqual(xs.transport.value(), '<stream:features/>')
430
def test_authenticator(self):
432
Test that the associated authenticator is correctly called.
434
connectionMadeCalls = []
435
streamStartedCalls = []
436
associateWithStreamCalls = []
438
class TestAuthenticator:
439
def connectionMade(self):
440
connectionMadeCalls.append(None)
442
def streamStarted(self, rootElement):
443
streamStartedCalls.append(rootElement)
445
def associateWithStream(self, xs):
446
associateWithStreamCalls.append(xs)
448
a = TestAuthenticator()
449
xs = xmlstream.XmlStream(a)
450
self.assertEqual([xs], associateWithStreamCalls)
452
self.assertEqual([None], connectionMadeCalls)
453
xs.dataReceived("<stream:stream xmlns='jabber:client' "
454
"xmlns:stream='http://etherx.jabber.org/streams' "
455
"from='example.com' id='12345'>")
456
self.assertEqual(1, len(streamStartedCalls))
458
self.assertEqual([None], connectionMadeCalls)
462
class TestError(Exception):
467
class AuthenticatorTest(unittest.TestCase):
469
self.authenticator = xmlstream.Authenticator()
470
self.xmlstream = xmlstream.XmlStream(self.authenticator)
473
def test_streamStart(self):
475
Test streamStart to fill the appropriate attributes from the
479
xs.makeConnection(proto_helpers.StringTransport())
480
xs.dataReceived("<stream:stream xmlns='jabber:client' "
481
"xmlns:stream='http://etherx.jabber.org/streams' "
482
"from='example.org' to='example.com' id='12345' "
484
self.assertEqual((1, 0), xs.version)
485
self.assertIdentical(None, xs.sid)
486
self.assertEqual('invalid', xs.namespace)
487
self.assertIdentical(None, xs.otherEntity)
488
self.assertEqual(None, xs.thisEntity)
491
def test_streamStartLegacy(self):
493
Test streamStart to fill the appropriate attributes from the
494
stream header for a pre-XMPP-1.0 header.
497
xs.makeConnection(proto_helpers.StringTransport())
498
xs.dataReceived("<stream:stream xmlns='jabber:client' "
499
"xmlns:stream='http://etherx.jabber.org/streams' "
500
"from='example.com' id='12345'>")
501
self.assertEqual((0, 0), xs.version)
504
def test_streamBadVersionOneDigit(self):
506
Test streamStart to fill the appropriate attributes from the
507
stream header for a version with only one digit.
510
xs.makeConnection(proto_helpers.StringTransport())
511
xs.dataReceived("<stream:stream xmlns='jabber:client' "
512
"xmlns:stream='http://etherx.jabber.org/streams' "
513
"from='example.com' id='12345' version='1'>")
514
self.assertEqual((0, 0), xs.version)
517
def test_streamBadVersionNoNumber(self):
519
Test streamStart to fill the appropriate attributes from the
520
stream header for a malformed version.
523
xs.makeConnection(proto_helpers.StringTransport())
524
xs.dataReceived("<stream:stream xmlns='jabber:client' "
525
"xmlns:stream='http://etherx.jabber.org/streams' "
526
"from='example.com' id='12345' version='blah'>")
527
self.assertEqual((0, 0), xs.version)
531
class ConnectAuthenticatorTest(unittest.TestCase):
534
self.gotAuthenticated = False
535
self.initFailure = None
536
self.authenticator = xmlstream.ConnectAuthenticator('otherHost')
537
self.xmlstream = xmlstream.XmlStream(self.authenticator)
538
self.xmlstream.addObserver('//event/stream/authd', self.onAuthenticated)
539
self.xmlstream.addObserver('//event/xmpp/initfailed', self.onInitFailed)
542
def onAuthenticated(self, obj):
543
self.gotAuthenticated = True
546
def onInitFailed(self, failure):
547
self.initFailure = failure
550
def testSucces(self):
552
Test successful completion of an initialization step.
555
def initialize(self):
559
self.xmlstream.initializers = [init]
561
self.authenticator.initializeStream()
562
self.assertEqual([], self.xmlstream.initializers)
563
self.assertTrue(self.gotAuthenticated)
566
def testFailure(self):
568
Test failure of an initialization step.
571
def initialize(self):
575
self.xmlstream.initializers = [init]
577
self.authenticator.initializeStream()
578
self.assertEqual([init], self.xmlstream.initializers)
579
self.assertFalse(self.gotAuthenticated)
580
self.assertNotIdentical(None, self.initFailure)
581
self.assertTrue(self.initFailure.check(TestError))
584
def test_streamStart(self):
586
Test streamStart to fill the appropriate attributes from the
589
self.authenticator.namespace = 'testns'
591
xs.makeConnection(proto_helpers.StringTransport())
592
xs.dataReceived("<stream:stream xmlns='jabber:client' "
593
"xmlns:stream='http://etherx.jabber.org/streams' "
594
"from='example.com' to='example.org' id='12345' "
596
self.assertEqual((1, 0), xs.version)
597
self.assertEqual('12345', xs.sid)
598
self.assertEqual('testns', xs.namespace)
599
self.assertEqual('example.com', xs.otherEntity.host)
600
self.assertIdentical(None, xs.thisEntity)
601
self.assertNot(self.gotAuthenticated)
602
xs.dataReceived("<stream:features>"
603
"<test xmlns='testns'/>"
604
"</stream:features>")
605
self.assertIn(('testns', 'test'), xs.features)
606
self.assertTrue(self.gotAuthenticated)
610
class ListenAuthenticatorTest(unittest.TestCase):
612
self.authenticator = xmlstream.ListenAuthenticator()
613
self.xmlstream = xmlstream.XmlStream(self.authenticator)
616
def test_streamStart(self):
618
Test streamStart to fill the appropriate attributes from the
622
xs.makeConnection(proto_helpers.StringTransport())
623
self.assertIdentical(None, xs.sid)
624
xs.dataReceived("<stream:stream xmlns='jabber:client' "
625
"xmlns:stream='http://etherx.jabber.org/streams' "
626
"from='example.org' to='example.com' id='12345' "
628
self.assertEqual((1, 0), xs.version)
629
self.assertNotIdentical(None, xs.sid)
630
self.assertNotEquals('12345', xs.sid)
631
self.assertEqual('jabber:client', xs.namespace)
632
self.assertIdentical(None, xs.otherEntity)
633
self.assertEqual('example.com', xs.thisEntity.host)
637
class TLSInitiatingInitializerTest(unittest.TestCase):
642
self.savedSSL = xmlstream.ssl
644
self.authenticator = xmlstream.Authenticator()
645
self.xmlstream = xmlstream.XmlStream(self.authenticator)
646
self.xmlstream.send = self.output.append
647
self.xmlstream.connectionMade()
648
self.xmlstream.dataReceived("<stream:stream xmlns='jabber:client' "
649
"xmlns:stream='http://etherx.jabber.org/streams' "
650
"from='example.com' id='12345' version='1.0'>")
651
self.init = xmlstream.TLSInitiatingInitializer(self.xmlstream)
655
xmlstream.ssl = self.savedSSL
658
def testWantedSupported(self):
660
Test start when TLS is wanted and the SSL library available.
662
self.xmlstream.transport = proto_helpers.StringTransport()
663
self.xmlstream.transport.startTLS = lambda ctx: self.done.append('TLS')
664
self.xmlstream.reset = lambda: self.done.append('reset')
665
self.xmlstream.sendHeader = lambda: self.done.append('header')
667
d = self.init.start()
668
d.addCallback(self.assertEquals, xmlstream.Reset)
669
starttls = self.output[0]
670
self.assertEquals('starttls', starttls.name)
671
self.assertEquals(NS_XMPP_TLS, starttls.uri)
672
self.xmlstream.dataReceived("<proceed xmlns='%s'/>" % NS_XMPP_TLS)
673
self.assertEquals(['TLS', 'reset', 'header'], self.done)
677
if not xmlstream.ssl:
678
testWantedSupported.skip = "SSL not available"
681
def testWantedNotSupportedNotRequired(self):
683
Test start when TLS is wanted and the SSL library available.
687
d = self.init.start()
688
d.addCallback(self.assertEquals, None)
689
self.assertEquals([], self.output)
694
def testWantedNotSupportedRequired(self):
696
Test start when TLS is wanted and the SSL library available.
699
self.init.required = True
701
d = self.init.start()
702
self.assertFailure(d, xmlstream.TLSNotSupported)
703
self.assertEquals([], self.output)
708
def testNotWantedRequired(self):
710
Test start when TLS is not wanted, but required by the server.
712
tls = domish.Element(('urn:ietf:params:xml:ns:xmpp-tls', 'starttls'))
713
tls.addElement('required')
714
self.xmlstream.features = {(tls.uri, tls.name): tls}
715
self.init.wanted = False
717
d = self.init.start()
718
self.assertEquals([], self.output)
719
self.assertFailure(d, xmlstream.TLSRequired)
724
def testNotWantedNotRequired(self):
726
Test start when TLS is not wanted, but required by the server.
728
tls = domish.Element(('urn:ietf:params:xml:ns:xmpp-tls', 'starttls'))
729
self.xmlstream.features = {(tls.uri, tls.name): tls}
730
self.init.wanted = False
732
d = self.init.start()
733
d.addCallback(self.assertEqual, None)
734
self.assertEquals([], self.output)
738
def testFailed(self):
740
Test failed TLS negotiation.
742
# Pretend that ssl is supported, it isn't actually used when the
743
# server starts out with a failure in response to our initial
744
# C{starttls} stanza.
747
d = self.init.start()
748
self.assertFailure(d, xmlstream.TLSFailed)
749
self.xmlstream.dataReceived("<failure xmlns='%s'/>" % NS_XMPP_TLS)
754
class TestFeatureInitializer(xmlstream.BaseFeatureInitiatingInitializer):
755
feature = ('testns', 'test')
758
return defer.succeed(None)
762
class BaseFeatureInitiatingInitializerTest(unittest.TestCase):
765
self.xmlstream = xmlstream.XmlStream(xmlstream.Authenticator())
766
self.init = TestFeatureInitializer(self.xmlstream)
769
def testAdvertized(self):
771
Test that an advertized feature results in successful initialization.
773
self.xmlstream.features = {self.init.feature:
774
domish.Element(self.init.feature)}
775
return self.init.initialize()
778
def testNotAdvertizedRequired(self):
780
Test that when the feature is not advertized, but required by the
781
initializer, an exception is raised.
783
self.init.required = True
784
self.assertRaises(xmlstream.FeatureNotAdvertized, self.init.initialize)
787
def testNotAdvertizedNotRequired(self):
789
Test that when the feature is not advertized, and not required by the
790
initializer, the initializer silently succeeds.
792
self.init.required = False
793
self.assertIdentical(None, self.init.initialize())
797
class ToResponseTest(unittest.TestCase):
799
def test_toResponse(self):
801
Test that a response stanza is generated with addressing swapped.
803
stanza = domish.Element(('jabber:client', 'iq'))
804
stanza['type'] = 'get'
805
stanza['to'] = 'user1@example.com'
806
stanza['from'] = 'user2@example.com/resource'
807
stanza['id'] = 'stanza1'
808
response = xmlstream.toResponse(stanza, 'result')
809
self.assertNotIdentical(stanza, response)
810
self.assertEqual(response['from'], 'user1@example.com')
811
self.assertEqual(response['to'], 'user2@example.com/resource')
812
self.assertEqual(response['type'], 'result')
813
self.assertEqual(response['id'], 'stanza1')
816
def test_toResponseNoFrom(self):
818
Test that a response is generated from a stanza without a from address.
820
stanza = domish.Element(('jabber:client', 'iq'))
821
stanza['type'] = 'get'
822
stanza['to'] = 'user1@example.com'
823
response = xmlstream.toResponse(stanza)
824
self.assertEqual(response['from'], 'user1@example.com')
825
self.assertFalse(response.hasAttribute('to'))
828
def test_toResponseNoTo(self):
830
Test that a response is generated from a stanza without a to address.
832
stanza = domish.Element(('jabber:client', 'iq'))
833
stanza['type'] = 'get'
834
stanza['from'] = 'user2@example.com/resource'
835
response = xmlstream.toResponse(stanza)
836
self.assertFalse(response.hasAttribute('from'))
837
self.assertEqual(response['to'], 'user2@example.com/resource')
840
def test_toResponseNoAddressing(self):
842
Test that a response is generated from a stanza without any addressing.
844
stanza = domish.Element(('jabber:client', 'message'))
845
stanza['type'] = 'chat'
846
response = xmlstream.toResponse(stanza)
847
self.assertFalse(response.hasAttribute('to'))
848
self.assertFalse(response.hasAttribute('from'))
853
Test that a proper response is generated without id attribute.
855
stanza = domish.Element(('jabber:client', 'message'))
856
response = xmlstream.toResponse(stanza)
857
self.assertFalse(response.hasAttribute('id'))
860
def test_noType(self):
862
Test that a proper response is generated without type attribute.
864
stanza = domish.Element(('jabber:client', 'message'))
865
response = xmlstream.toResponse(stanza)
866
self.assertFalse(response.hasAttribute('type'))
869
class DummyFactory(object):
871
Dummy XmlStream factory that only registers bootstrap observers.
877
def addBootstrap(self, event, callback):
878
self.callbacks[event] = callback
882
class DummyXMPPHandler(xmlstream.XMPPHandler):
884
Dummy XMPP subprotocol handler to count the methods are called on it.
888
self.doneInitialized = 0
892
def makeConnection(self, xs):
893
self.connectionMade()
896
def connectionMade(self):
900
def connectionInitialized(self):
901
self.doneInitialized += 1
904
def connectionLost(self, reason):
909
class XMPPHandlerTest(unittest.TestCase):
911
Tests for L{xmlstream.XMPPHandler}.
914
def test_interface(self):
916
L{xmlstream.XMPPHandler} implements L{ijabber.IXMPPHandler}.
918
verifyObject(ijabber.IXMPPHandler, xmlstream.XMPPHandler())
923
Test that data is passed on for sending by the stream manager.
925
class DummyStreamManager(object):
929
def send(self, data):
930
self.outlist.append(data)
932
handler = xmlstream.XMPPHandler()
933
handler.parent = DummyStreamManager()
934
handler.send('<presence/>')
935
self.assertEquals(['<presence/>'], handler.parent.outlist)
938
def test_makeConnection(self):
940
Test that makeConnection saves the XML stream and calls connectionMade.
942
class TestXMPPHandler(xmlstream.XMPPHandler):
943
def connectionMade(self):
946
handler = TestXMPPHandler()
947
xs = xmlstream.XmlStream(xmlstream.Authenticator())
948
handler.makeConnection(xs)
949
self.assertTrue(handler.doneMade)
950
self.assertIdentical(xs, handler.xmlstream)
953
def test_connectionLost(self):
955
Test that connectionLost forgets the XML stream.
957
handler = xmlstream.XMPPHandler()
958
xs = xmlstream.XmlStream(xmlstream.Authenticator())
959
handler.makeConnection(xs)
960
handler.connectionLost(Exception())
961
self.assertIdentical(None, handler.xmlstream)
965
class XMPPHandlerCollectionTest(unittest.TestCase):
967
Tests for L{xmlstream.XMPPHandlerCollection}.
971
self.collection = xmlstream.XMPPHandlerCollection()
974
def test_interface(self):
976
L{xmlstream.StreamManager} implements L{ijabber.IXMPPHandlerCollection}.
978
verifyObject(ijabber.IXMPPHandlerCollection, self.collection)
981
def test_addHandler(self):
983
Test the addition of a protocol handler.
985
handler = DummyXMPPHandler()
986
handler.setHandlerParent(self.collection)
987
self.assertIn(handler, self.collection)
988
self.assertIdentical(self.collection, handler.parent)
991
def test_removeHandler(self):
993
Test removal of a protocol handler.
995
handler = DummyXMPPHandler()
996
handler.setHandlerParent(self.collection)
997
handler.disownHandlerParent(self.collection)
998
self.assertNotIn(handler, self.collection)
999
self.assertIdentical(None, handler.parent)
1003
class StreamManagerTest(unittest.TestCase):
1005
Tests for L{xmlstream.StreamManager}.
1009
factory = DummyFactory()
1010
self.streamManager = xmlstream.StreamManager(factory)
1013
def test_basic(self):
1015
Test correct initialization and setup of factory observers.
1017
sm = self.streamManager
1018
self.assertIdentical(None, sm.xmlstream)
1019
self.assertEquals([], sm.handlers)
1020
self.assertEquals(sm._connected,
1021
sm.factory.callbacks['//event/stream/connected'])
1022
self.assertEquals(sm._authd,
1023
sm.factory.callbacks['//event/stream/authd'])
1024
self.assertEquals(sm._disconnected,
1025
sm.factory.callbacks['//event/stream/end'])
1026
self.assertEquals(sm.initializationFailed,
1027
sm.factory.callbacks['//event/xmpp/initfailed'])
1030
def test_connected(self):
1032
Test that protocol handlers have their connectionMade method called
1033
when the XML stream is connected.
1035
sm = self.streamManager
1036
handler = DummyXMPPHandler()
1037
handler.setHandlerParent(sm)
1038
xs = xmlstream.XmlStream(xmlstream.Authenticator())
1040
self.assertEquals(1, handler.doneMade)
1041
self.assertEquals(0, handler.doneInitialized)
1042
self.assertEquals(0, handler.doneLost)
1045
def test_connectedLogTrafficFalse(self):
1047
Test raw data functions unset when logTraffic is set to False.
1049
sm = self.streamManager
1050
handler = DummyXMPPHandler()
1051
handler.setHandlerParent(sm)
1052
xs = xmlstream.XmlStream(xmlstream.Authenticator())
1054
self.assertIdentical(None, xs.rawDataInFn)
1055
self.assertIdentical(None, xs.rawDataOutFn)
1058
def test_connectedLogTrafficTrue(self):
1060
Test raw data functions set when logTraffic is set to True.
1062
sm = self.streamManager
1063
sm.logTraffic = True
1064
handler = DummyXMPPHandler()
1065
handler.setHandlerParent(sm)
1066
xs = xmlstream.XmlStream(xmlstream.Authenticator())
1068
self.assertNotIdentical(None, xs.rawDataInFn)
1069
self.assertNotIdentical(None, xs.rawDataOutFn)
1072
def test_authd(self):
1074
Test that protocol handlers have their connectionInitialized method
1075
called when the XML stream is initialized.
1077
sm = self.streamManager
1078
handler = DummyXMPPHandler()
1079
handler.setHandlerParent(sm)
1080
xs = xmlstream.XmlStream(xmlstream.Authenticator())
1082
self.assertEquals(0, handler.doneMade)
1083
self.assertEquals(1, handler.doneInitialized)
1084
self.assertEquals(0, handler.doneLost)
1087
def test_disconnected(self):
1089
Test that protocol handlers have their connectionLost method
1090
called when the XML stream is disconnected.
1092
sm = self.streamManager
1093
handler = DummyXMPPHandler()
1094
handler.setHandlerParent(sm)
1095
xs = xmlstream.XmlStream(xmlstream.Authenticator())
1096
sm._disconnected(xs)
1097
self.assertEquals(0, handler.doneMade)
1098
self.assertEquals(0, handler.doneInitialized)
1099
self.assertEquals(1, handler.doneLost)
1102
def test_addHandler(self):
1104
Test the addition of a protocol handler while not connected.
1106
sm = self.streamManager
1107
handler = DummyXMPPHandler()
1108
handler.setHandlerParent(sm)
1110
self.assertEquals(0, handler.doneMade)
1111
self.assertEquals(0, handler.doneInitialized)
1112
self.assertEquals(0, handler.doneLost)
1115
def test_addHandlerInitialized(self):
1117
Test the addition of a protocol handler after the stream
1118
have been initialized.
1120
Make sure that the handler will have the connected stream
1121
passed via C{makeConnection} and have C{connectionInitialized}
1124
sm = self.streamManager
1125
xs = xmlstream.XmlStream(xmlstream.Authenticator())
1128
handler = DummyXMPPHandler()
1129
handler.setHandlerParent(sm)
1131
self.assertEquals(1, handler.doneMade)
1132
self.assertEquals(1, handler.doneInitialized)
1133
self.assertEquals(0, handler.doneLost)
1136
def test_sendInitialized(self):
1138
Test send when the stream has been initialized.
1140
The data should be sent directly over the XML stream.
1142
factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator())
1143
sm = xmlstream.StreamManager(factory)
1144
xs = factory.buildProtocol(None)
1145
xs.transport = proto_helpers.StringTransport()
1147
xs.dataReceived("<stream:stream xmlns='jabber:client' "
1148
"xmlns:stream='http://etherx.jabber.org/streams' "
1149
"from='example.com' id='12345'>")
1150
xs.dispatch(xs, "//event/stream/authd")
1151
sm.send("<presence/>")
1152
self.assertEquals("<presence/>", xs.transport.value())
1155
def test_sendNotConnected(self):
1157
Test send when there is no established XML stream.
1159
The data should be cached until an XML stream has been established and
1162
factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator())
1163
sm = xmlstream.StreamManager(factory)
1164
handler = DummyXMPPHandler()
1165
sm.addHandler(handler)
1167
xs = factory.buildProtocol(None)
1168
xs.transport = proto_helpers.StringTransport()
1169
sm.send("<presence/>")
1170
self.assertEquals("", xs.transport.value())
1171
self.assertEquals("<presence/>", sm._packetQueue[0])
1174
self.assertEquals("", xs.transport.value())
1175
self.assertEquals("<presence/>", sm._packetQueue[0])
1177
xs.dataReceived("<stream:stream xmlns='jabber:client' "
1178
"xmlns:stream='http://etherx.jabber.org/streams' "
1179
"from='example.com' id='12345'>")
1180
xs.dispatch(xs, "//event/stream/authd")
1182
self.assertEquals("<presence/>", xs.transport.value())
1183
self.assertFalse(sm._packetQueue)
1186
def test_sendNotInitialized(self):
1188
Test send when the stream is connected but not yet initialized.
1190
The data should be cached until the XML stream has been initialized.
1192
factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator())
1193
sm = xmlstream.StreamManager(factory)
1194
xs = factory.buildProtocol(None)
1195
xs.transport = proto_helpers.StringTransport()
1197
xs.dataReceived("<stream:stream xmlns='jabber:client' "
1198
"xmlns:stream='http://etherx.jabber.org/streams' "
1199
"from='example.com' id='12345'>")
1200
sm.send("<presence/>")
1201
self.assertEquals("", xs.transport.value())
1202
self.assertEquals("<presence/>", sm._packetQueue[0])
1205
def test_sendDisconnected(self):
1207
Test send after XML stream disconnection.
1209
The data should be cached until a new XML stream has been established
1212
factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator())
1213
sm = xmlstream.StreamManager(factory)
1214
handler = DummyXMPPHandler()
1215
sm.addHandler(handler)
1217
xs = factory.buildProtocol(None)
1219
xs.transport = proto_helpers.StringTransport()
1220
xs.connectionLost(None)
1222
sm.send("<presence/>")
1223
self.assertEquals("", xs.transport.value())
1224
self.assertEquals("<presence/>", sm._packetQueue[0])
1228
class XmlStreamServerFactoryTest(GenericXmlStreamFactoryTestsMixin):
1230
Tests for L{xmlstream.XmlStreamServerFactory}.
1235
Set up a server factory with a authenticator factory function.
1237
class TestAuthenticator(object):
1239
self.xmlstreams = []
1241
def associateWithStream(self, xs):
1242
self.xmlstreams.append(xs)
1244
def authenticatorFactory():
1245
return TestAuthenticator()
1247
self.factory = xmlstream.XmlStreamServerFactory(authenticatorFactory)
1250
def test_interface(self):
1252
L{XmlStreamServerFactory} is a L{Factory}.
1254
verifyObject(IProtocolFactory, self.factory)
1257
def test_buildProtocolAuthenticatorInstantiation(self):
1259
The authenticator factory should be used to instantiate the
1260
authenticator and pass it to the protocol.
1262
The default protocol, L{XmlStream} stores the authenticator it is
1263
passed, and calls its C{associateWithStream} method. so we use that to
1264
check whether our authenticator factory is used and the protocol
1265
instance gets an authenticator.
1267
xs = self.factory.buildProtocol(None)
1268
self.assertEquals([xs], xs.authenticator.xmlstreams)
1271
def test_buildProtocolXmlStream(self):
1273
The protocol factory creates Jabber XML Stream protocols by default.
1275
xs = self.factory.buildProtocol(None)
1276
self.assertIsInstance(xs, xmlstream.XmlStream)
1279
def test_buildProtocolTwice(self):
1281
Subsequent calls to buildProtocol should result in different instances
1282
of the protocol, as well as their authenticators.
1284
xs1 = self.factory.buildProtocol(None)
1285
xs2 = self.factory.buildProtocol(None)
1286
self.assertNotIdentical(xs1, xs2)
1287
self.assertNotIdentical(xs1.authenticator, xs2.authenticator)