source: wokkel/test/test_subprotocols.py @ 96:8e6130587088

Last change on this file since 96:8e6130587088 was 96:8e6130587088, checked in by Ralph Meijer <ralphm@…>, 9 years ago

Remove copyright dates from individual source files, only update LICENSE.

  • Property exe set to *
File size: 17.6 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
13from twisted.words.xish import domish
14from twisted.words.protocols.jabber import error, xmlstream
15
16from wokkel import iwokkel, subprotocols
17
18class DummyFactory(object):
19    """
20    Dummy XmlStream factory that only registers bootstrap observers.
21    """
22    def __init__(self):
23        self.callbacks = {}
24
25
26    def addBootstrap(self, event, callback):
27        self.callbacks[event] = callback
28
29
30
31class DummyXMPPHandler(subprotocols.XMPPHandler):
32    """
33    Dummy XMPP subprotocol handler to count the methods are called on it.
34    """
35    def __init__(self):
36        self.doneMade = 0
37        self.doneInitialized = 0
38        self.doneLost = 0
39
40
41    def makeConnection(self, xs):
42        self.connectionMade()
43
44
45    def connectionMade(self):
46        self.doneMade += 1
47
48
49    def connectionInitialized(self):
50        self.doneInitialized += 1
51
52
53    def connectionLost(self, reason):
54        self.doneLost += 1
55
56
57
58class XMPPHandlerTest(unittest.TestCase):
59    """
60    Tests for L{subprotocols.XMPPHandler}.
61    """
62
63    def test_interface(self):
64        """
65        L{xmlstream.XMPPHandler} implements L{iwokkel.IXMPPHandler}.
66        """
67        verifyObject(iwokkel.IXMPPHandler, subprotocols.XMPPHandler())
68
69
70    def test_send(self):
71        """
72        Test that data is passed on for sending by the stream manager.
73        """
74        class DummyStreamManager(object):
75            def __init__(self):
76                self.outlist = []
77
78            def send(self, data):
79                self.outlist.append(data)
80
81        handler = subprotocols.XMPPHandler()
82        handler.parent = DummyStreamManager()
83        handler.send('<presence/>')
84        self.assertEquals(['<presence/>'], handler.parent.outlist)
85
86
87    def test_makeConnection(self):
88        """
89        Test that makeConnection saves the XML stream and calls connectionMade.
90        """
91        class TestXMPPHandler(subprotocols.XMPPHandler):
92            def connectionMade(self):
93                self.doneMade = True
94
95        handler = TestXMPPHandler()
96        xs = xmlstream.XmlStream(xmlstream.Authenticator())
97        handler.makeConnection(xs)
98        self.assertTrue(handler.doneMade)
99        self.assertIdentical(xs, handler.xmlstream)
100
101
102    def test_connectionLost(self):
103        """
104        Test that connectionLost forgets the XML stream.
105        """
106        handler = subprotocols.XMPPHandler()
107        xs = xmlstream.XmlStream(xmlstream.Authenticator())
108        handler.makeConnection(xs)
109        handler.connectionLost(Exception())
110        self.assertIdentical(None, handler.xmlstream)
111
112
113
114class XMPPHandlerCollectionTest(unittest.TestCase):
115    """
116    Tests for L{subprotocols.XMPPHandlerCollection}.
117    """
118
119    def setUp(self):
120        self.collection = subprotocols.XMPPHandlerCollection()
121
122
123    def test_interface(self):
124        """
125        L{subprotocols.StreamManager} implements L{iwokkel.IXMPPHandlerCollection}.
126        """
127        verifyObject(iwokkel.IXMPPHandlerCollection, self.collection)
128
129
130    def test_addHandler(self):
131        """
132        Test the addition of a protocol handler.
133        """
134        handler = DummyXMPPHandler()
135        handler.setHandlerParent(self.collection)
136        self.assertIn(handler, self.collection)
137        self.assertIdentical(self.collection, handler.parent)
138
139
140    def test_removeHandler(self):
141        """
142        Test removal of a protocol handler.
143        """
144        handler = DummyXMPPHandler()
145        handler.setHandlerParent(self.collection)
146        handler.disownHandlerParent(self.collection)
147        self.assertNotIn(handler, self.collection)
148        self.assertIdentical(None, handler.parent)
149
150
151
152class StreamManagerTest(unittest.TestCase):
153    """
154    Tests for L{subprotocols.StreamManager}.
155    """
156
157    def setUp(self):
158        factory = DummyFactory()
159        self.streamManager = subprotocols.StreamManager(factory)
160
161    def test_basic(self):
162        """
163        Test correct initialization and setup of factory observers.
164        """
165        sm = self.streamManager
166        self.assertIdentical(None, sm.xmlstream)
167        self.assertEquals([], sm.handlers)
168        self.assertEquals(sm._connected,
169                          sm.factory.callbacks['//event/stream/connected'])
170        self.assertEquals(sm._authd,
171                          sm.factory.callbacks['//event/stream/authd'])
172        self.assertEquals(sm._disconnected,
173                          sm.factory.callbacks['//event/stream/end'])
174        self.assertEquals(sm.initializationFailed,
175                          sm.factory.callbacks['//event/xmpp/initfailed'])
176
177
178    def test_connected(self):
179        """
180        Test that protocol handlers have their connectionMade method called
181        when the XML stream is connected.
182        """
183        sm = self.streamManager
184        handler = DummyXMPPHandler()
185        handler.setHandlerParent(sm)
186        xs = xmlstream.XmlStream(xmlstream.Authenticator())
187        sm._connected(xs)
188        self.assertEquals(1, handler.doneMade)
189        self.assertEquals(0, handler.doneInitialized)
190        self.assertEquals(0, handler.doneLost)
191
192
193    def test_connectedLogTrafficFalse(self):
194        """
195        Test raw data functions unset when logTraffic is set to False.
196        """
197        sm = self.streamManager
198        handler = DummyXMPPHandler()
199        handler.setHandlerParent(sm)
200        xs = xmlstream.XmlStream(xmlstream.Authenticator())
201        sm._connected(xs)
202        self.assertIdentical(None, xs.rawDataInFn)
203        self.assertIdentical(None, xs.rawDataOutFn)
204
205
206    def test_connectedLogTrafficTrue(self):
207        """
208        Test raw data functions set when logTraffic is set to True.
209        """
210        sm = self.streamManager
211        sm.logTraffic = True
212        handler = DummyXMPPHandler()
213        handler.setHandlerParent(sm)
214        xs = xmlstream.XmlStream(xmlstream.Authenticator())
215        sm._connected(xs)
216        self.assertNotIdentical(None, xs.rawDataInFn)
217        self.assertNotIdentical(None, xs.rawDataOutFn)
218
219
220    def test_authd(self):
221        """
222        Test that protocol handlers have their connectionInitialized method
223        called when the XML stream is initialized.
224        """
225        sm = self.streamManager
226        handler = DummyXMPPHandler()
227        handler.setHandlerParent(sm)
228        xs = xmlstream.XmlStream(xmlstream.Authenticator())
229        sm._authd(xs)
230        self.assertEquals(0, handler.doneMade)
231        self.assertEquals(1, handler.doneInitialized)
232        self.assertEquals(0, handler.doneLost)
233
234
235    def test_disconnected(self):
236        """
237        Test that protocol handlers have their connectionLost method
238        called when the XML stream is disconnected.
239        """
240        sm = self.streamManager
241        handler = DummyXMPPHandler()
242        handler.setHandlerParent(sm)
243        xs = xmlstream.XmlStream(xmlstream.Authenticator())
244        sm._disconnected(xs)
245        self.assertEquals(0, handler.doneMade)
246        self.assertEquals(0, handler.doneInitialized)
247        self.assertEquals(1, handler.doneLost)
248
249
250    def test_addHandler(self):
251        """
252        Test the addition of a protocol handler while not connected.
253        """
254        sm = self.streamManager
255        handler = DummyXMPPHandler()
256        handler.setHandlerParent(sm)
257
258        self.assertEquals(0, handler.doneMade)
259        self.assertEquals(0, handler.doneInitialized)
260        self.assertEquals(0, handler.doneLost)
261
262
263    def test_addHandlerInitialized(self):
264        """
265        Test the addition of a protocol handler after the stream
266        have been initialized.
267
268        Make sure that the handler will have the connected stream
269        passed via C{makeConnection} and have C{connectionInitialized}
270        called.
271        """
272        sm = self.streamManager
273        xs = xmlstream.XmlStream(xmlstream.Authenticator())
274        sm._connected(xs)
275        sm._authd(xs)
276        handler = DummyXMPPHandler()
277        handler.setHandlerParent(sm)
278
279        self.assertEquals(1, handler.doneMade)
280        self.assertEquals(1, handler.doneInitialized)
281        self.assertEquals(0, handler.doneLost)
282
283    def test_removeHandler(self):
284        """
285        Test removal of protocol handler.
286        """
287        sm = self.streamManager
288        handler = DummyXMPPHandler()
289        handler.setHandlerParent(sm)
290        handler.disownHandlerParent(sm)
291        self.assertNotIn(handler, sm)
292        self.assertIdentical(None, handler.parent)
293
294    def test_sendInitialized(self):
295        """
296        Test send when the stream has been initialized.
297
298        The data should be sent directly over the XML stream.
299        """
300        factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator())
301        sm = subprotocols.StreamManager(factory)
302        xs = factory.buildProtocol(None)
303        xs.transport = proto_helpers.StringTransport()
304        xs.connectionMade()
305        xs.dataReceived("<stream:stream xmlns='jabber:client' "
306                        "xmlns:stream='http://etherx.jabber.org/streams' "
307                        "from='example.com' id='12345'>")
308        xs.dispatch(xs, "//event/stream/authd")
309        sm.send("<presence/>")
310        self.assertEquals("<presence/>", xs.transport.value())
311
312
313    def test_sendNotConnected(self):
314        """
315        Test send when there is no established XML stream.
316
317        The data should be cached until an XML stream has been established and
318        initialized.
319        """
320        factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator())
321        sm = subprotocols.StreamManager(factory)
322        handler = DummyXMPPHandler()
323        sm.addHandler(handler)
324
325        xs = factory.buildProtocol(None)
326        xs.transport = proto_helpers.StringTransport()
327        sm.send("<presence/>")
328        self.assertEquals("", xs.transport.value())
329        self.assertEquals("<presence/>", sm._packetQueue[0])
330
331        xs.connectionMade()
332        self.assertEquals("", xs.transport.value())
333        self.assertEquals("<presence/>", sm._packetQueue[0])
334
335        xs.dataReceived("<stream:stream xmlns='jabber:client' "
336                        "xmlns:stream='http://etherx.jabber.org/streams' "
337                        "from='example.com' id='12345'>")
338        xs.dispatch(xs, "//event/stream/authd")
339
340        self.assertEquals("<presence/>", xs.transport.value())
341        self.assertFalse(sm._packetQueue)
342
343
344    def test_sendNotInitialized(self):
345        """
346        Test send when the stream is connected but not yet initialized.
347
348        The data should be cached until the XML stream has been initialized.
349        """
350        factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator())
351        sm = subprotocols.StreamManager(factory)
352        xs = factory.buildProtocol(None)
353        xs.transport = proto_helpers.StringTransport()
354        xs.connectionMade()
355        xs.dataReceived("<stream:stream xmlns='jabber:client' "
356                        "xmlns:stream='http://etherx.jabber.org/streams' "
357                        "from='example.com' id='12345'>")
358        sm.send("<presence/>")
359        self.assertEquals("", xs.transport.value())
360        self.assertEquals("<presence/>", sm._packetQueue[0])
361
362
363    def test_sendDisconnected(self):
364        """
365        Test send after XML stream disconnection.
366
367        The data should be cached until a new XML stream has been established
368        and initialized.
369        """
370        factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator())
371        sm = subprotocols.StreamManager(factory)
372        handler = DummyXMPPHandler()
373        sm.addHandler(handler)
374
375        xs = factory.buildProtocol(None)
376        xs.connectionMade()
377        xs.transport = proto_helpers.StringTransport()
378        xs.connectionLost(None)
379
380        sm.send("<presence/>")
381        self.assertEquals("", xs.transport.value())
382        self.assertEquals("<presence/>", sm._packetQueue[0])
383
384
385
386class DummyIQHandler(subprotocols.IQHandlerMixin):
387    iqHandlers = {'/iq[@type="get"]': 'onGet'}
388
389    def __init__(self):
390        self.output = []
391        self.xmlstream = xmlstream.XmlStream(xmlstream.Authenticator())
392        self.xmlstream.send = self.output.append
393
394    def send(self, obj):
395        self.xmlstream.send(obj)
396
397
398class IQHandlerTest(unittest.TestCase):
399
400    def test_match(self):
401        """
402        Test that the matching handler gets called.
403        """
404
405        class Handler(DummyIQHandler):
406            called = False
407
408            def onGet(self, iq):
409                self.called = True
410
411        iq = domish.Element((None, 'iq'))
412        iq['type'] = 'get'
413        iq['id'] = 'r1'
414        handler = Handler()
415        handler.handleRequest(iq)
416        self.assertTrue(handler.called)
417
418    def test_noMatch(self):
419        """
420        Test that the matching handler gets called.
421        """
422
423        class Handler(DummyIQHandler):
424            called = False
425
426            def onGet(self, iq):
427                self.called = True
428
429        iq = domish.Element((None, 'iq'))
430        iq['type'] = 'set'
431        iq['id'] = 'r1'
432        handler = Handler()
433        handler.handleRequest(iq)
434        self.assertFalse(handler.called)
435
436    def test_success(self):
437        """
438        Test response when the request is handled successfully.
439        """
440
441        class Handler(DummyIQHandler):
442            def onGet(self, iq):
443                return None
444
445        iq = domish.Element((None, 'iq'))
446        iq['type'] = 'get'
447        iq['id'] = 'r1'
448        handler = Handler()
449        handler.handleRequest(iq)
450        response = handler.output[-1]
451        self.assertEquals(None, response.uri)
452        self.assertEquals('iq', response.name)
453        self.assertEquals('result', response['type'])
454
455    def test_successPayload(self):
456        """
457        Test response when the request is handled successfully with payload.
458        """
459
460        class Handler(DummyIQHandler):
461            payload = domish.Element(('testns', 'foo'))
462
463            def onGet(self, iq):
464                return self.payload
465
466        iq = domish.Element((None, 'iq'))
467        iq['type'] = 'get'
468        iq['id'] = 'r1'
469        handler = Handler()
470        handler.handleRequest(iq)
471        response = handler.output[-1]
472        self.assertEquals(None, response.uri)
473        self.assertEquals('iq', response.name)
474        self.assertEquals('result', response['type'])
475        payload = response.elements().next()
476        self.assertEqual(handler.payload, payload)
477
478    def test_successDeferred(self):
479        """
480        Test response when where the handler was a deferred.
481        """
482
483        class Handler(DummyIQHandler):
484            def onGet(self, iq):
485                return defer.succeed(None)
486
487        iq = domish.Element((None, 'iq'))
488        iq['type'] = 'get'
489        iq['id'] = 'r1'
490        handler = Handler()
491        handler.handleRequest(iq)
492        response = handler.output[-1]
493        self.assertEquals(None, response.uri)
494        self.assertEquals('iq', response.name)
495        self.assertEquals('result', response['type'])
496
497    def test_failure(self):
498        """
499        Test response when the request is handled unsuccessfully.
500        """
501
502        class Handler(DummyIQHandler):
503            def onGet(self, iq):
504                raise error.StanzaError('forbidden')
505
506        iq = domish.Element((None, 'iq'))
507        iq['type'] = 'get'
508        iq['id'] = 'r1'
509        handler = Handler()
510        handler.handleRequest(iq)
511        response = handler.output[-1]
512        self.assertEquals(None, response.uri)
513        self.assertEquals('iq', response.name)
514        self.assertEquals('error', response['type'])
515        e = error.exceptionFromStanza(response)
516        self.assertEquals('forbidden', e.condition)
517
518    def test_failureUnknown(self):
519        """
520        Test response when the request handler raises a non-stanza-error.
521        """
522
523        class TestError(Exception):
524            pass
525
526        class Handler(DummyIQHandler):
527            def onGet(self, iq):
528                raise TestError()
529
530        iq = domish.Element((None, 'iq'))
531        iq['type'] = 'get'
532        iq['id'] = 'r1'
533        handler = Handler()
534        handler.handleRequest(iq)
535        response = handler.output[-1]
536        self.assertEquals(None, response.uri)
537        self.assertEquals('iq', response.name)
538        self.assertEquals('error', response['type'])
539        e = error.exceptionFromStanza(response)
540        self.assertEquals('internal-server-error', e.condition)
541        self.assertEquals(1, len(self.flushLoggedErrors(TestError)))
542
543    def test_notImplemented(self):
544        """
545        Test response when the request is recognised but not implemented.
546        """
547
548        class Handler(DummyIQHandler):
549            def onGet(self, iq):
550                raise NotImplementedError()
551
552        iq = domish.Element((None, 'iq'))
553        iq['type'] = 'get'
554        iq['id'] = 'r1'
555        handler = Handler()
556        handler.handleRequest(iq)
557        response = handler.output[-1]
558        self.assertEquals(None, response.uri)
559        self.assertEquals('iq', response.name)
560        self.assertEquals('error', response['type'])
561        e = error.exceptionFromStanza(response)
562        self.assertEquals('feature-not-implemented', e.condition)
563
564    def test_noHandler(self):
565        """
566        Test when the request is not recognised.
567        """
568
569        iq = domish.Element((None, 'iq'))
570        iq['type'] = 'set'
571        iq['id'] = 'r1'
572        handler = DummyIQHandler()
573        handler.handleRequest(iq)
574        response = handler.output[-1]
575        self.assertEquals(None, response.uri)
576        self.assertEquals('iq', response.name)
577        self.assertEquals('error', response['type'])
578        e = error.exceptionFromStanza(response)
579        self.assertEquals('feature-not-implemented', e.condition)
Note: See TracBrowser for help on using the repository browser.