source: wokkel/test/test_pubsub.py @ 24:ada867483400

Last change on this file since 24:ada867483400 was 24:ada867483400, checked in by Ralph Meijer <ralphm@…>, 14 years ago

PubSubService?.items should return a list of Elements representing items.

File size: 19.4 KB
Line 
1# Copyright (c) 2003-2008 Ralph Meijer
2# See LICENSE for details.
3
4"""
5Tests for L{wokkel.pubsub}
6"""
7from zope.interface import verify
8
9from twisted.trial import unittest
10from twisted.internet import defer
11from twisted.words.xish import domish, xpath
12from twisted.words.protocols.jabber import error
13from twisted.words.protocols.jabber.jid import JID
14
15from wokkel import iwokkel, pubsub
16from wokkel.generic import parseXml
17from wokkel.test.helpers import XmlStreamStub
18
19try:
20    from twisted.words.protocols.jabber.xmlstream import toResponse
21except ImportError:
22    from wokkel.compat import toResponse
23
24NS_PUBSUB = 'http://jabber.org/protocol/pubsub'
25NS_PUBSUB_ERRORS = 'http://jabber.org/protocol/pubsub#errors'
26NS_PUBSUB_EVENT = 'http://jabber.org/protocol/pubsub#event'
27
28def calledAsync(fn):
29    """
30    Function wrapper that fires a deferred upon calling the given function.
31    """
32    d = defer.Deferred()
33
34    def func(*args, **kwargs):
35        try:
36            result = fn(*args, **kwargs)
37        except:
38            d.errback()
39        else:
40            d.callback(result)
41
42    return d, func
43
44
45class PubSubClientTest(unittest.TestCase):
46    timeout = 2
47
48    def setUp(self):
49        self.stub = XmlStreamStub()
50        self.protocol = pubsub.PubSubClient()
51        self.protocol.xmlstream = self.stub.xmlstream
52        self.protocol.connectionInitialized()
53
54
55    def test_interface(self):
56        """
57        Do instances of L{pubsub.PubSubClient} provide L{iwokkel.IPubSubClient}?
58        """
59        verify.verifyObject(iwokkel.IPubSubClient, self.protocol)
60
61
62    def test_eventItems(self):
63        """
64        Test receiving an items event resulting in a call to itemsReceived.
65        """
66        message = domish.Element((None, 'message'))
67        message['from'] = 'pubsub.example.org'
68        message['to'] = 'user@example.org/home'
69        event = message.addElement((NS_PUBSUB_EVENT, 'event'))
70        items = event.addElement('items')
71        items['node'] = 'test'
72        item1 = items.addElement('item')
73        item1['id'] = 'item1'
74        item2 = items.addElement('retract')
75        item2['id'] = 'item2'
76        item3 = items.addElement('item')
77        item3['id'] = 'item3'
78
79        def itemsReceived(recipient, service, nodeIdentifier, items):
80            self.assertEquals(JID('user@example.org/home'), recipient)
81            self.assertEquals(JID('pubsub.example.org'), service)
82            self.assertEquals('test', nodeIdentifier)
83            self.assertEquals([item1, item2, item3], items)
84
85        d, self.protocol.itemsReceived = calledAsync(itemsReceived)
86        self.stub.send(message)
87        return d
88
89
90    def test_event_delete(self):
91        """
92        Test receiving a delete event resulting in a call to deleteReceived.
93        """
94        message = domish.Element((None, 'message'))
95        message['from'] = 'pubsub.example.org'
96        message['to'] = 'user@example.org/home'
97        event = message.addElement((NS_PUBSUB_EVENT, 'event'))
98        items = event.addElement('delete')
99        items['node'] = 'test'
100
101        def deleteReceived(recipient, service, nodeIdentifier):
102            self.assertEquals(JID('user@example.org/home'), recipient)
103            self.assertEquals(JID('pubsub.example.org'), service)
104            self.assertEquals('test', nodeIdentifier)
105
106        d, self.protocol.deleteReceived = calledAsync(deleteReceived)
107        self.stub.send(message)
108        return d
109
110
111    def test_event_purge(self):
112        """
113        Test receiving a purge event resulting in a call to purgeReceived.
114        """
115        message = domish.Element((None, 'message'))
116        message['from'] = 'pubsub.example.org'
117        message['to'] = 'user@example.org/home'
118        event = message.addElement((NS_PUBSUB_EVENT, 'event'))
119        items = event.addElement('purge')
120        items['node'] = 'test'
121
122        def purgeReceived(recipient, service, nodeIdentifier):
123            self.assertEquals(JID('user@example.org/home'), recipient)
124            self.assertEquals(JID('pubsub.example.org'), service)
125            self.assertEquals('test', nodeIdentifier)
126
127        d, self.protocol.purgeReceived = calledAsync(purgeReceived)
128        self.stub.send(message)
129        return d
130
131
132    def test_createNode(self):
133        """
134        Test sending create request.
135        """
136
137        def cb(nodeIdentifier):
138            self.assertEquals('test', nodeIdentifier)
139
140        d = self.protocol.createNode(JID('pubsub.example.org'), 'test')
141        d.addCallback(cb)
142
143        iq = self.stub.output[-1]
144        self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
145        self.assertEquals('set', iq.getAttribute('type'))
146        self.assertEquals('pubsub', iq.pubsub.name)
147        self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
148        children = list(domish.generateElementsQNamed(iq.pubsub.children,
149                                                      'create', NS_PUBSUB))
150        self.assertEquals(1, len(children))
151        child = children[0]
152        self.assertEquals('test', child['node'])
153
154        response = toResponse(iq, 'result')
155        self.stub.send(response)
156        return d
157
158
159    def test_createNodeInstant(self):
160        """
161        Test sending create request resulting in an instant node.
162        """
163
164        def cb(nodeIdentifier):
165            self.assertEquals('test', nodeIdentifier)
166
167        d = self.protocol.createNode(JID('pubsub.example.org'))
168        d.addCallback(cb)
169
170        iq = self.stub.output[-1]
171        children = list(domish.generateElementsQNamed(iq.pubsub.children,
172                                                      'create', NS_PUBSUB))
173        child = children[0]
174        self.assertFalse(child.hasAttribute('node'))
175
176        response = toResponse(iq, 'result')
177        command = response.addElement((NS_PUBSUB, 'pubsub'))
178        create = command.addElement('create')
179        create['node'] = 'test'
180        self.stub.send(response)
181        return d
182
183
184    def test_createNodeRenamed(self):
185        """
186        Test sending create request resulting in renamed node.
187        """
188
189        def cb(nodeIdentifier):
190            self.assertEquals('test2', nodeIdentifier)
191
192        d = self.protocol.createNode(JID('pubsub.example.org'), 'test')
193        d.addCallback(cb)
194
195        iq = self.stub.output[-1]
196        children = list(domish.generateElementsQNamed(iq.pubsub.children,
197                                                      'create', NS_PUBSUB))
198        child = children[0]
199        self.assertEquals('test', child['node'])
200
201        response = toResponse(iq, 'result')
202        command = response.addElement((NS_PUBSUB, 'pubsub'))
203        create = command.addElement('create')
204        create['node'] = 'test2'
205        self.stub.send(response)
206        return d
207
208
209    def test_deleteNode(self):
210        """
211        Test sending delete request.
212        """
213
214        d = self.protocol.deleteNode(JID('pubsub.example.org'), 'test')
215
216        iq = self.stub.output[-1]
217        self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
218        self.assertEquals('set', iq.getAttribute('type'))
219        self.assertEquals('pubsub', iq.pubsub.name)
220        self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
221        children = list(domish.generateElementsQNamed(iq.pubsub.children,
222                                                      'delete', NS_PUBSUB))
223        self.assertEquals(1, len(children))
224        child = children[0]
225        self.assertEquals('test', child['node'])
226
227        response = toResponse(iq, 'result')
228        self.stub.send(response)
229        return d
230
231
232    def test_publish(self):
233        """
234        Test sending publish request.
235        """
236
237        item = pubsub.Item()
238        d = self.protocol.publish(JID('pubsub.example.org'), 'test', [item])
239
240        iq = self.stub.output[-1]
241        self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
242        self.assertEquals('set', iq.getAttribute('type'))
243        self.assertEquals('pubsub', iq.pubsub.name)
244        self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
245        children = list(domish.generateElementsQNamed(iq.pubsub.children,
246                                                      'publish', NS_PUBSUB))
247        self.assertEquals(1, len(children))
248        child = children[0]
249        self.assertEquals('test', child['node'])
250        items = list(domish.generateElementsQNamed(child.children,
251                                                   'item', NS_PUBSUB))
252        self.assertEquals(1, len(items))
253        self.assertIdentical(item, items[0])
254
255        response = toResponse(iq, 'result')
256        self.stub.send(response)
257        return d
258
259
260    def test_publishNoItems(self):
261        """
262        Test sending publish request without items.
263        """
264
265        d = self.protocol.publish(JID('pubsub.example.org'), 'test')
266
267        iq = self.stub.output[-1]
268        self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
269        self.assertEquals('set', iq.getAttribute('type'))
270        self.assertEquals('pubsub', iq.pubsub.name)
271        self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
272        children = list(domish.generateElementsQNamed(iq.pubsub.children,
273                                                      'publish', NS_PUBSUB))
274        self.assertEquals(1, len(children))
275        child = children[0]
276        self.assertEquals('test', child['node'])
277
278        response = toResponse(iq, 'result')
279        self.stub.send(response)
280        return d
281
282
283    def test_subscribe(self):
284        """
285        Test sending subscription request.
286        """
287        d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
288                                      JID('user@example.org'))
289
290        iq = self.stub.output[-1]
291        self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
292        self.assertEquals('set', iq.getAttribute('type'))
293        self.assertEquals('pubsub', iq.pubsub.name)
294        self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
295        children = list(domish.generateElementsQNamed(iq.pubsub.children,
296                                                      'subscribe', NS_PUBSUB))
297        self.assertEquals(1, len(children))
298        child = children[0]
299        self.assertEquals('test', child['node'])
300        self.assertEquals('user@example.org', child['jid'])
301
302        response = toResponse(iq, 'result')
303        pubsub = response.addElement((NS_PUBSUB, 'pubsub'))
304        subscription = pubsub.addElement('subscription')
305        subscription['node'] = 'test'
306        subscription['jid'] = 'user@example.org'
307        subscription['subscription'] = 'subscribed'
308        self.stub.send(response)
309        return d
310
311
312    def test_subscribePending(self):
313        """
314        Test sending subscription request that results in a pending
315        subscription.
316        """
317        d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
318                                      JID('user@example.org'))
319
320        iq = self.stub.output[-1]
321        response = toResponse(iq, 'result')
322        command = response.addElement((NS_PUBSUB, 'pubsub'))
323        subscription = command.addElement('subscription')
324        subscription['node'] = 'test'
325        subscription['jid'] = 'user@example.org'
326        subscription['subscription'] = 'pending'
327        self.stub.send(response)
328        self.assertFailure(d, pubsub.SubscriptionPending)
329        return d
330
331
332    def test_subscribeUnconfigured(self):
333        """
334        Test sending subscription request that results in an unconfigured
335        subscription.
336        """
337        d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
338                                      JID('user@example.org'))
339
340        iq = self.stub.output[-1]
341        response = toResponse(iq, 'result')
342        command = response.addElement((NS_PUBSUB, 'pubsub'))
343        subscription = command.addElement('subscription')
344        subscription['node'] = 'test'
345        subscription['jid'] = 'user@example.org'
346        subscription['subscription'] = 'unconfigured'
347        self.stub.send(response)
348        self.assertFailure(d, pubsub.SubscriptionUnconfigured)
349        return d
350
351
352    def test_unsubscribe(self):
353        """
354        Test sending unsubscription request.
355        """
356        d = self.protocol.unsubscribe(JID('pubsub.example.org'), 'test',
357                                      JID('user@example.org'))
358
359        iq = self.stub.output[-1]
360        self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
361        self.assertEquals('set', iq.getAttribute('type'))
362        self.assertEquals('pubsub', iq.pubsub.name)
363        self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
364        children = list(domish.generateElementsQNamed(iq.pubsub.children,
365                                                      'unsubscribe', NS_PUBSUB))
366        self.assertEquals(1, len(children))
367        child = children[0]
368        self.assertEquals('test', child['node'])
369        self.assertEquals('user@example.org', child['jid'])
370
371        self.stub.send(toResponse(iq, 'result'))
372        return d
373
374
375    def test_items(self):
376        """
377        Test sending items request.
378        """
379        def cb(items):
380            self.assertEquals([], items)
381
382        d = self.protocol.items(JID('pubsub.example.org'), 'test')
383        d.addCallback(cb)
384
385        iq = self.stub.output[-1]
386        self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
387        self.assertEquals('get', iq.getAttribute('type'))
388        self.assertEquals('pubsub', iq.pubsub.name)
389        self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
390        children = list(domish.generateElementsQNamed(iq.pubsub.children,
391                                                      'items', NS_PUBSUB))
392        self.assertEquals(1, len(children))
393        child = children[0]
394        self.assertEquals('test', child['node'])
395
396        response = toResponse(iq, 'result')
397        items = response.addElement((NS_PUBSUB, 'pubsub')).addElement('items')
398        items['node'] = 'test'
399
400        self.stub.send(response)
401
402        return d
403
404
405    def test_itemsMaxItems(self):
406        """
407        Test sending items request, with limit on the number of items.
408        """
409        def cb(items):
410            self.assertEquals(2, len(items))
411            self.assertEquals([item1, item2], items)
412
413        d = self.protocol.items(JID('pubsub.example.org'), 'test', maxItems=2)
414        d.addCallback(cb)
415
416        iq = self.stub.output[-1]
417        self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
418        self.assertEquals('get', iq.getAttribute('type'))
419        self.assertEquals('pubsub', iq.pubsub.name)
420        self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
421        children = list(domish.generateElementsQNamed(iq.pubsub.children,
422                                                      'items', NS_PUBSUB))
423        self.assertEquals(1, len(children))
424        child = children[0]
425        self.assertEquals('test', child['node'])
426        self.assertEquals('2', child['max_items'])
427
428        response = toResponse(iq, 'result')
429        items = response.addElement((NS_PUBSUB, 'pubsub')).addElement('items')
430        items['node'] = 'test'
431        item1 = items.addElement('item')
432        item1['id'] = 'item1'
433        item2 = items.addElement('item')
434        item2['id'] = 'item2'
435
436        self.stub.send(response)
437
438        return d
439
440
441
442class PubSubServiceTest(unittest.TestCase):
443    """
444    Tests for L{pubsub.PubSubService}.
445    """
446
447    def handleRequest(self, handler, iq):
448        """
449        Find a handler and call it directly
450        """
451        for queryString, method in handler.iqHandlers.iteritems():
452            if xpath.internQuery(queryString).matches(iq):
453                handler = getattr(handler, method)
454
455        if handler:
456            d = defer.maybeDeferred(handler, iq)
457        else:
458            d = defer.fail(NotImplementedError())
459
460        return d
461
462
463    def test_interface(self):
464        """
465        Do instances of L{pubsub.PubSubService} provide L{iwokkel.IPubSubService}?
466        """
467        verify.verifyObject(iwokkel.IPubSubService, pubsub.PubSubService())
468
469
470    def test_onPublishNoNode(self):
471        """
472        The root node is always a collection, publishing is a bad request.
473        """
474        xml = """
475        <iq type='set' to='pubsub.example.org'
476                       from='user@example.org'>
477          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
478            <publish/>
479          </pubsub>
480        </iq>
481        """
482
483        def cb(result):
484            self.assertEquals('bad-request', result.condition)
485
486        handler = pubsub.PubSubService()
487        d = self.handleRequest(handler, parseXml(xml))
488        self.assertFailure(d, error.StanzaError)
489        d.addCallback(cb)
490        return d
491
492    def test_onPublish(self):
493        """
494        A publish request should result in L{PubSubService.publish} being
495        called.
496        """
497        class Handler(pubsub.PubSubService):
498            def publish(self, requestor, service, nodeIdentifier, items):
499                return defer.succeed((requestor, service,nodeIdentifier,
500                                      items))
501
502        xml = """
503        <iq type='set' to='pubsub.example.org'
504                       from='user@example.org'>
505          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
506            <publish node='test'/>
507          </pubsub>
508        </iq>
509        """
510
511        def cb(result):
512            self.assertEqual((JID('user@example.org'),
513                              JID('pubsub.example.org'),'test', []), result)
514
515        handler = Handler()
516        d = self.handleRequest(handler, parseXml(xml))
517        d.addCallback(cb)
518        return d
519
520
521    def test_onOptionsGet(self):
522        """
523        Subscription options are not supported.
524        """
525
526        handler = pubsub.PubSubService()
527        xml = """
528        <iq type='get' to='pubsub.example.org'
529                       from='user@example.org'>
530          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
531            <options/>
532          </pubsub>
533        </iq>
534        """
535
536        def cb(result):
537            self.assertEquals('feature-not-implemented', result.condition)
538            self.assertEquals('unsupported', result.appCondition.name)
539            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
540
541        handler = pubsub.PubSubService()
542        d = self.handleRequest(handler, parseXml(xml))
543        self.assertFailure(d, error.StanzaError)
544        d.addCallback(cb)
545        return d
546
547
548    def test_onItems(self):
549        """
550        On a items request, return all items for the given node.
551        """
552        class Handler(pubsub.PubSubService):
553            def items(self, *args, **kwargs):
554                self.args = args
555                self.kwargs = kwargs
556                return defer.succeed([pubsub.Item('current')])
557
558        xml = """
559        <iq type='get' to='pubsub.example.org'
560                       from='user@example.org'>
561          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
562            <items node='test'/>
563          </pubsub>
564        </iq>
565        """
566
567        def cb(element):
568            self.assertEqual((JID('user@example.org'),
569                              JID('pubsub.example.org'), 'test', None, []),
570                             handler.args)
571
572            self.assertEqual(NS_PUBSUB, element.uri)
573            self.assertEqual(NS_PUBSUB, element.items.uri)
574            self.assertEqual(1, len(element.items.children))
575            item = element.items.children[-1]
576            self.assertTrue(domish.IElement.providedBy(item))
577            self.assertEqual('item', item.name)
578            self.assertEqual(NS_PUBSUB, item.uri)
579            self.assertEqual('current', item['id'])
580
581        handler = Handler()
582        d = self.handleRequest(handler, parseXml(xml))
583        d.addCallback(cb)
584        return d
Note: See TracBrowser for help on using the repository browser.