source: wokkel/test/test_subprotocols.py @ 164:bf7b7e600db8

Last change on this file since 164:bf7b7e600db8 was 101:d88462a49f86, checked in by Ralph Meijer <ralphm@…>, 9 years ago

Add request method to XMPPHandler, passing up to its StreamManager?.

  • Property exe set to *
File size: 30.1 KB
Line 
1# Copyright (c) Ralph Meijer.
2# See LICENSE for details.
3
4"""
5Tests for L{wokkel.subprotocols}
6"""
7
8from zope.interface.verify import verifyObject
9
10from twisted.trial import unittest
11from twisted.test import proto_helpers
12from twisted.internet import defer, task
13from twisted.internet.error import ConnectionDone
14from twisted.python import failure
15from twisted.words.xish import domish
16from twisted.words.protocols.jabber import error, xmlstream
17
18from wokkel import generic, iwokkel, subprotocols
19
20class DummyFactory(object):
21    """
22    Dummy XmlStream factory that only registers bootstrap observers.
23    """
24    def __init__(self):
25        self.callbacks = {}
26
27
28    def addBootstrap(self, event, callback):
29        self.callbacks[event] = callback
30
31
32
33class DummyXMPPHandler(subprotocols.XMPPHandler):
34    """
35    Dummy XMPP subprotocol handler to count the methods are called on it.
36    """
37    def __init__(self):
38        self.doneMade = 0
39        self.doneInitialized = 0
40        self.doneLost = 0
41
42
43    def makeConnection(self, xs):
44        self.connectionMade()
45
46
47    def connectionMade(self):
48        self.doneMade += 1
49
50
51    def connectionInitialized(self):
52        self.doneInitialized += 1
53
54
55    def connectionLost(self, reason):
56        self.doneLost += 1
57
58
59
60class FailureReasonXMPPHandler(subprotocols.XMPPHandler):
61    """
62    Dummy handler specifically for failure Reason tests.
63    """
64    def __init__(self):
65        self.gotFailureReason = False
66
67
68    def connectionLost(self, reason):
69        if isinstance(reason, failure.Failure):
70            self.gotFailureReason = True
71
72
73
74class IQGetStanza(generic.Stanza):
75    timeout = None
76
77    stanzaKind = 'iq'
78    stanzaType = 'get'
79    stanzaID = 'test'
80
81
82
83class XMPPHandlerTest(unittest.TestCase):
84    """
85    Tests for L{subprotocols.XMPPHandler}.
86    """
87
88    def test_interface(self):
89        """
90        L{xmlstream.XMPPHandler} implements L{iwokkel.IXMPPHandler}.
91        """
92        verifyObject(iwokkel.IXMPPHandler, subprotocols.XMPPHandler())
93
94
95    def test_send(self):
96        """
97        Test that data is passed on for sending by the stream manager.
98        """
99        class DummyStreamManager(object):
100            def __init__(self):
101                self.outlist = []
102
103            def send(self, data):
104                self.outlist.append(data)
105
106        handler = subprotocols.XMPPHandler()
107        handler.parent = DummyStreamManager()
108        handler.send('<presence/>')
109        self.assertEquals(['<presence/>'], handler.parent.outlist)
110
111
112    def test_makeConnection(self):
113        """
114        Test that makeConnection saves the XML stream and calls connectionMade.
115        """
116        class TestXMPPHandler(subprotocols.XMPPHandler):
117            def connectionMade(self):
118                self.doneMade = True
119
120        handler = TestXMPPHandler()
121        xs = xmlstream.XmlStream(xmlstream.Authenticator())
122        handler.makeConnection(xs)
123        self.assertTrue(handler.doneMade)
124        self.assertIdentical(xs, handler.xmlstream)
125
126
127    def test_connectionLost(self):
128        """
129        Test that connectionLost forgets the XML stream.
130        """
131        handler = subprotocols.XMPPHandler()
132        xs = xmlstream.XmlStream(xmlstream.Authenticator())
133        handler.makeConnection(xs)
134        handler.connectionLost(Exception())
135        self.assertIdentical(None, handler.xmlstream)
136
137
138    def test_request(self):
139        """
140        A request is passed up to the stream manager.
141        """
142        class DummyStreamManager(object):
143            def __init__(self):
144                self.requests = []
145
146            def request(self, request):
147                self.requests.append(request)
148                return defer.succeed(None)
149
150        handler = subprotocols.XMPPHandler()
151        handler.parent = DummyStreamManager()
152        request = IQGetStanza()
153        d = handler.request(request)
154        self.assertEquals(1, len(handler.parent.requests))
155        self.assertIdentical(request, handler.parent.requests[-1])
156        return d
157
158
159
160class XMPPHandlerCollectionTest(unittest.TestCase):
161    """
162    Tests for L{subprotocols.XMPPHandlerCollection}.
163    """
164
165    def setUp(self):
166        self.collection = subprotocols.XMPPHandlerCollection()
167
168
169    def test_interface(self):
170        """
171        L{subprotocols.StreamManager} implements L{iwokkel.IXMPPHandlerCollection}.
172        """
173        verifyObject(iwokkel.IXMPPHandlerCollection, self.collection)
174
175
176    def test_addHandler(self):
177        """
178        Test the addition of a protocol handler.
179        """
180        handler = DummyXMPPHandler()
181        handler.setHandlerParent(self.collection)
182        self.assertIn(handler, self.collection)
183        self.assertIdentical(self.collection, handler.parent)
184
185
186    def test_removeHandler(self):
187        """
188        Test removal of a protocol handler.
189        """
190        handler = DummyXMPPHandler()
191        handler.setHandlerParent(self.collection)
192        handler.disownHandlerParent(self.collection)
193        self.assertNotIn(handler, self.collection)
194        self.assertIdentical(None, handler.parent)
195
196
197
198class StreamManagerTest(unittest.TestCase):
199    """
200    Tests for L{subprotocols.StreamManager}.
201    """
202
203    def setUp(self):
204        factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator())
205        self.clock = task.Clock()
206        self.streamManager = subprotocols.StreamManager(factory, self.clock)
207        self.xmlstream = factory.buildProtocol(None)
208        self.transport = proto_helpers.StringTransport()
209        self.xmlstream.transport = self.transport
210
211        self.request = IQGetStanza()
212
213    def _streamStarted(self):
214        """
215        Bring the test stream to the initialized state.
216        """
217        self.xmlstream.connectionMade()
218        self.xmlstream.dataReceived(
219                "<stream:stream xmlns='jabber:client' "
220                    "xmlns:stream='http://etherx.jabber.org/streams' "
221                    "from='example.com' id='12345'>")
222        self.xmlstream.dispatch(self.xmlstream, "//event/stream/authd")
223
224
225    def test_basic(self):
226        """
227        Test correct initialization and setup of factory observers.
228        """
229        factory = DummyFactory()
230        sm = subprotocols.StreamManager(factory)
231        self.assertIdentical(None, sm.xmlstream)
232        self.assertEquals([], sm.handlers)
233        self.assertEquals(sm._connected,
234                          sm.factory.callbacks['//event/stream/connected'])
235        self.assertEquals(sm._authd,
236                          sm.factory.callbacks['//event/stream/authd'])
237        self.assertEquals(sm._disconnected,
238                          sm.factory.callbacks['//event/stream/end'])
239        self.assertEquals(sm.initializationFailed,
240                          sm.factory.callbacks['//event/xmpp/initfailed'])
241
242
243    def test_connected(self):
244        """
245        Test that protocol handlers have their connectionMade method called
246        when the XML stream is connected.
247        """
248        sm = self.streamManager
249        handler = DummyXMPPHandler()
250        handler.setHandlerParent(sm)
251        xs = xmlstream.XmlStream(xmlstream.Authenticator())
252        sm._connected(xs)
253        self.assertEquals(1, handler.doneMade)
254        self.assertEquals(0, handler.doneInitialized)
255        self.assertEquals(0, handler.doneLost)
256
257
258    def test_connectedLogTrafficFalse(self):
259        """
260        Test raw data functions unset when logTraffic is set to False.
261        """
262        sm = self.streamManager
263        handler = DummyXMPPHandler()
264        handler.setHandlerParent(sm)
265        xs = xmlstream.XmlStream(xmlstream.Authenticator())
266        sm._connected(xs)
267        self.assertIdentical(None, xs.rawDataInFn)
268        self.assertIdentical(None, xs.rawDataOutFn)
269
270
271    def test_connectedLogTrafficTrue(self):
272        """
273        Test raw data functions set when logTraffic is set to True.
274        """
275        sm = self.streamManager
276        sm.logTraffic = True
277        handler = DummyXMPPHandler()
278        handler.setHandlerParent(sm)
279        xs = xmlstream.XmlStream(xmlstream.Authenticator())
280        sm._connected(xs)
281        self.assertNotIdentical(None, xs.rawDataInFn)
282        self.assertNotIdentical(None, xs.rawDataOutFn)
283
284
285    def test_authd(self):
286        """
287        Test that protocol handlers have their connectionInitialized method
288        called when the XML stream is initialized.
289        """
290        sm = self.streamManager
291        handler = DummyXMPPHandler()
292        handler.setHandlerParent(sm)
293        xs = xmlstream.XmlStream(xmlstream.Authenticator())
294        sm._authd(xs)
295        self.assertEquals(0, handler.doneMade)
296        self.assertEquals(1, handler.doneInitialized)
297        self.assertEquals(0, handler.doneLost)
298
299
300    def test_disconnected(self):
301        """
302        Protocol handlers have connectionLost called on stream disconnect.
303        """
304        sm = self.streamManager
305        handler = DummyXMPPHandler()
306        handler.setHandlerParent(sm)
307        sm._disconnected(None)
308        self.assertEquals(0, handler.doneMade)
309        self.assertEquals(0, handler.doneInitialized)
310        self.assertEquals(1, handler.doneLost)
311
312
313    def test_disconnectedReason(self):
314        """
315        A L{STREAM_END_EVENT} results in L{StreamManager} firing the handlers
316        L{connectionLost} methods, passing a L{failure.Failure} reason.
317        """
318        sm = self.streamManager
319        handler = FailureReasonXMPPHandler()
320        handler.setHandlerParent(sm)
321        xs = xmlstream.XmlStream(xmlstream.Authenticator())
322        sm._disconnected(failure.Failure(Exception("no reason")))
323        self.assertEquals(True, handler.gotFailureReason)
324
325
326    def test_addHandler(self):
327        """
328        Test the addition of a protocol handler while not connected.
329        """
330        sm = self.streamManager
331        handler = DummyXMPPHandler()
332        handler.setHandlerParent(sm)
333
334        self.assertEquals(0, handler.doneMade)
335        self.assertEquals(0, handler.doneInitialized)
336        self.assertEquals(0, handler.doneLost)
337
338
339    def test_addHandlerConnected(self):
340        """
341        Adding a handler when connected doesn't call connectionInitialized.
342        """
343        sm = self.streamManager
344        xs = xmlstream.XmlStream(xmlstream.Authenticator())
345        sm._connected(xs)
346        handler = DummyXMPPHandler()
347        handler.setHandlerParent(sm)
348
349        self.assertEquals(1, handler.doneMade)
350        self.assertEquals(0, handler.doneInitialized)
351        self.assertEquals(0, handler.doneLost)
352
353
354    def test_addHandlerConnectedNested(self):
355        """
356        Adding a handler in connectionMade doesn't cause 2nd call.
357        """
358        class NestingHandler(DummyXMPPHandler):
359            nestedHandler = None
360
361            def connectionMade(self):
362                DummyXMPPHandler.connectionMade(self)
363                self.nestedHandler = DummyXMPPHandler()
364                self.nestedHandler.setHandlerParent(self.parent)
365
366        sm = self.streamManager
367        xs = xmlstream.XmlStream(xmlstream.Authenticator())
368        handler = NestingHandler()
369        handler.setHandlerParent(sm)
370        sm._connected(xs)
371
372        self.assertEquals(1, handler.doneMade)
373        self.assertEquals(0, handler.doneInitialized)
374        self.assertEquals(0, handler.doneLost)
375
376        self.assertEquals(1, handler.nestedHandler.doneMade)
377        self.assertEquals(0, handler.nestedHandler.doneInitialized)
378        self.assertEquals(0, handler.nestedHandler.doneLost)
379
380
381
382    def test_addHandlerInitialized(self):
383        """
384        Test the addition of a protocol handler after the stream
385        have been initialized.
386
387        Make sure that the handler will have the connected stream
388        passed via C{makeConnection} and have C{connectionInitialized}
389        called.
390        """
391        sm = self.streamManager
392        xs = xmlstream.XmlStream(xmlstream.Authenticator())
393        sm._connected(xs)
394        sm._authd(xs)
395        handler = DummyXMPPHandler()
396        handler.setHandlerParent(sm)
397
398        self.assertEquals(1, handler.doneMade)
399        self.assertEquals(1, handler.doneInitialized)
400        self.assertEquals(0, handler.doneLost)
401
402
403    def test_addHandlerInitializedNested(self):
404        """
405        Adding a handler in connectionInitialized doesn't cause 2nd call.
406        """
407        class NestingHandler(DummyXMPPHandler):
408            nestedHandler = None
409
410            def connectionInitialized(self):
411                DummyXMPPHandler.connectionInitialized(self)
412                self.nestedHandler = DummyXMPPHandler()
413                self.nestedHandler.setHandlerParent(self.parent)
414
415        sm = self.streamManager
416        xs = xmlstream.XmlStream(xmlstream.Authenticator())
417        handler = NestingHandler()
418        handler.setHandlerParent(sm)
419        sm._connected(xs)
420        sm._authd(xs)
421
422        self.assertEquals(1, handler.doneMade)
423        self.assertEquals(1, handler.doneInitialized)
424        self.assertEquals(0, handler.doneLost)
425
426        self.assertEquals(1, handler.nestedHandler.doneMade)
427        self.assertEquals(1, handler.nestedHandler.doneInitialized)
428        self.assertEquals(0, handler.nestedHandler.doneLost)
429
430
431    def test_addHandlerConnectionLostNested(self):
432        """
433        Adding a handler in connectionLost doesn't call connectionLost there.
434        """
435        class NestingHandler(DummyXMPPHandler):
436            nestedHandler = None
437
438            def connectionLost(self, reason):
439                DummyXMPPHandler.connectionLost(self, reason)
440                self.nestedHandler = DummyXMPPHandler()
441                self.nestedHandler.setHandlerParent(self.parent)
442
443        sm = self.streamManager
444        xs = xmlstream.XmlStream(xmlstream.Authenticator())
445        handler = NestingHandler()
446        handler.setHandlerParent(sm)
447        sm._connected(xs)
448        sm._authd(xs)
449        sm._disconnected(xs)
450
451        self.assertEquals(1, handler.doneMade)
452        self.assertEquals(1, handler.doneInitialized)
453        self.assertEquals(1, handler.doneLost)
454
455        self.assertEquals(0, handler.nestedHandler.doneMade)
456        self.assertEquals(0, handler.nestedHandler.doneInitialized)
457        self.assertEquals(0, handler.nestedHandler.doneLost)
458
459
460
461    def test_removeHandler(self):
462        """
463        Test removal of protocol handler.
464        """
465        sm = self.streamManager
466        handler = DummyXMPPHandler()
467        handler.setHandlerParent(sm)
468        handler.disownHandlerParent(sm)
469        self.assertNotIn(handler, sm)
470        self.assertIdentical(None, handler.parent)
471
472
473    def test_sendInitialized(self):
474        """
475        Test send when the stream has been initialized.
476
477        The data should be sent directly over the XML stream.
478        """
479        factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator())
480        sm = subprotocols.StreamManager(factory)
481        xs = factory.buildProtocol(None)
482        xs.transport = proto_helpers.StringTransport()
483        xs.connectionMade()
484        xs.dataReceived("<stream:stream xmlns='jabber:client' "
485                        "xmlns:stream='http://etherx.jabber.org/streams' "
486                        "from='example.com' id='12345'>")
487        xs.dispatch(xs, "//event/stream/authd")
488        sm.send("<presence/>")
489        self.assertEquals("<presence/>", xs.transport.value())
490
491
492    def test_sendNotConnected(self):
493        """
494        Test send when there is no established XML stream.
495
496        The data should be cached until an XML stream has been established and
497        initialized.
498        """
499        factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator())
500        sm = subprotocols.StreamManager(factory)
501        handler = DummyXMPPHandler()
502        sm.addHandler(handler)
503
504        xs = factory.buildProtocol(None)
505        xs.transport = proto_helpers.StringTransport()
506        sm.send("<presence/>")
507        self.assertEquals("", xs.transport.value())
508        self.assertEquals("<presence/>", sm._packetQueue[0])
509
510        xs.connectionMade()
511        self.assertEquals("", xs.transport.value())
512        self.assertEquals("<presence/>", sm._packetQueue[0])
513
514        xs.dataReceived("<stream:stream xmlns='jabber:client' "
515                        "xmlns:stream='http://etherx.jabber.org/streams' "
516                        "from='example.com' id='12345'>")
517        xs.dispatch(xs, "//event/stream/authd")
518
519        self.assertEquals("<presence/>", xs.transport.value())
520        self.assertFalse(sm._packetQueue)
521
522
523    def test_sendNotInitialized(self):
524        """
525        Test send when the stream is connected but not yet initialized.
526
527        The data should be cached until the XML stream has been initialized.
528        """
529        factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator())
530        sm = subprotocols.StreamManager(factory)
531        xs = factory.buildProtocol(None)
532        xs.transport = proto_helpers.StringTransport()
533        xs.connectionMade()
534        xs.dataReceived("<stream:stream xmlns='jabber:client' "
535                        "xmlns:stream='http://etherx.jabber.org/streams' "
536                        "from='example.com' id='12345'>")
537        sm.send("<presence/>")
538        self.assertEquals("", xs.transport.value())
539        self.assertEquals("<presence/>", sm._packetQueue[0])
540
541
542    def test_sendDisconnected(self):
543        """
544        Test send after XML stream disconnection.
545
546        The data should be cached until a new XML stream has been established
547        and initialized.
548        """
549        factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator())
550        sm = subprotocols.StreamManager(factory)
551        handler = DummyXMPPHandler()
552        sm.addHandler(handler)
553
554        xs = factory.buildProtocol(None)
555        xs.connectionMade()
556        xs.transport = proto_helpers.StringTransport()
557        xs.connectionLost(None)
558
559        sm.send("<presence/>")
560        self.assertEquals("", xs.transport.value())
561        self.assertEquals("<presence/>", sm._packetQueue[0])
562
563
564    def test_requestSendInitialized(self):
565        """
566        A request is sent out over the wire when the stream is initialized.
567        """
568        self._streamStarted()
569
570        self.streamManager.request(self.request)
571        expected = u"<iq type='get' id='%s'/>" % self.request.stanzaID
572        self.assertEquals(expected, self.transport.value())
573
574
575    def test_requestSendInitializedFreshID(self):
576        """
577        A request without an ID gets a fresh one upon send.
578        """
579        self._streamStarted()
580
581        self.request.stanzaID = None
582        self.streamManager.request(self.request)
583        self.assertNotIdentical(None, self.request.stanzaID)
584        expected = u"<iq type='get' id='%s'/>" % self.request.stanzaID
585        self.assertEquals(expected, self.transport.value())
586
587
588    def test_requestSendNotConnected(self):
589        """
590        A request is queued until a stream is initialized.
591        """
592        handler = DummyXMPPHandler()
593        self.streamManager.addHandler(handler)
594
595        self.streamManager.request(self.request)
596        expected = u"<iq type='get' id='test'/>"
597
598        xs = self.xmlstream
599        self.assertEquals("", xs.transport.value())
600
601        xs.connectionMade()
602        self.assertEquals("", xs.transport.value())
603
604        xs.dataReceived("<stream:stream xmlns='jabber:client' "
605                        "xmlns:stream='http://etherx.jabber.org/streams' "
606                        "from='example.com' id='12345'>")
607        xs.dispatch(xs, "//event/stream/authd")
608
609        self.assertEquals(expected, xs.transport.value())
610        self.assertFalse(self.streamManager._packetQueue)
611
612
613    def test_requestResultResponse(self):
614        """
615        A result response gets the request deferred fired with the response.
616        """
617        def cb(result):
618            self.assertEquals(result['type'], 'result')
619
620        self._streamStarted()
621        d = self.streamManager.request(self.request)
622        d.addCallback(cb)
623
624        xs = self.xmlstream
625        xs.dataReceived("<iq type='result' id='test'/>")
626        return d
627
628
629    def test_requestErrorResponse(self):
630        """
631        An error response gets the request deferred fired with a failure.
632        """
633        self._streamStarted()
634        d = self.streamManager.request(self.request)
635        self.assertFailure(d, error.StanzaError)
636
637        xs = self.xmlstream
638        xs.dataReceived("<iq type='error' id='test'/>")
639        return d
640
641
642    def test_requestNonTrackedResponse(self):
643        """
644        Test that untracked iq responses don't trigger any action.
645
646        Untracked means that the id of the incoming response iq is not
647        in the stream's C{iqDeferreds} dictionary.
648        """
649        # Set up a fallback handler that checks the stanza's handled attribute.
650        # If that is set to True, the iq tracker claims to have handled the
651        # response.
652        dispatched = []
653        def cb(iq):
654            dispatched.append(iq)
655
656        self._streamStarted()
657        self.xmlstream.addObserver("/iq", cb, -1)
658
659        # Receive an untracked iq response
660        self.xmlstream.dataReceived("<iq type='result' id='other'/>")
661        self.assertEquals(1, len(dispatched))
662        self.assertFalse(getattr(dispatched[-1], 'handled', False))
663
664
665    def test_requestCleanup(self):
666        """
667        Test if the deferred associated with an iq request is removed
668        from the list kept in the L{XmlStream} object after it has
669        been fired.
670        """
671        self._streamStarted()
672        d = self.streamManager.request(self.request)
673        xs = self.xmlstream
674        xs.dataReceived("<iq type='result' id='test'/>")
675        self.assertNotIn('test', self.streamManager._iqDeferreds)
676        return d
677
678
679    def test_requestDisconnectCleanup(self):
680        """
681        Test if deferreds for iq's that haven't yet received a response
682        have their errback called on stream disconnect.
683        """
684        d = self.streamManager.request(self.request)
685        xs = self.xmlstream
686        xs.connectionLost(failure.Failure(ConnectionDone()))
687        self.assertFailure(d, ConnectionDone)
688        return d
689
690
691    def test_requestNoModifyingDict(self):
692        """
693        Test to make sure the errbacks cannot cause the iteration of the
694        iqDeferreds to blow up in our face.
695        """
696
697        def eb(failure):
698            d = xmlstream.IQ(self.xmlstream).send()
699            d.addErrback(eb)
700
701        d = self.streamManager.request(self.request)
702        d.addErrback(eb)
703        self.xmlstream.connectionLost(failure.Failure(ConnectionDone()))
704        return d
705
706
707    def test_requestTimingOut(self):
708        """
709        Test that an iq request with a defined timeout times out.
710        """
711        self.request.timeout = 60
712        d = self.streamManager.request(self.request)
713        self.assertFailure(d, xmlstream.TimeoutError)
714
715        self.clock.pump([1, 60])
716        self.assertFalse(self.clock.calls)
717        self.assertFalse(self.streamManager._iqDeferreds)
718        return d
719
720
721    def test_requestNotTimingOut(self):
722        """
723        Test that an iq request with a defined timeout does not time out
724        when a response was received before the timeout period elapsed.
725        """
726        self._streamStarted()
727        self.request.timeout = 60
728        d = self.streamManager.request(self.request)
729        self.clock.callLater(1, self.xmlstream.dataReceived,
730                             "<iq type='result' id='test'/>")
731        self.clock.pump([1, 1])
732        self.assertFalse(self.clock.calls)
733        return d
734
735
736    def test_requestDisconnectTimeoutCancellation(self):
737        """
738        Test if timeouts for iq's that haven't yet received a response
739        are cancelled on stream disconnect.
740        """
741
742        self.request.timeout = 60
743        d = self.streamManager.request(self.request)
744
745        self.xmlstream.connectionLost(failure.Failure(ConnectionDone()))
746        self.assertFailure(d, ConnectionDone)
747        self.assertFalse(self.clock.calls)
748        return d
749
750
751    def test_requestNotIQ(self):
752        """
753        The request stanza must be an iq.
754        """
755        stanza = generic.Stanza()
756        stanza.stanzaKind = 'message'
757
758        d = self.streamManager.request(stanza)
759        self.assertFailure(d, ValueError)
760
761
762    def test_requestNotResult(self):
763        """
764        The request stanza cannot be of type 'result'.
765        """
766        stanza = generic.Stanza()
767        stanza.stanzaKind = 'iq'
768        stanza.stanzaType = 'result'
769
770        d = self.streamManager.request(stanza)
771        self.assertFailure(d, ValueError)
772
773
774    def test_requestNotError(self):
775        """
776        The request stanza cannot be of type 'error'.
777        """
778        stanza = generic.Stanza()
779        stanza.stanzaKind = 'iq'
780        stanza.stanzaType = 'error'
781
782        d = self.streamManager.request(stanza)
783        self.assertFailure(d, ValueError)
784
785
786
787class DummyIQHandler(subprotocols.IQHandlerMixin):
788    iqHandlers = {'/iq[@type="get"]': 'onGet'}
789
790    def __init__(self):
791        self.output = []
792        self.xmlstream = xmlstream.XmlStream(xmlstream.Authenticator())
793        self.xmlstream.send = self.output.append
794
795    def send(self, obj):
796        self.xmlstream.send(obj)
797
798
799class IQHandlerTest(unittest.TestCase):
800
801    def test_match(self):
802        """
803        Test that the matching handler gets called.
804        """
805
806        class Handler(DummyIQHandler):
807            called = False
808
809            def onGet(self, iq):
810                self.called = True
811
812        iq = domish.Element((None, 'iq'))
813        iq['type'] = 'get'
814        iq['id'] = 'r1'
815        handler = Handler()
816        handler.handleRequest(iq)
817        self.assertTrue(handler.called)
818
819    def test_noMatch(self):
820        """
821        Test that the matching handler gets called.
822        """
823
824        class Handler(DummyIQHandler):
825            called = False
826
827            def onGet(self, iq):
828                self.called = True
829
830        iq = domish.Element((None, 'iq'))
831        iq['type'] = 'set'
832        iq['id'] = 'r1'
833        handler = Handler()
834        handler.handleRequest(iq)
835        self.assertFalse(handler.called)
836
837    def test_success(self):
838        """
839        Test response when the request is handled successfully.
840        """
841
842        class Handler(DummyIQHandler):
843            def onGet(self, iq):
844                return None
845
846        iq = domish.Element((None, 'iq'))
847        iq['type'] = 'get'
848        iq['id'] = 'r1'
849        handler = Handler()
850        handler.handleRequest(iq)
851        response = handler.output[-1]
852        self.assertEquals(None, response.uri)
853        self.assertEquals('iq', response.name)
854        self.assertEquals('result', response['type'])
855
856    def test_successPayload(self):
857        """
858        Test response when the request is handled successfully with payload.
859        """
860
861        class Handler(DummyIQHandler):
862            payload = domish.Element(('testns', 'foo'))
863
864            def onGet(self, iq):
865                return self.payload
866
867        iq = domish.Element((None, 'iq'))
868        iq['type'] = 'get'
869        iq['id'] = 'r1'
870        handler = Handler()
871        handler.handleRequest(iq)
872        response = handler.output[-1]
873        self.assertEquals(None, response.uri)
874        self.assertEquals('iq', response.name)
875        self.assertEquals('result', response['type'])
876        payload = response.elements().next()
877        self.assertEqual(handler.payload, payload)
878
879    def test_successDeferred(self):
880        """
881        Test response when where the handler was a deferred.
882        """
883
884        class Handler(DummyIQHandler):
885            def onGet(self, iq):
886                return defer.succeed(None)
887
888        iq = domish.Element((None, 'iq'))
889        iq['type'] = 'get'
890        iq['id'] = 'r1'
891        handler = Handler()
892        handler.handleRequest(iq)
893        response = handler.output[-1]
894        self.assertEquals(None, response.uri)
895        self.assertEquals('iq', response.name)
896        self.assertEquals('result', response['type'])
897
898    def test_failure(self):
899        """
900        Test response when the request is handled unsuccessfully.
901        """
902
903        class Handler(DummyIQHandler):
904            def onGet(self, iq):
905                raise error.StanzaError('forbidden')
906
907        iq = domish.Element((None, 'iq'))
908        iq['type'] = 'get'
909        iq['id'] = 'r1'
910        handler = Handler()
911        handler.handleRequest(iq)
912        response = handler.output[-1]
913        self.assertEquals(None, response.uri)
914        self.assertEquals('iq', response.name)
915        self.assertEquals('error', response['type'])
916        e = error.exceptionFromStanza(response)
917        self.assertEquals('forbidden', e.condition)
918
919    def test_failureUnknown(self):
920        """
921        Test response when the request handler raises a non-stanza-error.
922        """
923
924        class TestError(Exception):
925            pass
926
927        class Handler(DummyIQHandler):
928            def onGet(self, iq):
929                raise TestError()
930
931        iq = domish.Element((None, 'iq'))
932        iq['type'] = 'get'
933        iq['id'] = 'r1'
934        handler = Handler()
935        handler.handleRequest(iq)
936        response = handler.output[-1]
937        self.assertEquals(None, response.uri)
938        self.assertEquals('iq', response.name)
939        self.assertEquals('error', response['type'])
940        e = error.exceptionFromStanza(response)
941        self.assertEquals('internal-server-error', e.condition)
942        self.assertEquals(1, len(self.flushLoggedErrors(TestError)))
943
944    def test_notImplemented(self):
945        """
946        Test response when the request is recognised but not implemented.
947        """
948
949        class Handler(DummyIQHandler):
950            def onGet(self, iq):
951                raise NotImplementedError()
952
953        iq = domish.Element((None, 'iq'))
954        iq['type'] = 'get'
955        iq['id'] = 'r1'
956        handler = Handler()
957        handler.handleRequest(iq)
958        response = handler.output[-1]
959        self.assertEquals(None, response.uri)
960        self.assertEquals('iq', response.name)
961        self.assertEquals('error', response['type'])
962        e = error.exceptionFromStanza(response)
963        self.assertEquals('feature-not-implemented', e.condition)
964
965    def test_noHandler(self):
966        """
967        Test when the request is not recognised.
968        """
969
970        iq = domish.Element((None, 'iq'))
971        iq['type'] = 'set'
972        iq['id'] = 'r1'
973        handler = DummyIQHandler()
974        handler.handleRequest(iq)
975        response = handler.output[-1]
976        self.assertEquals(None, response.uri)
977        self.assertEquals('iq', response.name)
978        self.assertEquals('error', response['type'])
979        e = error.exceptionFromStanza(response)
980        self.assertEquals('feature-not-implemented', e.condition)
Note: See TracBrowser for help on using the repository browser.