source: wokkel/test/test_pubsub.py @ 87:c9d1bf0b783d

Last change on this file since 87:c9d1bf0b783d was 87:c9d1bf0b783d, checked in by Ralph Meijer <ralphm@…>, 11 years ago

Correctly report disco identity for PubSubService? without PubSubResource?.

Author: ralphm.
Fixes #64.

File size: 128.1 KB
Line 
1# Copyright (c) 2003-2010 Ralph Meijer
2# See LICENSE for details.
3
4"""
5Tests for L{wokkel.pubsub}
6"""
7
8from zope.interface import verify
9
10from twisted.trial import unittest
11from twisted.internet import defer
12from twisted.words.xish import domish
13from twisted.words.protocols.jabber import error
14from twisted.words.protocols.jabber.jid import JID
15from twisted.words.protocols.jabber.xmlstream import toResponse
16
17from wokkel import data_form, disco, iwokkel, pubsub, shim
18from wokkel.generic import parseXml
19from wokkel.test.helpers import TestableRequestHandlerMixin, XmlStreamStub
20
21NS_PUBSUB = 'http://jabber.org/protocol/pubsub'
22NS_PUBSUB_NODE_CONFIG = 'http://jabber.org/protocol/pubsub#node_config'
23NS_PUBSUB_ERRORS = 'http://jabber.org/protocol/pubsub#errors'
24NS_PUBSUB_EVENT = 'http://jabber.org/protocol/pubsub#event'
25NS_PUBSUB_OWNER = 'http://jabber.org/protocol/pubsub#owner'
26NS_PUBSUB_META_DATA = 'http://jabber.org/protocol/pubsub#meta-data'
27NS_PUBSUB_SUBSCRIBE_OPTIONS = 'http://jabber.org/protocol/pubsub#subscribe_options'
28
29def calledAsync(fn):
30    """
31    Function wrapper that fires a deferred upon calling the given function.
32    """
33    d = defer.Deferred()
34
35    def func(*args, **kwargs):
36        try:
37            result = fn(*args, **kwargs)
38        except:
39            d.errback()
40        else:
41            d.callback(result)
42
43    return d, func
44
45
46class SubscriptionTest(unittest.TestCase):
47    """
48    Tests for L{pubsub.Subscription}.
49    """
50
51    def test_fromElement(self):
52        """
53        fromElement parses a subscription from XML DOM.
54        """
55        xml = """
56        <subscription node='test' jid='user@example.org/Home'
57                      subscription='pending'/>
58        """
59        subscription = pubsub.Subscription.fromElement(parseXml(xml))
60        self.assertEqual('test', subscription.nodeIdentifier)
61        self.assertEqual(JID('user@example.org/Home'), subscription.subscriber)
62        self.assertEqual('pending', subscription.state)
63        self.assertIdentical(None, subscription.subscriptionIdentifier)
64
65
66    def test_fromElementWithSubscriptionIdentifier(self):
67        """
68        A subscription identifier in the subscription should be parsed, too.
69        """
70        xml = """
71        <subscription node='test' jid='user@example.org/Home' subid='1234'
72                      subscription='pending'/>
73        """
74        subscription = pubsub.Subscription.fromElement(parseXml(xml))
75        self.assertEqual('1234', subscription.subscriptionIdentifier)
76
77
78    def test_toElement(self):
79        """
80        Rendering a Subscription should yield the proper attributes.
81        """
82        subscription = pubsub.Subscription('test',
83                                           JID('user@example.org/Home'),
84                                           'pending')
85        element = subscription.toElement()
86        self.assertEqual('subscription', element.name)
87        self.assertEqual(None, element.uri)
88        self.assertEqual('test', element.getAttribute('node'))
89        self.assertEqual('user@example.org/Home', element.getAttribute('jid'))
90        self.assertEqual('pending', element.getAttribute('subscription'))
91        self.assertFalse(element.hasAttribute('subid'))
92
93
94    def test_toElementEmptyNodeIdentifier(self):
95        """
96        The empty node identifier should not yield a node attribute.
97        """
98        subscription = pubsub.Subscription('',
99                                           JID('user@example.org/Home'),
100                                           'pending')
101        element = subscription.toElement()
102        self.assertFalse(element.hasAttribute('node'))
103
104
105    def test_toElementWithSubscriptionIdentifier(self):
106        """
107        The subscription identifier, if set, is in the subid attribute.
108        """
109        subscription = pubsub.Subscription('test',
110                                           JID('user@example.org/Home'),
111                                           'pending',
112                                           subscriptionIdentifier='1234')
113        element = subscription.toElement()
114        self.assertEqual('1234', element.getAttribute('subid'))
115
116
117
118class PubSubClientTest(unittest.TestCase):
119    timeout = 2
120
121    def setUp(self):
122        self.stub = XmlStreamStub()
123        self.protocol = pubsub.PubSubClient()
124        self.protocol.xmlstream = self.stub.xmlstream
125        self.protocol.connectionInitialized()
126
127
128    def test_interface(self):
129        """
130        Do instances of L{pubsub.PubSubClient} provide L{iwokkel.IPubSubClient}?
131        """
132        verify.verifyObject(iwokkel.IPubSubClient, self.protocol)
133
134
135    def test_eventItems(self):
136        """
137        Test receiving an items event resulting in a call to itemsReceived.
138        """
139        message = domish.Element((None, 'message'))
140        message['from'] = 'pubsub.example.org'
141        message['to'] = 'user@example.org/home'
142        event = message.addElement((NS_PUBSUB_EVENT, 'event'))
143        items = event.addElement('items')
144        items['node'] = 'test'
145        item1 = items.addElement('item')
146        item1['id'] = 'item1'
147        item2 = items.addElement('retract')
148        item2['id'] = 'item2'
149        item3 = items.addElement('item')
150        item3['id'] = 'item3'
151
152        def itemsReceived(event):
153            self.assertEquals(JID('user@example.org/home'), event.recipient)
154            self.assertEquals(JID('pubsub.example.org'), event.sender)
155            self.assertEquals('test', event.nodeIdentifier)
156            self.assertEquals([item1, item2, item3], event.items)
157
158        d, self.protocol.itemsReceived = calledAsync(itemsReceived)
159        self.stub.send(message)
160        return d
161
162
163    def test_eventItemsCollection(self):
164        """
165        Test receiving an items event resulting in a call to itemsReceived.
166        """
167        message = domish.Element((None, 'message'))
168        message['from'] = 'pubsub.example.org'
169        message['to'] = 'user@example.org/home'
170        event = message.addElement((NS_PUBSUB_EVENT, 'event'))
171        items = event.addElement('items')
172        items['node'] = 'test'
173
174        headers = shim.Headers([('Collection', 'collection')])
175        message.addChild(headers)
176
177        def itemsReceived(event):
178            self.assertEquals(JID('user@example.org/home'), event.recipient)
179            self.assertEquals(JID('pubsub.example.org'), event.sender)
180            self.assertEquals('test', event.nodeIdentifier)
181            self.assertEquals({'Collection': ['collection']}, event.headers)
182
183        d, self.protocol.itemsReceived = calledAsync(itemsReceived)
184        self.stub.send(message)
185        return d
186
187
188    def test_eventDelete(self):
189        """
190        Test receiving a delete event resulting in a call to deleteReceived.
191        """
192        message = domish.Element((None, 'message'))
193        message['from'] = 'pubsub.example.org'
194        message['to'] = 'user@example.org/home'
195        event = message.addElement((NS_PUBSUB_EVENT, 'event'))
196        delete = event.addElement('delete')
197        delete['node'] = 'test'
198
199        def deleteReceived(event):
200            self.assertEquals(JID('user@example.org/home'), event.recipient)
201            self.assertEquals(JID('pubsub.example.org'), event.sender)
202            self.assertEquals('test', event.nodeIdentifier)
203
204        d, self.protocol.deleteReceived = calledAsync(deleteReceived)
205        self.stub.send(message)
206        return d
207
208
209    def test_eventDeleteRedirect(self):
210        """
211        Test receiving a delete event with a redirect URI.
212        """
213        message = domish.Element((None, 'message'))
214        message['from'] = 'pubsub.example.org'
215        message['to'] = 'user@example.org/home'
216        event = message.addElement((NS_PUBSUB_EVENT, 'event'))
217        delete = event.addElement('delete')
218        delete['node'] = 'test'
219        uri = 'xmpp:pubsub.example.org?;node=test2'
220        delete.addElement('redirect')['uri'] = uri
221
222        def deleteReceived(event):
223            self.assertEquals(JID('user@example.org/home'), event.recipient)
224            self.assertEquals(JID('pubsub.example.org'), event.sender)
225            self.assertEquals('test', event.nodeIdentifier)
226            self.assertEquals(uri, event.redirectURI)
227
228        d, self.protocol.deleteReceived = calledAsync(deleteReceived)
229        self.stub.send(message)
230        return d
231
232
233    def test_event_purge(self):
234        """
235        Test receiving a purge event resulting in a call to purgeReceived.
236        """
237        message = domish.Element((None, 'message'))
238        message['from'] = 'pubsub.example.org'
239        message['to'] = 'user@example.org/home'
240        event = message.addElement((NS_PUBSUB_EVENT, 'event'))
241        items = event.addElement('purge')
242        items['node'] = 'test'
243
244        def purgeReceived(event):
245            self.assertEquals(JID('user@example.org/home'), event.recipient)
246            self.assertEquals(JID('pubsub.example.org'), event.sender)
247            self.assertEquals('test', event.nodeIdentifier)
248
249        d, self.protocol.purgeReceived = calledAsync(purgeReceived)
250        self.stub.send(message)
251        return d
252
253
254    def test_createNode(self):
255        """
256        Test sending create request.
257        """
258
259        def cb(nodeIdentifier):
260            self.assertEquals('test', nodeIdentifier)
261
262        d = self.protocol.createNode(JID('pubsub.example.org'), 'test')
263        d.addCallback(cb)
264
265        iq = self.stub.output[-1]
266        self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
267        self.assertEquals('set', iq.getAttribute('type'))
268        self.assertEquals('pubsub', iq.pubsub.name)
269        self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
270        children = list(domish.generateElementsQNamed(iq.pubsub.children,
271                                                      'create', NS_PUBSUB))
272        self.assertEquals(1, len(children))
273        child = children[0]
274        self.assertEquals('test', child['node'])
275
276        response = toResponse(iq, 'result')
277        self.stub.send(response)
278        return d
279
280
281    def test_createNodeInstant(self):
282        """
283        Test sending create request resulting in an instant node.
284        """
285
286        def cb(nodeIdentifier):
287            self.assertEquals('test', nodeIdentifier)
288
289        d = self.protocol.createNode(JID('pubsub.example.org'))
290        d.addCallback(cb)
291
292        iq = self.stub.output[-1]
293        children = list(domish.generateElementsQNamed(iq.pubsub.children,
294                                                      'create', NS_PUBSUB))
295        child = children[0]
296        self.assertFalse(child.hasAttribute('node'))
297
298        response = toResponse(iq, 'result')
299        command = response.addElement((NS_PUBSUB, 'pubsub'))
300        create = command.addElement('create')
301        create['node'] = 'test'
302        self.stub.send(response)
303        return d
304
305
306    def test_createNodeRenamed(self):
307        """
308        Test sending create request resulting in renamed node.
309        """
310
311        def cb(nodeIdentifier):
312            self.assertEquals('test2', nodeIdentifier)
313
314        d = self.protocol.createNode(JID('pubsub.example.org'), 'test')
315        d.addCallback(cb)
316
317        iq = self.stub.output[-1]
318        children = list(domish.generateElementsQNamed(iq.pubsub.children,
319                                                      'create', NS_PUBSUB))
320        child = children[0]
321        self.assertEquals('test', child['node'])
322
323        response = toResponse(iq, 'result')
324        command = response.addElement((NS_PUBSUB, 'pubsub'))
325        create = command.addElement('create')
326        create['node'] = 'test2'
327        self.stub.send(response)
328        return d
329
330
331    def test_createNodeWithSender(self):
332        """
333        Test sending create request from a specific JID.
334        """
335
336        d = self.protocol.createNode(JID('pubsub.example.org'), 'test',
337                                     sender=JID('user@example.org'))
338
339        iq = self.stub.output[-1]
340        self.assertEquals('user@example.org', iq['from'])
341
342        response = toResponse(iq, 'result')
343        self.stub.send(response)
344        return d
345
346
347    def test_createNodeWithConfig(self):
348        """
349        Test sending create request with configuration options
350        """
351
352        options = {
353            'pubsub#title': 'Princely Musings (Atom)',
354            'pubsub#deliver_payloads': True,
355            'pubsub#persist_items': '1',
356            'pubsub#max_items': '10',
357            'pubsub#access_model': 'open',
358            'pubsub#type': 'http://www.w3.org/2005/Atom',
359        }
360
361        d = self.protocol.createNode(JID('pubsub.example.org'), 'test',
362                                     sender=JID('user@example.org'),
363                                     options=options)
364
365        iq = self.stub.output[-1]
366
367        # check if there is exactly one configure element
368        children = list(domish.generateElementsQNamed(iq.pubsub.children,
369                                                      'configure', NS_PUBSUB))
370        self.assertEqual(1, len(children))
371
372        # check that it has a configuration form
373        form = data_form.findForm(children[0], NS_PUBSUB_NODE_CONFIG)
374        self.assertEqual('submit', form.formType)
375
376
377        response = toResponse(iq, 'result')
378        self.stub.send(response)
379        return d
380
381
382    def test_deleteNode(self):
383        """
384        Test sending delete request.
385        """
386
387        d = self.protocol.deleteNode(JID('pubsub.example.org'), 'test')
388
389        iq = self.stub.output[-1]
390        self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
391        self.assertEquals('set', iq.getAttribute('type'))
392        self.assertEquals('pubsub', iq.pubsub.name)
393        self.assertEquals(NS_PUBSUB_OWNER, iq.pubsub.uri)
394        children = list(domish.generateElementsQNamed(iq.pubsub.children,
395                                                      'delete', NS_PUBSUB_OWNER))
396        self.assertEquals(1, len(children))
397        child = children[0]
398        self.assertEquals('test', child['node'])
399
400        response = toResponse(iq, 'result')
401        self.stub.send(response)
402        return d
403
404
405    def test_deleteNodeWithSender(self):
406        """
407        Test sending delete request.
408        """
409
410        d = self.protocol.deleteNode(JID('pubsub.example.org'), 'test',
411                                     sender=JID('user@example.org'))
412
413        iq = self.stub.output[-1]
414        self.assertEquals('user@example.org', iq['from'])
415
416        response = toResponse(iq, 'result')
417        self.stub.send(response)
418        return d
419
420
421    def test_publish(self):
422        """
423        Test sending publish request.
424        """
425
426        item = pubsub.Item()
427        d = self.protocol.publish(JID('pubsub.example.org'), 'test', [item])
428
429        iq = self.stub.output[-1]
430        self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
431        self.assertEquals('set', iq.getAttribute('type'))
432        self.assertEquals('pubsub', iq.pubsub.name)
433        self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
434        children = list(domish.generateElementsQNamed(iq.pubsub.children,
435                                                      'publish', NS_PUBSUB))
436        self.assertEquals(1, len(children))
437        child = children[0]
438        self.assertEquals('test', child['node'])
439
440        items = []
441        for element in child.elements():
442            if element.name == 'item' and element.uri in (NS_PUBSUB, None):
443                items.append(element)
444
445        self.assertEquals(1, len(items))
446        self.assertIdentical(item, items[0])
447
448        response = toResponse(iq, 'result')
449        self.stub.send(response)
450        return d
451
452
453    def test_publishNoItems(self):
454        """
455        Test sending publish request without items.
456        """
457
458        d = self.protocol.publish(JID('pubsub.example.org'), 'test')
459
460        iq = self.stub.output[-1]
461        self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
462        self.assertEquals('set', iq.getAttribute('type'))
463        self.assertEquals('pubsub', iq.pubsub.name)
464        self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
465        children = list(domish.generateElementsQNamed(iq.pubsub.children,
466                                                      'publish', NS_PUBSUB))
467        self.assertEquals(1, len(children))
468        child = children[0]
469        self.assertEquals('test', child['node'])
470
471        response = toResponse(iq, 'result')
472        self.stub.send(response)
473        return d
474
475
476    def test_publishWithSender(self):
477        """
478        Test sending publish request from a specific JID.
479        """
480
481        item = pubsub.Item()
482        d = self.protocol.publish(JID('pubsub.example.org'), 'test', [item],
483                                  JID('user@example.org'))
484
485        iq = self.stub.output[-1]
486        self.assertEquals('user@example.org', iq['from'])
487
488        response = toResponse(iq, 'result')
489        self.stub.send(response)
490        return d
491
492
493    def test_subscribe(self):
494        """
495        Test sending subscription request.
496        """
497        d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
498                                      JID('user@example.org'))
499
500        iq = self.stub.output[-1]
501        self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
502        self.assertEquals('set', iq.getAttribute('type'))
503        self.assertEquals('pubsub', iq.pubsub.name)
504        self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
505        children = list(domish.generateElementsQNamed(iq.pubsub.children,
506                                                      'subscribe', NS_PUBSUB))
507        self.assertEquals(1, len(children))
508        child = children[0]
509        self.assertEquals('test', child['node'])
510        self.assertEquals('user@example.org', child['jid'])
511
512        response = toResponse(iq, 'result')
513        pubsub = response.addElement((NS_PUBSUB, 'pubsub'))
514        subscription = pubsub.addElement('subscription')
515        subscription['node'] = 'test'
516        subscription['jid'] = 'user@example.org'
517        subscription['subscription'] = 'subscribed'
518        self.stub.send(response)
519        return d
520
521
522    def test_subscribeReturnsSubscription(self):
523        """
524        A successful subscription should return a Subscription instance.
525        """
526        def cb(subscription):
527            self.assertEqual(JID('user@example.org'), subscription.subscriber)
528
529        d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
530                                      JID('user@example.org'))
531        d.addCallback(cb)
532
533        iq = self.stub.output[-1]
534
535        response = toResponse(iq, 'result')
536        pubsub = response.addElement((NS_PUBSUB, 'pubsub'))
537        subscription = pubsub.addElement('subscription')
538        subscription['node'] = 'test'
539        subscription['jid'] = 'user@example.org'
540        subscription['subscription'] = 'subscribed'
541        self.stub.send(response)
542        return d
543
544
545    def test_subscribePending(self):
546        """
547        Test sending subscription request that results in a pending
548        subscription.
549        """
550        d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
551                                      JID('user@example.org'))
552
553        iq = self.stub.output[-1]
554        response = toResponse(iq, 'result')
555        command = response.addElement((NS_PUBSUB, 'pubsub'))
556        subscription = command.addElement('subscription')
557        subscription['node'] = 'test'
558        subscription['jid'] = 'user@example.org'
559        subscription['subscription'] = 'pending'
560        self.stub.send(response)
561        self.assertFailure(d, pubsub.SubscriptionPending)
562        return d
563
564
565    def test_subscribeUnconfigured(self):
566        """
567        Test sending subscription request that results in an unconfigured
568        subscription.
569        """
570        d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
571                                      JID('user@example.org'))
572
573        iq = self.stub.output[-1]
574        response = toResponse(iq, 'result')
575        command = response.addElement((NS_PUBSUB, 'pubsub'))
576        subscription = command.addElement('subscription')
577        subscription['node'] = 'test'
578        subscription['jid'] = 'user@example.org'
579        subscription['subscription'] = 'unconfigured'
580        self.stub.send(response)
581        self.assertFailure(d, pubsub.SubscriptionUnconfigured)
582        return d
583
584
585    def test_subscribeWithOptions(self):
586        options = {'pubsub#deliver': False}
587
588        d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
589                                    JID('user@example.org'),
590                                    options=options)
591        iq = self.stub.output[-1]
592
593        # Check options present
594        childNames = []
595        for element in iq.pubsub.elements():
596            if element.uri == NS_PUBSUB:
597                childNames.append(element.name)
598
599        self.assertEqual(['subscribe', 'options'], childNames)
600        form = data_form.findForm(iq.pubsub.options,
601                                  NS_PUBSUB_SUBSCRIBE_OPTIONS)
602        self.assertEqual('submit', form.formType)
603        form.typeCheck({'pubsub#deliver': {'type': 'boolean'}})
604        self.assertEqual(options, form.getValues())
605
606        # Send response
607        response = toResponse(iq, 'result')
608        pubsub = response.addElement((NS_PUBSUB, 'pubsub'))
609        subscription = pubsub.addElement('subscription')
610        subscription['node'] = 'test'
611        subscription['jid'] = 'user@example.org'
612        subscription['subscription'] = 'subscribed'
613        self.stub.send(response)
614
615        return d
616
617
618    def test_subscribeWithSender(self):
619        """
620        Test sending subscription request from a specific JID.
621        """
622        d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
623                                      JID('user@example.org'),
624                                      sender=JID('user@example.org'))
625
626        iq = self.stub.output[-1]
627        self.assertEquals('user@example.org', iq['from'])
628
629        response = toResponse(iq, 'result')
630        pubsub = response.addElement((NS_PUBSUB, 'pubsub'))
631        subscription = pubsub.addElement('subscription')
632        subscription['node'] = 'test'
633        subscription['jid'] = 'user@example.org'
634        subscription['subscription'] = 'subscribed'
635        self.stub.send(response)
636        return d
637
638
639    def test_subscribeReturningSubscriptionIdentifier(self):
640        """
641        Test sending subscription request with subscription identifier.
642        """
643        def cb(subscription):
644            self.assertEqual('1234', subscription.subscriptionIdentifier)
645
646        d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
647                                      JID('user@example.org'))
648        d.addCallback(cb)
649
650        iq = self.stub.output[-1]
651
652        response = toResponse(iq, 'result')
653        pubsub = response.addElement((NS_PUBSUB, 'pubsub'))
654        subscription = pubsub.addElement('subscription')
655        subscription['node'] = 'test'
656        subscription['jid'] = 'user@example.org'
657        subscription['subscription'] = 'subscribed'
658        subscription['subid'] = '1234'
659        self.stub.send(response)
660        return d
661
662
663    def test_unsubscribe(self):
664        """
665        Test sending unsubscription request.
666        """
667        d = self.protocol.unsubscribe(JID('pubsub.example.org'), 'test',
668                                      JID('user@example.org'))
669
670        iq = self.stub.output[-1]
671        self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
672        self.assertEquals('set', iq.getAttribute('type'))
673        self.assertEquals('pubsub', iq.pubsub.name)
674        self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
675        children = list(domish.generateElementsQNamed(iq.pubsub.children,
676                                                      'unsubscribe', NS_PUBSUB))
677        self.assertEquals(1, len(children))
678        child = children[0]
679        self.assertEquals('test', child['node'])
680        self.assertEquals('user@example.org', child['jid'])
681
682        self.stub.send(toResponse(iq, 'result'))
683        return d
684
685
686    def test_unsubscribeWithSender(self):
687        """
688        Test sending unsubscription request from a specific JID.
689        """
690        d = self.protocol.unsubscribe(JID('pubsub.example.org'), 'test',
691                                      JID('user@example.org'),
692                                      sender=JID('user@example.org'))
693
694        iq = self.stub.output[-1]
695        self.assertEquals('user@example.org', iq['from'])
696        self.stub.send(toResponse(iq, 'result'))
697        return d
698
699
700    def test_unsubscribeWithSubscriptionIdentifier(self):
701        """
702        Test sending unsubscription request with subscription identifier.
703        """
704        d = self.protocol.unsubscribe(JID('pubsub.example.org'), 'test',
705                                      JID('user@example.org'),
706                                      subscriptionIdentifier='1234')
707
708        iq = self.stub.output[-1]
709        child = iq.pubsub.unsubscribe
710        self.assertEquals('1234', child['subid'])
711
712        self.stub.send(toResponse(iq, 'result'))
713        return d
714
715
716    def test_items(self):
717        """
718        Test sending items request.
719        """
720        def cb(items):
721            self.assertEquals([], items)
722
723        d = self.protocol.items(JID('pubsub.example.org'), 'test')
724        d.addCallback(cb)
725
726        iq = self.stub.output[-1]
727        self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
728        self.assertEquals('get', iq.getAttribute('type'))
729        self.assertEquals('pubsub', iq.pubsub.name)
730        self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
731        children = list(domish.generateElementsQNamed(iq.pubsub.children,
732                                                      'items', NS_PUBSUB))
733        self.assertEquals(1, len(children))
734        child = children[0]
735        self.assertEquals('test', child['node'])
736
737        response = toResponse(iq, 'result')
738        items = response.addElement((NS_PUBSUB, 'pubsub')).addElement('items')
739        items['node'] = 'test'
740
741        self.stub.send(response)
742
743        return d
744
745
746    def test_itemsMaxItems(self):
747        """
748        Test sending items request, with limit on the number of items.
749        """
750        def cb(items):
751            self.assertEquals(2, len(items))
752            self.assertEquals([item1, item2], items)
753
754        d = self.protocol.items(JID('pubsub.example.org'), 'test', maxItems=2)
755        d.addCallback(cb)
756
757        iq = self.stub.output[-1]
758        self.assertEquals('pubsub.example.org', iq.getAttribute('to'))
759        self.assertEquals('get', iq.getAttribute('type'))
760        self.assertEquals('pubsub', iq.pubsub.name)
761        self.assertEquals(NS_PUBSUB, iq.pubsub.uri)
762        children = list(domish.generateElementsQNamed(iq.pubsub.children,
763                                                      'items', NS_PUBSUB))
764        self.assertEquals(1, len(children))
765        child = children[0]
766        self.assertEquals('test', child['node'])
767        self.assertEquals('2', child['max_items'])
768
769        response = toResponse(iq, 'result')
770        items = response.addElement((NS_PUBSUB, 'pubsub')).addElement('items')
771        items['node'] = 'test'
772        item1 = items.addElement('item')
773        item1['id'] = 'item1'
774        item2 = items.addElement('item')
775        item2['id'] = 'item2'
776
777        self.stub.send(response)
778
779        return d
780
781
782    def test_itemsWithSubscriptionIdentifier(self):
783        """
784        Test sending items request with a subscription identifier.
785        """
786
787        d = self.protocol.items(JID('pubsub.example.org'), 'test',
788                               subscriptionIdentifier='1234')
789
790        iq = self.stub.output[-1]
791        child = iq.pubsub.items
792        self.assertEquals('1234', child['subid'])
793
794        response = toResponse(iq, 'result')
795        items = response.addElement((NS_PUBSUB, 'pubsub')).addElement('items')
796        items['node'] = 'test'
797
798        self.stub.send(response)
799        return d
800
801
802    def test_itemsWithSender(self):
803        """
804        Test sending items request from a specific JID.
805        """
806
807        d = self.protocol.items(JID('pubsub.example.org'), 'test',
808                               sender=JID('user@example.org'))
809
810        iq = self.stub.output[-1]
811        self.assertEquals('user@example.org', iq['from'])
812
813        response = toResponse(iq, 'result')
814        items = response.addElement((NS_PUBSUB, 'pubsub')).addElement('items')
815        items['node'] = 'test'
816
817        self.stub.send(response)
818        return d
819
820
821    def test_getOptions(self):
822        def cb(form):
823            self.assertEqual('form', form.formType)
824            self.assertEqual(NS_PUBSUB_SUBSCRIBE_OPTIONS, form.formNamespace)
825            field = form.fields['pubsub#deliver']
826            self.assertEqual('boolean', field.fieldType)
827            self.assertIdentical(True, field.value)
828            self.assertEqual('Enable delivery?', field.label)
829
830        d = self.protocol.getOptions(JID('pubsub.example.org'), 'test',
831                                     JID('user@example.org'),
832                                     sender=JID('user@example.org'))
833        d.addCallback(cb)
834
835        iq = self.stub.output[-1]
836        self.assertEqual('pubsub.example.org', iq.getAttribute('to'))
837        self.assertEqual('get', iq.getAttribute('type'))
838        self.assertEqual('pubsub', iq.pubsub.name)
839        self.assertEqual(NS_PUBSUB, iq.pubsub.uri)
840        children = list(domish.generateElementsQNamed(iq.pubsub.children,
841                                                      'options', NS_PUBSUB))
842        self.assertEqual(1, len(children))
843        child = children[0]
844        self.assertEqual('test', child['node'])
845
846        self.assertEqual(0, len(child.children))
847
848        # Send response
849        form = data_form.Form('form', formNamespace=NS_PUBSUB_SUBSCRIBE_OPTIONS)
850        form.addField(data_form.Field('boolean', var='pubsub#deliver',
851                                                 label='Enable delivery?',
852                                                 value=True))
853        response = toResponse(iq, 'result')
854        response.addElement((NS_PUBSUB, 'pubsub'))
855        response.pubsub.addElement('options')
856        response.pubsub.options.addChild(form.toElement())
857        self.stub.send(response)
858
859        return d
860
861
862    def test_getOptionsWithSubscriptionIdentifier(self):
863        """
864        Getting options with a subid should have the subid in the request.
865        """
866
867        d = self.protocol.getOptions(JID('pubsub.example.org'), 'test',
868                                     JID('user@example.org'),
869                                     sender=JID('user@example.org'),
870                                     subscriptionIdentifier='1234')
871
872        iq = self.stub.output[-1]
873        child = iq.pubsub.options
874        self.assertEqual('1234', child['subid'])
875
876        # Send response
877        form = data_form.Form('form', formNamespace=NS_PUBSUB_SUBSCRIBE_OPTIONS)
878        form.addField(data_form.Field('boolean', var='pubsub#deliver',
879                                                 label='Enable delivery?',
880                                                 value=True))
881        response = toResponse(iq, 'result')
882        response.addElement((NS_PUBSUB, 'pubsub'))
883        response.pubsub.addElement('options')
884        response.pubsub.options.addChild(form.toElement())
885        self.stub.send(response)
886
887        return d
888
889
890    def test_setOptions(self):
891        """
892        setOptions should send out a options-set request.
893        """
894        options = {'pubsub#deliver': False}
895
896        d = self.protocol.setOptions(JID('pubsub.example.org'), 'test',
897                                     JID('user@example.org'),
898                                     options,
899                                     sender=JID('user@example.org'))
900
901        iq = self.stub.output[-1]
902        self.assertEqual('pubsub.example.org', iq.getAttribute('to'))
903        self.assertEqual('set', iq.getAttribute('type'))
904        self.assertEqual('pubsub', iq.pubsub.name)
905        self.assertEqual(NS_PUBSUB, iq.pubsub.uri)
906        children = list(domish.generateElementsQNamed(iq.pubsub.children,
907                                                      'options', NS_PUBSUB))
908        self.assertEqual(1, len(children))
909        child = children[0]
910        self.assertEqual('test', child['node'])
911
912        form = data_form.findForm(child, NS_PUBSUB_SUBSCRIBE_OPTIONS)
913        self.assertEqual('submit', form.formType)
914        form.typeCheck({'pubsub#deliver': {'type': 'boolean'}})
915        self.assertEqual(options, form.getValues())
916
917        response = toResponse(iq, 'result')
918        self.stub.send(response)
919
920        return d
921
922
923    def test_setOptionsWithSubscriptionIdentifier(self):
924        """
925        setOptions should send out a options-set request with subid.
926        """
927        options = {'pubsub#deliver': False}
928
929        d = self.protocol.setOptions(JID('pubsub.example.org'), 'test',
930                                     JID('user@example.org'),
931                                     options,
932                                     subscriptionIdentifier='1234',
933                                     sender=JID('user@example.org'))
934
935        iq = self.stub.output[-1]
936        child = iq.pubsub.options
937        self.assertEqual('1234', child['subid'])
938
939        form = data_form.findForm(child, NS_PUBSUB_SUBSCRIBE_OPTIONS)
940        self.assertEqual('submit', form.formType)
941        form.typeCheck({'pubsub#deliver': {'type': 'boolean'}})
942        self.assertEqual(options, form.getValues())
943
944        response = toResponse(iq, 'result')
945        self.stub.send(response)
946
947        return d
948
949
950class PubSubRequestTest(unittest.TestCase):
951
952    def test_fromElementUnknown(self):
953        """
954        An unknown verb raises NotImplementedError.
955        """
956
957        xml = """
958        <iq type='set' to='pubsub.example.org'
959                       from='user@example.org'>
960          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
961            <non-existing-verb/>
962          </pubsub>
963        </iq>
964        """
965
966        self.assertRaises(NotImplementedError,
967                          pubsub.PubSubRequest.fromElement, parseXml(xml))
968
969
970    def test_fromElementKnownBadCombination(self):
971        """
972        Multiple verbs in an unknown configuration raises NotImplementedError.
973        """
974
975        xml = """
976        <iq type='set' to='pubsub.example.org'
977                       from='user@example.org'>
978          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
979             <publish/>
980             <create/>
981          </pubsub>
982        </iq>
983        """
984
985        self.assertRaises(NotImplementedError,
986                          pubsub.PubSubRequest.fromElement, parseXml(xml))
987
988    def test_fromElementPublish(self):
989        """
990        Test parsing a publish request.
991        """
992
993        xml = """
994        <iq type='set' to='pubsub.example.org'
995                       from='user@example.org'>
996          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
997            <publish node='test'/>
998          </pubsub>
999        </iq>
1000        """
1001
1002        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1003        self.assertEqual('publish', request.verb)
1004        self.assertEqual(JID('user@example.org'), request.sender)
1005        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1006        self.assertEqual('test', request.nodeIdentifier)
1007        self.assertEqual([], request.items)
1008
1009
1010    def test_fromElementPublishItems(self):
1011        """
1012        Test parsing a publish request with items.
1013        """
1014
1015        xml = """
1016        <iq type='set' to='pubsub.example.org'
1017                       from='user@example.org'>
1018          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1019            <publish node='test'>
1020              <item id="item1"/>
1021              <item id="item2"/>
1022            </publish>
1023          </pubsub>
1024        </iq>
1025        """
1026
1027        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1028        self.assertEqual(2, len(request.items))
1029        self.assertEqual(u'item1', request.items[0]["id"])
1030        self.assertEqual(u'item2', request.items[1]["id"])
1031
1032
1033    def test_fromElementPublishNoNode(self):
1034        """
1035        A publish request to the root node should raise an exception.
1036        """
1037        xml = """
1038        <iq type='set' to='pubsub.example.org'
1039                       from='user@example.org'>
1040          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1041            <publish/>
1042          </pubsub>
1043        </iq>
1044        """
1045
1046        err = self.assertRaises(error.StanzaError,
1047                                pubsub.PubSubRequest.fromElement,
1048                                parseXml(xml))
1049        self.assertEqual('bad-request', err.condition)
1050        self.assertEqual(NS_PUBSUB_ERRORS, err.appCondition.uri)
1051        self.assertEqual('nodeid-required', err.appCondition.name)
1052
1053
1054    def test_fromElementSubscribe(self):
1055        """
1056        Test parsing a subscription request.
1057        """
1058
1059        xml = """
1060        <iq type='set' to='pubsub.example.org'
1061                       from='user@example.org'>
1062          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1063            <subscribe node='test' jid='user@example.org/Home'/>
1064          </pubsub>
1065        </iq>
1066        """
1067
1068        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1069        self.assertEqual('subscribe', request.verb)
1070        self.assertEqual(JID('user@example.org'), request.sender)
1071        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1072        self.assertEqual('test', request.nodeIdentifier)
1073        self.assertEqual(JID('user@example.org/Home'), request.subscriber)
1074
1075
1076    def test_fromElementSubscribeEmptyNode(self):
1077        """
1078        Test parsing a subscription request to the root node.
1079        """
1080
1081        xml = """
1082        <iq type='set' to='pubsub.example.org'
1083                       from='user@example.org'>
1084          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1085            <subscribe jid='user@example.org/Home'/>
1086          </pubsub>
1087        </iq>
1088        """
1089
1090        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1091        self.assertEqual('', request.nodeIdentifier)
1092
1093
1094    def test_fromElementSubscribeNoJID(self):
1095        """
1096        Subscribe requests without a JID should raise a bad-request exception.
1097        """
1098        xml = """
1099        <iq type='set' to='pubsub.example.org'
1100                       from='user@example.org'>
1101          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1102            <subscribe node='test'/>
1103          </pubsub>
1104        </iq>
1105        """
1106        err = self.assertRaises(error.StanzaError,
1107                                pubsub.PubSubRequest.fromElement,
1108                                parseXml(xml))
1109        self.assertEqual('bad-request', err.condition)
1110        self.assertEqual(NS_PUBSUB_ERRORS, err.appCondition.uri)
1111        self.assertEqual('jid-required', err.appCondition.name)
1112
1113
1114    def test_fromElementSubscribeWithOptions(self):
1115        """
1116        Test parsing a subscription request.
1117        """
1118
1119        xml = """
1120        <iq type='set' to='pubsub.example.org'
1121                       from='user@example.org'>
1122          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1123            <subscribe node='test' jid='user@example.org/Home'/>
1124            <options>
1125              <x xmlns="jabber:x:data" type='submit'>
1126                <field var='FORM_TYPE' type='hidden'>
1127                  <value>http://jabber.org/protocol/pubsub#subscribe_options</value>
1128                </field>
1129                <field var='pubsub#deliver' type='boolean'
1130                       label='Enable delivery?'>
1131                  <value>1</value>
1132                </field>
1133              </x>
1134            </options>
1135          </pubsub>
1136        </iq>
1137        """
1138
1139        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1140        self.assertEqual('subscribe', request.verb)
1141        request.options.typeCheck({'pubsub#deliver': {'type': 'boolean'}})
1142        self.assertEqual({'pubsub#deliver': True}, request.options.getValues())
1143
1144
1145    def test_fromElementSubscribeWithOptionsBadFormType(self):
1146        """
1147        The options form should have the right type.
1148        """
1149
1150        xml = """
1151        <iq type='set' to='pubsub.example.org'
1152                       from='user@example.org'>
1153          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1154            <subscribe node='test' jid='user@example.org/Home'/>
1155            <options>
1156              <x xmlns="jabber:x:data" type='result'>
1157                <field var='FORM_TYPE' type='hidden'>
1158                  <value>http://jabber.org/protocol/pubsub#subscribe_options</value>
1159                </field>
1160                <field var='pubsub#deliver' type='boolean'
1161                       label='Enable delivery?'>
1162                  <value>1</value>
1163                </field>
1164              </x>
1165            </options>
1166          </pubsub>
1167        </iq>
1168        """
1169
1170        err = self.assertRaises(error.StanzaError,
1171                                pubsub.PubSubRequest.fromElement,
1172                                parseXml(xml))
1173        self.assertEqual('bad-request', err.condition)
1174        self.assertEqual("Unexpected form type 'result'", err.text)
1175        self.assertEqual(None, err.appCondition)
1176
1177
1178    def test_fromElementSubscribeWithOptionsEmpty(self):
1179        """
1180        When no (suitable) form is found, the options are empty.
1181        """
1182
1183        xml = """
1184        <iq type='set' to='pubsub.example.org'
1185                       from='user@example.org'>
1186          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1187            <subscribe node='test' jid='user@example.org/Home'/>
1188            <options/>
1189          </pubsub>
1190        </iq>
1191        """
1192
1193        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1194        self.assertEqual('subscribe', request.verb)
1195        self.assertEqual({}, request.options.getValues())
1196
1197
1198    def test_fromElementUnsubscribe(self):
1199        """
1200        Test parsing an unsubscription request.
1201        """
1202
1203        xml = """
1204        <iq type='set' to='pubsub.example.org'
1205                       from='user@example.org'>
1206          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1207            <unsubscribe node='test' jid='user@example.org/Home'/>
1208          </pubsub>
1209        </iq>
1210        """
1211
1212        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1213        self.assertEqual('unsubscribe', request.verb)
1214        self.assertEqual(JID('user@example.org'), request.sender)
1215        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1216        self.assertEqual('test', request.nodeIdentifier)
1217        self.assertEqual(JID('user@example.org/Home'), request.subscriber)
1218
1219
1220    def test_fromElementUnsubscribeWithSubscriptionIdentifier(self):
1221        """
1222        Test parsing an unsubscription request with subscription identifier.
1223        """
1224
1225        xml = """
1226        <iq type='set' to='pubsub.example.org'
1227                       from='user@example.org'>
1228          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1229            <unsubscribe node='test' jid='user@example.org/Home'
1230                         subid='1234'/>
1231          </pubsub>
1232        </iq>
1233        """
1234
1235        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1236        self.assertEqual('1234', request.subscriptionIdentifier)
1237
1238
1239    def test_fromElementUnsubscribeNoJID(self):
1240        """
1241        Unsubscribe requests without a JID should raise a bad-request exception.
1242        """
1243        xml = """
1244        <iq type='set' to='pubsub.example.org'
1245                       from='user@example.org'>
1246          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1247            <unsubscribe node='test'/>
1248          </pubsub>
1249        </iq>
1250        """
1251        err = self.assertRaises(error.StanzaError,
1252                                pubsub.PubSubRequest.fromElement,
1253                                parseXml(xml))
1254        self.assertEqual('bad-request', err.condition)
1255        self.assertEqual(NS_PUBSUB_ERRORS, err.appCondition.uri)
1256        self.assertEqual('jid-required', err.appCondition.name)
1257
1258
1259    def test_fromElementOptionsGet(self):
1260        """
1261        Test parsing a request for getting subscription options.
1262        """
1263
1264        xml = """
1265        <iq type='get' to='pubsub.example.org'
1266                       from='user@example.org'>
1267          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1268            <options node='test' jid='user@example.org/Home'/>
1269          </pubsub>
1270        </iq>
1271        """
1272
1273        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1274        self.assertEqual('optionsGet', request.verb)
1275        self.assertEqual(JID('user@example.org'), request.sender)
1276        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1277        self.assertEqual('test', request.nodeIdentifier)
1278        self.assertEqual(JID('user@example.org/Home'), request.subscriber)
1279
1280
1281    def test_fromElementOptionsGetWithSubscriptionIdentifier(self):
1282        """
1283        Test parsing a request for getting subscription options with subid.
1284        """
1285
1286        xml = """
1287        <iq type='get' to='pubsub.example.org'
1288                       from='user@example.org'>
1289          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1290            <options node='test' jid='user@example.org/Home'
1291                     subid='1234'/>
1292          </pubsub>
1293        </iq>
1294        """
1295
1296        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1297        self.assertEqual('1234', request.subscriptionIdentifier)
1298
1299
1300    def test_fromElementOptionsSet(self):
1301        """
1302        Test parsing a request for setting subscription options.
1303        """
1304
1305        xml = """
1306        <iq type='set' to='pubsub.example.org'
1307                       from='user@example.org'>
1308          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1309            <options node='test' jid='user@example.org/Home'>
1310              <x xmlns='jabber:x:data' type='submit'>
1311                <field var='FORM_TYPE' type='hidden'>
1312                  <value>http://jabber.org/protocol/pubsub#subscribe_options</value>
1313                </field>
1314                <field var='pubsub#deliver'><value>1</value></field>
1315              </x>
1316            </options>
1317          </pubsub>
1318        </iq>
1319        """
1320
1321        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1322        self.assertEqual('optionsSet', request.verb)
1323        self.assertEqual(JID('user@example.org'), request.sender)
1324        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1325        self.assertEqual('test', request.nodeIdentifier)
1326        self.assertEqual(JID('user@example.org/Home'), request.subscriber)
1327        self.assertEqual({'pubsub#deliver': '1'}, request.options.getValues())
1328
1329
1330    def test_fromElementOptionsSetWithSubscriptionIdentifier(self):
1331        """
1332        Test parsing a request for setting subscription options with subid.
1333        """
1334
1335        xml = """
1336        <iq type='set' to='pubsub.example.org'
1337                       from='user@example.org'>
1338          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1339            <options node='test' jid='user@example.org/Home'
1340                     subid='1234'>
1341              <x xmlns='jabber:x:data' type='submit'>
1342                <field var='FORM_TYPE' type='hidden'>
1343                  <value>http://jabber.org/protocol/pubsub#subscribe_options</value>
1344                </field>
1345                <field var='pubsub#deliver'><value>1</value></field>
1346              </x>
1347            </options>
1348          </pubsub>
1349        </iq>
1350        """
1351
1352        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1353        self.assertEqual('1234', request.subscriptionIdentifier)
1354
1355
1356    def test_fromElementOptionsSetCancel(self):
1357        """
1358        Test parsing a request for cancelling setting subscription options.
1359        """
1360
1361        xml = """
1362        <iq type='set' to='pubsub.example.org'
1363                       from='user@example.org'>
1364          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1365            <options node='test' jid='user@example.org/Home'>
1366              <x xmlns='jabber:x:data' type='cancel'/>
1367            </options>
1368          </pubsub>
1369        </iq>
1370        """
1371
1372        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1373        self.assertEqual('cancel', request.options.formType)
1374
1375
1376    def test_fromElementOptionsSetBadFormType(self):
1377        """
1378        On a options set request unknown fields should be ignored.
1379        """
1380
1381        xml = """
1382        <iq type='set' to='pubsub.example.org'
1383                       from='user@example.org'>
1384          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1385            <options node='test' jid='user@example.org/Home'>
1386              <x xmlns='jabber:x:data' type='result'>
1387                <field var='FORM_TYPE' type='hidden'>
1388                  <value>http://jabber.org/protocol/pubsub#subscribe_options</value>
1389                </field>
1390                <field var='pubsub#deliver'><value>1</value></field>
1391              </x>
1392            </options>
1393          </pubsub>
1394        </iq>
1395        """
1396
1397        err = self.assertRaises(error.StanzaError,
1398                                pubsub.PubSubRequest.fromElement,
1399                                parseXml(xml))
1400        self.assertEqual('bad-request', err.condition)
1401        self.assertEqual("Unexpected form type 'result'", err.text)
1402        self.assertEqual(None, err.appCondition)
1403
1404
1405    def test_fromElementOptionsSetNoForm(self):
1406        """
1407        On a options set request a form is required.
1408        """
1409
1410        xml = """
1411        <iq type='set' to='pubsub.example.org'
1412                       from='user@example.org'>
1413          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1414            <options node='test' jid='user@example.org/Home'/>
1415          </pubsub>
1416        </iq>
1417        """
1418        err = self.assertRaises(error.StanzaError,
1419                                pubsub.PubSubRequest.fromElement,
1420                                parseXml(xml))
1421        self.assertEqual('bad-request', err.condition)
1422        self.assertEqual(None, err.appCondition)
1423
1424
1425    def test_fromElementSubscriptions(self):
1426        """
1427        Test parsing a request for all subscriptions.
1428        """
1429
1430        xml = """
1431        <iq type='get' to='pubsub.example.org'
1432                       from='user@example.org'>
1433          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1434            <subscriptions/>
1435          </pubsub>
1436        </iq>
1437        """
1438
1439        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1440        self.assertEqual('subscriptions', request.verb)
1441        self.assertEqual(JID('user@example.org'), request.sender)
1442        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1443
1444
1445    def test_fromElementAffiliations(self):
1446        """
1447        Test parsing a request for all affiliations.
1448        """
1449
1450        xml = """
1451        <iq type='get' to='pubsub.example.org'
1452                       from='user@example.org'>
1453          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1454            <affiliations/>
1455          </pubsub>
1456        </iq>
1457        """
1458
1459        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1460        self.assertEqual('affiliations', request.verb)
1461        self.assertEqual(JID('user@example.org'), request.sender)
1462        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1463
1464
1465    def test_fromElementCreate(self):
1466        """
1467        Test parsing a request to create a node.
1468        """
1469
1470        xml = """
1471        <iq type='set' to='pubsub.example.org'
1472                       from='user@example.org'>
1473          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1474            <create node='mynode'/>
1475          </pubsub>
1476        </iq>
1477        """
1478
1479        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1480        self.assertEqual('create', request.verb)
1481        self.assertEqual(JID('user@example.org'), request.sender)
1482        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1483        self.assertEqual('mynode', request.nodeIdentifier)
1484        self.assertIdentical(None, request.options)
1485
1486
1487    def test_fromElementCreateInstant(self):
1488        """
1489        Test parsing a request to create an instant node.
1490        """
1491
1492        xml = """
1493        <iq type='set' to='pubsub.example.org'
1494                       from='user@example.org'>
1495          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1496            <create/>
1497          </pubsub>
1498        </iq>
1499        """
1500
1501        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1502        self.assertIdentical(None, request.nodeIdentifier)
1503
1504
1505    def test_fromElementCreateConfigureEmpty(self):
1506        """
1507        Test parsing a request to create a node with an empty configuration.
1508        """
1509
1510        xml = """
1511        <iq type='set' to='pubsub.example.org'
1512                       from='user@example.org'>
1513          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1514            <create node='mynode'/>
1515            <configure/>
1516          </pubsub>
1517        </iq>
1518        """
1519
1520        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1521        self.assertEqual({}, request.options.getValues())
1522
1523
1524    def test_fromElementCreateConfigureEmptyWrongOrder(self):
1525        """
1526        Test parsing a request to create a node and configure, wrong order.
1527
1528        The C{configure} element should come after the C{create} request,
1529        but we should accept both orders.
1530        """
1531
1532        xml = """
1533        <iq type='set' to='pubsub.example.org'
1534                       from='user@example.org'>
1535          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1536            <configure/>
1537            <create node='mynode'/>
1538          </pubsub>
1539        </iq>
1540        """
1541
1542        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1543        self.assertEqual({}, request.options.getValues())
1544
1545
1546    def test_fromElementCreateConfigure(self):
1547        """
1548        Test parsing a request to create a node.
1549        """
1550
1551        xml = """
1552        <iq type='set' to='pubsub.example.org'
1553                       from='user@example.org'>
1554          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1555            <create node='mynode'/>
1556            <configure>
1557              <x xmlns='jabber:x:data' type='submit'>
1558                <field var='FORM_TYPE' type='hidden'>
1559                  <value>http://jabber.org/protocol/pubsub#node_config</value>
1560                </field>
1561                <field var='pubsub#access_model'><value>open</value></field>
1562                <field var='pubsub#persist_items'><value>0</value></field>
1563              </x>
1564            </configure>
1565          </pubsub>
1566        </iq>
1567        """
1568
1569        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1570        values = request.options.getValues()
1571        self.assertIn('pubsub#access_model', values)
1572        self.assertEqual(u'open', values['pubsub#access_model'])
1573        self.assertIn('pubsub#persist_items', values)
1574        self.assertEqual(u'0', values['pubsub#persist_items'])
1575
1576
1577    def test_fromElementCreateConfigureBadFormType(self):
1578        """
1579        The form of a node creation request should have the right type.
1580        """
1581
1582        xml = """
1583        <iq type='set' to='pubsub.example.org'
1584                       from='user@example.org'>
1585          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1586            <create node='mynode'/>
1587            <configure>
1588              <x xmlns='jabber:x:data' type='result'>
1589                <field var='FORM_TYPE' type='hidden'>
1590                  <value>http://jabber.org/protocol/pubsub#node_config</value>
1591                </field>
1592                <field var='pubsub#access_model'><value>open</value></field>
1593                <field var='pubsub#persist_items'><value>0</value></field>
1594              </x>
1595            </configure>
1596          </pubsub>
1597        </iq>
1598        """
1599
1600        err = self.assertRaises(error.StanzaError,
1601                                pubsub.PubSubRequest.fromElement,
1602                                parseXml(xml))
1603        self.assertEqual('bad-request', err.condition)
1604        self.assertEqual("Unexpected form type 'result'", err.text)
1605        self.assertEqual(None, err.appCondition)
1606
1607
1608    def test_fromElementDefault(self):
1609        """
1610        Test parsing a request for the default node configuration.
1611        """
1612
1613        xml = """
1614        <iq type='get' to='pubsub.example.org'
1615                       from='user@example.org'>
1616          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1617            <default/>
1618          </pubsub>
1619        </iq>
1620        """
1621
1622        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1623        self.assertEqual('default', request.verb)
1624        self.assertEqual(JID('user@example.org'), request.sender)
1625        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1626        self.assertEqual('leaf', request.nodeType)
1627
1628
1629    def test_fromElementDefaultCollection(self):
1630        """
1631        Parsing a request for the default configuration extracts the node type.
1632        """
1633
1634        xml = """
1635        <iq type='get' to='pubsub.example.org'
1636                       from='user@example.org'>
1637          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1638            <default>
1639              <x xmlns='jabber:x:data' type='submit'>
1640                <field var='FORM_TYPE' type='hidden'>
1641                  <value>http://jabber.org/protocol/pubsub#node_config</value>
1642                </field>
1643                <field var='pubsub#node_type'>
1644                  <value>collection</value>
1645                </field>
1646              </x>
1647            </default>
1648
1649          </pubsub>
1650        </iq>
1651        """
1652
1653        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1654        self.assertEqual('collection', request.nodeType)
1655
1656
1657    def test_fromElementConfigureGet(self):
1658        """
1659        Test parsing a node configuration get request.
1660        """
1661
1662        xml = """
1663        <iq type='get' to='pubsub.example.org'
1664                       from='user@example.org'>
1665          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1666            <configure node='test'/>
1667          </pubsub>
1668        </iq>
1669        """
1670
1671        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1672        self.assertEqual('configureGet', request.verb)
1673        self.assertEqual(JID('user@example.org'), request.sender)
1674        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1675        self.assertEqual('test', request.nodeIdentifier)
1676
1677
1678    def test_fromElementConfigureSet(self):
1679        """
1680        On a node configuration set request the Data Form is parsed.
1681        """
1682
1683        xml = """
1684        <iq type='set' to='pubsub.example.org'
1685                       from='user@example.org'>
1686          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1687            <configure node='test'>
1688              <x xmlns='jabber:x:data' type='submit'>
1689                <field var='FORM_TYPE' type='hidden'>
1690                  <value>http://jabber.org/protocol/pubsub#node_config</value>
1691                </field>
1692                <field var='pubsub#deliver_payloads'><value>0</value></field>
1693                <field var='pubsub#persist_items'><value>1</value></field>
1694              </x>
1695            </configure>
1696          </pubsub>
1697        </iq>
1698        """
1699
1700        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1701        self.assertEqual('configureSet', request.verb)
1702        self.assertEqual(JID('user@example.org'), request.sender)
1703        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1704        self.assertEqual('test', request.nodeIdentifier)
1705        self.assertEqual({'pubsub#deliver_payloads': '0',
1706                          'pubsub#persist_items': '1'},
1707                         request.options.getValues())
1708
1709
1710    def test_fromElementConfigureSetCancel(self):
1711        """
1712        The node configuration is cancelled, so no options.
1713        """
1714
1715        xml = """
1716        <iq type='set' to='pubsub.example.org'
1717                       from='user@example.org'>
1718          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1719            <configure node='test'>
1720              <x xmlns='jabber:x:data' type='cancel'/>
1721            </configure>
1722          </pubsub>
1723        </iq>
1724        """
1725
1726        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1727        self.assertEqual('cancel', request.options.formType)
1728
1729
1730    def test_fromElementConfigureSetBadFormType(self):
1731        """
1732        The form of a node configuraton set request should have the right type.
1733        """
1734
1735        xml = """
1736        <iq type='set' to='pubsub.example.org'
1737                       from='user@example.org'>
1738          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1739            <configure node='test'>
1740              <x xmlns='jabber:x:data' type='result'>
1741                <field var='FORM_TYPE' type='hidden'>
1742                  <value>http://jabber.org/protocol/pubsub#node_config</value>
1743                </field>
1744                <field var='pubsub#deliver_payloads'><value>0</value></field>
1745                <field var='x-myfield'><value>1</value></field>
1746              </x>
1747            </configure>
1748          </pubsub>
1749        </iq>
1750        """
1751
1752        err = self.assertRaises(error.StanzaError,
1753                                pubsub.PubSubRequest.fromElement,
1754                                parseXml(xml))
1755        self.assertEqual('bad-request', err.condition)
1756        self.assertEqual("Unexpected form type 'result'", err.text)
1757        self.assertEqual(None, err.appCondition)
1758
1759
1760    def test_fromElementConfigureSetNoForm(self):
1761        """
1762        On a node configuration set request a form is required.
1763        """
1764
1765        xml = """
1766        <iq type='set' to='pubsub.example.org'
1767                       from='user@example.org'>
1768          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1769            <configure node='test'/>
1770          </pubsub>
1771        </iq>
1772        """
1773        err = self.assertRaises(error.StanzaError,
1774                                pubsub.PubSubRequest.fromElement,
1775                                parseXml(xml))
1776        self.assertEqual('bad-request', err.condition)
1777        self.assertEqual(None, err.appCondition)
1778
1779
1780    def test_fromElementItems(self):
1781        """
1782        Test parsing an items request.
1783        """
1784        xml = """
1785        <iq type='get' to='pubsub.example.org'
1786                       from='user@example.org'>
1787          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1788            <items node='test'/>
1789          </pubsub>
1790        </iq>
1791        """
1792
1793        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1794        self.assertEqual('items', request.verb)
1795        self.assertEqual(JID('user@example.org'), request.sender)
1796        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1797        self.assertEqual('test', request.nodeIdentifier)
1798        self.assertIdentical(None, request.maxItems)
1799        self.assertIdentical(None, request.subscriptionIdentifier)
1800        self.assertEqual([], request.itemIdentifiers)
1801
1802
1803    def test_fromElementItemsSubscriptionIdentifier(self):
1804        """
1805        Test parsing an items request with subscription identifier.
1806        """
1807        xml = """
1808        <iq type='get' to='pubsub.example.org'
1809                       from='user@example.org'>
1810          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1811            <items node='test' subid='1234'/>
1812          </pubsub>
1813        </iq>
1814        """
1815
1816        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1817        self.assertEqual('1234', request.subscriptionIdentifier)
1818
1819
1820    def test_fromElementRetract(self):
1821        """
1822        Test parsing a retract request.
1823        """
1824
1825        xml = """
1826        <iq type='set' to='pubsub.example.org'
1827                       from='user@example.org'>
1828          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1829            <retract node='test'>
1830              <item id='item1'/>
1831              <item id='item2'/>
1832            </retract>
1833          </pubsub>
1834        </iq>
1835        """
1836
1837        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1838        self.assertEqual('retract', request.verb)
1839        self.assertEqual(JID('user@example.org'), request.sender)
1840        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1841        self.assertEqual('test', request.nodeIdentifier)
1842        self.assertEqual(['item1', 'item2'], request.itemIdentifiers)
1843
1844
1845    def test_fromElementPurge(self):
1846        """
1847        Test parsing a purge request.
1848        """
1849
1850        xml = """
1851        <iq type='set' to='pubsub.example.org'
1852                       from='user@example.org'>
1853          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1854            <purge node='test'/>
1855          </pubsub>
1856        </iq>
1857        """
1858
1859        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1860        self.assertEqual('purge', request.verb)
1861        self.assertEqual(JID('user@example.org'), request.sender)
1862        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1863        self.assertEqual('test', request.nodeIdentifier)
1864
1865
1866    def test_fromElementDelete(self):
1867        """
1868        Test parsing a delete request.
1869        """
1870
1871        xml = """
1872        <iq type='set' to='pubsub.example.org'
1873                       from='user@example.org'>
1874          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1875            <delete node='test'/>
1876          </pubsub>
1877        </iq>
1878        """
1879
1880        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1881        self.assertEqual('delete', request.verb)
1882        self.assertEqual(JID('user@example.org'), request.sender)
1883        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1884        self.assertEqual('test', request.nodeIdentifier)
1885
1886
1887
1888class PubSubServiceTest(unittest.TestCase, TestableRequestHandlerMixin):
1889    """
1890    Tests for L{pubsub.PubSubService}.
1891    """
1892
1893    def setUp(self):
1894        self.stub = XmlStreamStub()
1895        self.resource = pubsub.PubSubResource()
1896        self.service = pubsub.PubSubService(self.resource)
1897        self.service.send = self.stub.xmlstream.send
1898
1899    def test_interface(self):
1900        """
1901        Do instances of L{pubsub.PubSubService} provide L{iwokkel.IPubSubService}?
1902        """
1903        verify.verifyObject(iwokkel.IPubSubService, self.service)
1904
1905
1906    def test_connectionMade(self):
1907        """
1908        Verify setup of observers in L{pubsub.connectionMade}.
1909        """
1910        requests = []
1911
1912        def handleRequest(iq):
1913            requests.append(iq)
1914
1915        self.service.xmlstream = self.stub.xmlstream
1916        self.service.handleRequest = handleRequest
1917        self.service.connectionMade()
1918
1919        for namespace in (NS_PUBSUB, NS_PUBSUB_OWNER):
1920            for stanzaType in ('get', 'set'):
1921                iq = domish.Element((None, 'iq'))
1922                iq['type'] = stanzaType
1923                iq.addElement((namespace, 'pubsub'))
1924                self.stub.xmlstream.dispatch(iq)
1925
1926        self.assertEqual(4, len(requests))
1927
1928
1929    def test_getDiscoInfo(self):
1930        """
1931        Test getDiscoInfo calls getNodeInfo and returns some minimal info.
1932        """
1933        def cb(info):
1934            discoInfo = disco.DiscoInfo()
1935            for item in info:
1936                discoInfo.append(item)
1937            self.assertIn(('pubsub', 'service'), discoInfo.identities)
1938            self.assertIn(disco.NS_DISCO_ITEMS, discoInfo.features)
1939
1940        d = self.service.getDiscoInfo(JID('user@example.org/home'),
1941                                      JID('pubsub.example.org'), '')
1942        d.addCallback(cb)
1943        return d
1944
1945
1946    def test_getDiscoInfoNodeType(self):
1947        """
1948        Test getDiscoInfo with node type.
1949        """
1950        def cb(info):
1951            discoInfo = disco.DiscoInfo()
1952            for item in info:
1953                discoInfo.append(item)
1954            self.assertIn(('pubsub', 'collection'), discoInfo.identities)
1955
1956        def getInfo(requestor, target, nodeIdentifier):
1957            return defer.succeed({'type': 'collection',
1958                                  'meta-data': {}})
1959
1960        self.resource.getInfo = getInfo
1961        d = self.service.getDiscoInfo(JID('user@example.org/home'),
1962                                      JID('pubsub.example.org'), '')
1963        d.addCallback(cb)
1964        return d
1965
1966
1967    def test_getDiscoInfoMetaData(self):
1968        """
1969        Test getDiscoInfo with returned meta data.
1970        """
1971        def cb(info):
1972            discoInfo = disco.DiscoInfo()
1973            for item in info:
1974                discoInfo.append(item)
1975
1976            self.assertIn(('pubsub', 'leaf'), discoInfo.identities)
1977            self.assertIn(NS_PUBSUB_META_DATA, discoInfo.extensions)
1978            form = discoInfo.extensions[NS_PUBSUB_META_DATA]
1979            self.assertIn('pubsub#node_type', form.fields)
1980
1981        def getInfo(requestor, target, nodeIdentifier):
1982            metaData = [{'var': 'pubsub#persist_items',
1983                         'label': 'Persist items to storage',
1984                         'value': True}]
1985            return defer.succeed({'type': 'leaf', 'meta-data': metaData})
1986
1987        self.resource.getInfo = getInfo
1988        d = self.service.getDiscoInfo(JID('user@example.org/home'),
1989                                      JID('pubsub.example.org'), '')
1990        d.addCallback(cb)
1991        return d
1992
1993
1994    def test_getDiscoInfoResourceFeatures(self):
1995        """
1996        Test getDiscoInfo with the resource features.
1997        """
1998        def cb(info):
1999            discoInfo = disco.DiscoInfo()
2000            for item in info:
2001                discoInfo.append(item)
2002            self.assertIn('http://jabber.org/protocol/pubsub#publish',
2003                          discoInfo.features)
2004
2005        self.resource.features = ['publish']
2006        d = self.service.getDiscoInfo(JID('user@example.org/home'),
2007                                      JID('pubsub.example.org'), '')
2008        d.addCallback(cb)
2009        return d
2010
2011
2012    def test_getDiscoItemsRoot(self):
2013        """
2014        Test getDiscoItems on the root node.
2015        """
2016        def getNodes(requestor, service, nodeIdentifier):
2017            return defer.succeed(['node1', 'node2'])
2018
2019        def cb(items):
2020            self.assertEqual(2, len(items))
2021            item1, item2 = items
2022
2023            self.assertEqual(JID('pubsub.example.org'), item1.entity)
2024            self.assertEqual('node1', item1.nodeIdentifier)
2025
2026            self.assertEqual(JID('pubsub.example.org'), item2.entity)
2027            self.assertEqual('node2', item2.nodeIdentifier)
2028
2029        self.resource.getNodes = getNodes
2030        d = self.service.getDiscoItems(JID('user@example.org/home'),
2031                                       JID('pubsub.example.org'),
2032                                       '')
2033        d.addCallback(cb)
2034        return d
2035
2036
2037    def test_getDiscoItemsRootHideNodes(self):
2038        """
2039        Test getDiscoItems on the root node.
2040        """
2041        def getNodes(requestor, service, nodeIdentifier):
2042            raise Exception("Unexpected call to getNodes")
2043
2044        def cb(items):
2045            self.assertEqual([], items)
2046
2047        self.service.hideNodes = True
2048        self.resource.getNodes = getNodes
2049        d = self.service.getDiscoItems(JID('user@example.org/home'),
2050                                       JID('pubsub.example.org'),
2051                                       '')
2052        d.addCallback(cb)
2053        return d
2054
2055
2056    def test_getDiscoItemsNonRoot(self):
2057        """
2058        Test getDiscoItems on a non-root node.
2059        """
2060        def getNodes(requestor, service, nodeIdentifier):
2061            return defer.succeed(['node1', 'node2'])
2062
2063        def cb(items):
2064            self.assertEqual(2, len(items))
2065
2066        self.resource.getNodes = getNodes
2067        d = self.service.getDiscoItems(JID('user@example.org/home'),
2068                                       JID('pubsub.example.org'),
2069                                       'test')
2070        d.addCallback(cb)
2071        return d
2072
2073
2074    def test_on_publish(self):
2075        """
2076        A publish request should result in L{PubSubService.publish} being
2077        called.
2078        """
2079
2080        xml = """
2081        <iq type='set' to='pubsub.example.org'
2082                       from='user@example.org'>
2083          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2084            <publish node='test'/>
2085          </pubsub>
2086        </iq>
2087        """
2088
2089        def publish(request):
2090            return defer.succeed(None)
2091
2092        self.resource.publish = publish
2093        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2094        return self.handleRequest(xml)
2095
2096
2097    def test_on_subscribe(self):
2098        """
2099        A successful subscription should return the current subscription.
2100        """
2101
2102        xml = """
2103        <iq type='set' to='pubsub.example.org'
2104                       from='user@example.org'>
2105          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2106            <subscribe node='test' jid='user@example.org/Home'/>
2107          </pubsub>
2108        </iq>
2109        """
2110
2111        def subscribe(request):
2112            return defer.succeed(pubsub.Subscription(request.nodeIdentifier,
2113                                                     request.subscriber,
2114                                                     'subscribed'))
2115
2116        def cb(element):
2117            self.assertEqual('pubsub', element.name)
2118            self.assertEqual(NS_PUBSUB, element.uri)
2119            subscription = element.subscription
2120            self.assertIn(subscription.uri, (None, NS_PUBSUB))
2121            self.assertEqual('test', subscription['node'])
2122            self.assertEqual('user@example.org/Home', subscription['jid'])
2123            self.assertEqual('subscribed', subscription['subscription'])
2124
2125        self.resource.subscribe = subscribe
2126        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2127        d = self.handleRequest(xml)
2128        d.addCallback(cb)
2129        return d
2130
2131
2132    def test_on_subscribeEmptyNode(self):
2133        """
2134        A successful subscription on root node should return no node attribute.
2135        """
2136
2137        xml = """
2138        <iq type='set' to='pubsub.example.org'
2139                       from='user@example.org'>
2140          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2141            <subscribe jid='user@example.org/Home'/>
2142          </pubsub>
2143        </iq>
2144        """
2145
2146        def subscribe(request):
2147            return defer.succeed(pubsub.Subscription(request.nodeIdentifier,
2148                                                     request.subscriber,
2149                                                     'subscribed'))
2150
2151        def cb(element):
2152            self.assertFalse(element.subscription.hasAttribute('node'))
2153
2154        self.resource.subscribe = subscribe
2155        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2156        d = self.handleRequest(xml)
2157        d.addCallback(cb)
2158        return d
2159
2160
2161    def test_on_subscribeSubscriptionIdentifier(self):
2162        """
2163        If a subscription returns a subid, this should be available.
2164        """
2165
2166        xml = """
2167        <iq type='set' to='pubsub.example.org'
2168                       from='user@example.org'>
2169          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2170            <subscribe node='test' jid='user@example.org/Home'/>
2171          </pubsub>
2172        </iq>
2173        """
2174
2175        def subscribe(request):
2176            subscription = pubsub.Subscription(request.nodeIdentifier,
2177                                               request.subscriber,
2178                                               'subscribed',
2179                                               subscriptionIdentifier='1234')
2180            return defer.succeed(subscription)
2181
2182        def cb(element):
2183            self.assertEqual('1234', element.subscription.getAttribute('subid'))
2184
2185        self.resource.subscribe = subscribe
2186        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2187        d = self.handleRequest(xml)
2188        d.addCallback(cb)
2189        return d
2190
2191
2192    def test_on_unsubscribe(self):
2193        """
2194        A successful unsubscription should return an empty response.
2195        """
2196
2197        xml = """
2198        <iq type='set' to='pubsub.example.org'
2199                       from='user@example.org'>
2200          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2201            <unsubscribe node='test' jid='user@example.org/Home'/>
2202          </pubsub>
2203        </iq>
2204        """
2205
2206        def unsubscribe(request):
2207            return defer.succeed(None)
2208
2209        def cb(element):
2210            self.assertIdentical(None, element)
2211
2212        self.resource.unsubscribe = unsubscribe
2213        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2214        d = self.handleRequest(xml)
2215        d.addCallback(cb)
2216        return d
2217
2218
2219    def test_on_unsubscribe(self):
2220        """
2221        A successful unsubscription with subid should return an empty response.
2222        """
2223
2224        xml = """
2225        <iq type='set' to='pubsub.example.org'
2226                       from='user@example.org'>
2227          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2228            <unsubscribe node='test' jid='user@example.org/Home' subid='1234'/>
2229          </pubsub>
2230        </iq>
2231        """
2232
2233        def unsubscribe(request):
2234            self.assertEqual('1234', request.subscriptionIdentifier)
2235            return defer.succeed(None)
2236
2237        def cb(element):
2238            self.assertIdentical(None, element)
2239
2240        self.resource.unsubscribe = unsubscribe
2241        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2242        d = self.handleRequest(xml)
2243        d.addCallback(cb)
2244        return d
2245
2246
2247    def test_on_optionsGet(self):
2248        """
2249        Getting subscription options is not supported.
2250        """
2251
2252        xml = """
2253        <iq type='get' to='pubsub.example.org'
2254                       from='user@example.org'>
2255          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2256            <options node='test' jid='user@example.org/Home'/>
2257          </pubsub>
2258        </iq>
2259        """
2260
2261        def cb(result):
2262            self.assertEquals('feature-not-implemented', result.condition)
2263            self.assertEquals('unsupported', result.appCondition.name)
2264            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
2265
2266        d = self.handleRequest(xml)
2267        self.assertFailure(d, error.StanzaError)
2268        d.addCallback(cb)
2269        return d
2270
2271
2272    def test_on_optionsSet(self):
2273        """
2274        Setting subscription options is not supported.
2275        """
2276
2277        xml = """
2278        <iq type='set' to='pubsub.example.org'
2279                       from='user@example.org'>
2280          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2281            <options node='test' jid='user@example.org/Home'>
2282              <x xmlns='jabber:x:data' type='submit'>
2283                <field var='FORM_TYPE' type='hidden'>
2284                  <value>http://jabber.org/protocol/pubsub#subscribe_options</value>
2285                </field>
2286                <field var='pubsub#deliver'><value>1</value></field>
2287              </x>
2288            </options>
2289          </pubsub>
2290        </iq>
2291        """
2292
2293        def cb(result):
2294            self.assertEquals('feature-not-implemented', result.condition)
2295            self.assertEquals('unsupported', result.appCondition.name)
2296            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
2297
2298        d = self.handleRequest(xml)
2299        self.assertFailure(d, error.StanzaError)
2300        d.addCallback(cb)
2301        return d
2302
2303
2304    def test_on_subscriptions(self):
2305        """
2306        A subscriptions request should result in
2307        L{PubSubService.subscriptions} being called and the result prepared
2308        for the response.
2309        """
2310
2311        xml = """
2312        <iq type='get' to='pubsub.example.org'
2313                       from='user@example.org'>
2314          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2315            <subscriptions/>
2316          </pubsub>
2317        </iq>
2318        """
2319
2320        def subscriptions(request):
2321            subscription = pubsub.Subscription('test', JID('user@example.org'),
2322                                               'subscribed')
2323            return defer.succeed([subscription])
2324
2325        def cb(element):
2326            self.assertEqual('pubsub', element.name)
2327            self.assertEqual(NS_PUBSUB, element.uri)
2328            self.assertEqual(NS_PUBSUB, element.subscriptions.uri)
2329            children = list(element.subscriptions.elements())
2330            self.assertEqual(1, len(children))
2331            subscription = children[0]
2332            self.assertEqual('subscription', subscription.name)
2333            self.assertIn(subscription.uri, (None, NS_PUBSUB))
2334            self.assertEqual('user@example.org', subscription['jid'])
2335            self.assertEqual('test', subscription['node'])
2336            self.assertEqual('subscribed', subscription['subscription'])
2337
2338        self.resource.subscriptions = subscriptions
2339        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2340        d = self.handleRequest(xml)
2341        d.addCallback(cb)
2342        return d
2343
2344
2345    def test_on_subscriptionsWithSubscriptionIdentifier(self):
2346        """
2347        A subscriptions request response should include subids, if set.
2348        """
2349
2350        xml = """
2351        <iq type='get' to='pubsub.example.org'
2352                       from='user@example.org'>
2353          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2354            <subscriptions/>
2355          </pubsub>
2356        </iq>
2357        """
2358
2359        def subscriptions(request):
2360            subscription = pubsub.Subscription('test', JID('user@example.org'),
2361                                               'subscribed',
2362                                               subscriptionIdentifier='1234')
2363            return defer.succeed([subscription])
2364
2365        def cb(element):
2366            subscription = element.subscriptions.subscription
2367            self.assertEqual('1234', subscription['subid'])
2368
2369        self.resource.subscriptions = subscriptions
2370        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2371        d = self.handleRequest(xml)
2372        d.addCallback(cb)
2373        return d
2374
2375
2376    def test_on_affiliations(self):
2377        """
2378        A subscriptions request should result in
2379        L{PubSubService.affiliations} being called and the result prepared
2380        for the response.
2381        """
2382
2383        xml = """
2384        <iq type='get' to='pubsub.example.org'
2385                       from='user@example.org'>
2386          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2387            <affiliations/>
2388          </pubsub>
2389        </iq>
2390        """
2391
2392        def affiliations(request):
2393            affiliation = ('test', 'owner')
2394            return defer.succeed([affiliation])
2395
2396        def cb(element):
2397            self.assertEqual('pubsub', element.name)
2398            self.assertEqual(NS_PUBSUB, element.uri)
2399            self.assertEqual(NS_PUBSUB, element.affiliations.uri)
2400            children = list(element.affiliations.elements())
2401            self.assertEqual(1, len(children))
2402            affiliation = children[0]
2403            self.assertEqual('affiliation', affiliation.name)
2404            self.assertEqual(NS_PUBSUB, affiliation.uri)
2405            self.assertEqual('test', affiliation['node'])
2406            self.assertEqual('owner', affiliation['affiliation'])
2407
2408        self.resource.affiliations = affiliations
2409        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2410        d = self.handleRequest(xml)
2411        d.addCallback(cb)
2412        return d
2413
2414
2415    def test_on_create(self):
2416        """
2417        Replies to create node requests don't return the created node.
2418        """
2419
2420        xml = """
2421        <iq type='set' to='pubsub.example.org'
2422                       from='user@example.org'>
2423          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2424            <create node='mynode'/>
2425          </pubsub>
2426        </iq>
2427        """
2428
2429        def create(request):
2430            return defer.succeed(request.nodeIdentifier)
2431
2432        def cb(element):
2433            self.assertIdentical(None, element)
2434
2435        self.resource.create = create
2436        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2437        d = self.handleRequest(xml)
2438        d.addCallback(cb)
2439        return d
2440
2441
2442    def test_on_createChanged(self):
2443        """
2444        Replies to create node requests return the created node if changed.
2445        """
2446
2447        xml = """
2448        <iq type='set' to='pubsub.example.org'
2449                       from='user@example.org'>
2450          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2451            <create node='mynode'/>
2452          </pubsub>
2453        </iq>
2454        """
2455
2456        def create(request):
2457            return defer.succeed(u'myrenamednode')
2458
2459        def cb(element):
2460            self.assertEqual('pubsub', element.name)
2461            self.assertEqual(NS_PUBSUB, element.uri)
2462            self.assertEqual(NS_PUBSUB, element.create.uri)
2463            self.assertEqual(u'myrenamednode',
2464                             element.create.getAttribute('node'))
2465
2466        self.resource.create = create
2467        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2468        d = self.handleRequest(xml)
2469        d.addCallback(cb)
2470        return d
2471
2472
2473    def test_on_createInstant(self):
2474        """
2475        Replies to create instant node requests return the created node.
2476        """
2477
2478        xml = """
2479        <iq type='set' to='pubsub.example.org'
2480                       from='user@example.org'>
2481          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2482            <create/>
2483          </pubsub>
2484        </iq>
2485        """
2486
2487        def create(request):
2488            return defer.succeed(u'random')
2489
2490        def cb(element):
2491            self.assertEqual('pubsub', element.name)
2492            self.assertEqual(NS_PUBSUB, element.uri)
2493            self.assertEqual(NS_PUBSUB, element.create.uri)
2494            self.assertEqual(u'random', element.create.getAttribute('node'))
2495
2496        self.resource.create = create
2497        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2498        d = self.handleRequest(xml)
2499        d.addCallback(cb)
2500        return d
2501
2502
2503    def test_on_createWithConfig(self):
2504        """
2505        On a node create with configuration request the Data Form is parsed and
2506        L{PubSubResource.create} is called with the passed options.
2507        """
2508
2509        xml = """
2510        <iq type='set' to='pubsub.example.org'
2511                       from='user@example.org'>
2512          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2513            <create node='mynode'/>
2514            <configure>
2515              <x xmlns='jabber:x:data' type='submit'>
2516                <field var='FORM_TYPE' type='hidden'>
2517                  <value>http://jabber.org/protocol/pubsub#node_config</value>
2518                </field>
2519                <field var='pubsub#deliver_payloads'><value>0</value></field>
2520                <field var='pubsub#persist_items'><value>1</value></field>
2521              </x>
2522            </configure>
2523          </pubsub>
2524        </iq>
2525        """
2526
2527        def getConfigurationOptions():
2528            return {
2529                "pubsub#persist_items":
2530                    {"type": "boolean",
2531                     "label": "Persist items to storage"},
2532                "pubsub#deliver_payloads":
2533                    {"type": "boolean",
2534                     "label": "Deliver payloads with event notifications"}
2535                }
2536
2537        def create(request):
2538            self.assertEqual({'pubsub#deliver_payloads': False,
2539                              'pubsub#persist_items': True},
2540                             request.options.getValues())
2541            return defer.succeed(None)
2542
2543        self.resource.getConfigurationOptions = getConfigurationOptions
2544        self.resource.create = create
2545        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2546        return self.handleRequest(xml)
2547
2548
2549    def test_on_default(self):
2550        """
2551        A default request should result in
2552        L{PubSubService.getDefaultConfiguration} being called.
2553        """
2554
2555        xml = """
2556        <iq type='get' to='pubsub.example.org'
2557                       from='user@example.org'>
2558          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2559            <default/>
2560          </pubsub>
2561        </iq>
2562        """
2563
2564        def getConfigurationOptions():
2565            return {
2566                "pubsub#persist_items":
2567                    {"type": "boolean",
2568                     "label": "Persist items to storage"},
2569                "pubsub#deliver_payloads":
2570                    {"type": "boolean",
2571                     "label": "Deliver payloads with event notifications"}
2572                }
2573
2574        def default(request):
2575            return defer.succeed({})
2576
2577        def cb(element):
2578            self.assertEqual('pubsub', element.name)
2579            self.assertEqual(NS_PUBSUB_OWNER, element.uri)
2580            self.assertEqual(NS_PUBSUB_OWNER, element.default.uri)
2581            form = data_form.Form.fromElement(element.default.x)
2582            self.assertEqual(NS_PUBSUB_NODE_CONFIG, form.formNamespace)
2583
2584        self.resource.getConfigurationOptions = getConfigurationOptions
2585        self.resource.default = default
2586        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2587        d = self.handleRequest(xml)
2588        d.addCallback(cb)
2589        return d
2590
2591
2592    def test_on_defaultCollection(self):
2593        """
2594        Responses to default requests should depend on passed node type.
2595        """
2596
2597        xml = """
2598        <iq type='get' to='pubsub.example.org'
2599                       from='user@example.org'>
2600          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2601            <default>
2602              <x xmlns='jabber:x:data' type='submit'>
2603                <field var='FORM_TYPE' type='hidden'>
2604                  <value>http://jabber.org/protocol/pubsub#node_config</value>
2605                </field>
2606                <field var='pubsub#node_type'>
2607                  <value>collection</value>
2608                </field>
2609              </x>
2610            </default>
2611
2612          </pubsub>
2613        </iq>
2614        """
2615
2616        def getConfigurationOptions():
2617            return {
2618                "pubsub#deliver_payloads":
2619                    {"type": "boolean",
2620                     "label": "Deliver payloads with event notifications"}
2621                }
2622
2623        def default(request):
2624            return defer.succeed({})
2625
2626        self.resource.getConfigurationOptions = getConfigurationOptions
2627        self.resource.default = default
2628        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2629        return self.handleRequest(xml)
2630
2631
2632    def test_on_defaultUnknownNodeType(self):
2633        """
2634        A default request should result in
2635        L{PubSubResource.default} being called.
2636        """
2637
2638        xml = """
2639        <iq type='get' to='pubsub.example.org'
2640                       from='user@example.org'>
2641          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2642            <default>
2643              <x xmlns='jabber:x:data' type='submit'>
2644                <field var='FORM_TYPE' type='hidden'>
2645                  <value>http://jabber.org/protocol/pubsub#node_config</value>
2646                </field>
2647                <field var='pubsub#node_type'>
2648                  <value>unknown</value>
2649                </field>
2650              </x>
2651            </default>
2652
2653          </pubsub>
2654        </iq>
2655        """
2656
2657        def default(request):
2658            self.fail("Unexpected call to getConfiguration")
2659
2660        def cb(result):
2661            self.assertEquals('not-acceptable', result.condition)
2662
2663        self.resource.default = default
2664        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2665        d = self.handleRequest(xml)
2666        self.assertFailure(d, error.StanzaError)
2667        d.addCallback(cb)
2668        return d
2669
2670
2671    def test_on_configureGet(self):
2672        """
2673        On a node configuration get
2674        requestL{PubSubResource.configureGet} is called and results in a
2675        data form with the configuration.
2676        """
2677
2678        xml = """
2679        <iq type='get' to='pubsub.example.org'
2680                       from='user@example.org'>
2681          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2682            <configure node='test'/>
2683          </pubsub>
2684        </iq>
2685        """
2686
2687        def getConfigurationOptions():
2688            return {
2689                "pubsub#persist_items":
2690                    {"type": "boolean",
2691                     "label": "Persist items to storage"},
2692                "pubsub#deliver_payloads":
2693                    {"type": "boolean",
2694                     "label": "Deliver payloads with event notifications"},
2695                "pubsub#owner":
2696                    {"type": "jid-single",
2697                     "label": "Owner of the node"}
2698                }
2699
2700        def configureGet(request):
2701            return defer.succeed({'pubsub#deliver_payloads': '0',
2702                                  'pubsub#persist_items': '1',
2703                                  'pubsub#owner': JID('user@example.org'),
2704                                  'x-myfield': 'a'})
2705
2706        def cb(element):
2707            self.assertEqual('pubsub', element.name)
2708            self.assertEqual(NS_PUBSUB_OWNER, element.uri)
2709            self.assertEqual(NS_PUBSUB_OWNER, element.configure.uri)
2710            form = data_form.Form.fromElement(element.configure.x)
2711            self.assertEqual(NS_PUBSUB_NODE_CONFIG, form.formNamespace)
2712            fields = form.fields
2713
2714            self.assertIn('pubsub#deliver_payloads', fields)
2715            field = fields['pubsub#deliver_payloads']
2716            self.assertEqual('boolean', field.fieldType)
2717            field.typeCheck()
2718            self.assertEqual(False, field.value)
2719
2720            self.assertIn('pubsub#persist_items', fields)
2721            field = fields['pubsub#persist_items']
2722            self.assertEqual('boolean', field.fieldType)
2723            field.typeCheck()
2724            self.assertEqual(True, field.value)
2725
2726            self.assertIn('pubsub#owner', fields)
2727            field = fields['pubsub#owner']
2728            self.assertEqual('jid-single', field.fieldType)
2729            field.typeCheck()
2730            self.assertEqual(JID('user@example.org'), field.value)
2731
2732            self.assertNotIn('x-myfield', fields)
2733
2734        self.resource.getConfigurationOptions = getConfigurationOptions
2735        self.resource.configureGet = configureGet
2736        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2737        d = self.handleRequest(xml)
2738        d.addCallback(cb)
2739        return d
2740
2741
2742    def test_on_configureSet(self):
2743        """
2744        On a node configuration set request the Data Form is parsed and
2745        L{PubSubResource.configureSet} is called with the passed options.
2746        """
2747
2748        xml = """
2749        <iq type='set' to='pubsub.example.org'
2750                       from='user@example.org'>
2751          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2752            <configure node='test'>
2753              <x xmlns='jabber:x:data' type='submit'>
2754                <field var='FORM_TYPE' type='hidden'>
2755                  <value>http://jabber.org/protocol/pubsub#node_config</value>
2756                </field>
2757                <field var='pubsub#deliver_payloads'><value>0</value></field>
2758                <field var='pubsub#persist_items'><value>1</value></field>
2759              </x>
2760            </configure>
2761          </pubsub>
2762        </iq>
2763        """
2764
2765        def getConfigurationOptions():
2766            return {
2767                "pubsub#persist_items":
2768                    {"type": "boolean",
2769                     "label": "Persist items to storage"},
2770                "pubsub#deliver_payloads":
2771                    {"type": "boolean",
2772                     "label": "Deliver payloads with event notifications"}
2773                }
2774
2775        def configureSet(request):
2776            self.assertEqual({'pubsub#deliver_payloads': False,
2777                              'pubsub#persist_items': True},
2778                             request.options.getValues())
2779            return defer.succeed(None)
2780
2781        self.resource.getConfigurationOptions = getConfigurationOptions
2782        self.resource.configureSet = configureSet
2783        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2784        return self.handleRequest(xml)
2785
2786
2787    def test_on_configureSetCancel(self):
2788        """
2789        The node configuration is cancelled,
2790        L{PubSubResource.configureSet} not called.
2791        """
2792
2793        xml = """
2794        <iq type='set' to='pubsub.example.org'
2795                       from='user@example.org'>
2796          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2797            <configure node='test'>
2798              <x xmlns='jabber:x:data' type='cancel'>
2799                <field var='FORM_TYPE' type='hidden'>
2800                  <value>http://jabber.org/protocol/pubsub#node_config</value>
2801                </field>
2802              </x>
2803            </configure>
2804          </pubsub>
2805        </iq>
2806        """
2807
2808        def configureSet(request):
2809            self.fail("Unexpected call to setConfiguration")
2810
2811        self.resource.configureSet = configureSet
2812        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2813        return self.handleRequest(xml)
2814
2815
2816    def test_on_configureSetIgnoreUnknown(self):
2817        """
2818        On a node configuration set request unknown fields should be ignored.
2819        """
2820
2821        xml = """
2822        <iq type='set' to='pubsub.example.org'
2823                       from='user@example.org'>
2824          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2825            <configure node='test'>
2826              <x xmlns='jabber:x:data' type='submit'>
2827                <field var='FORM_TYPE' type='hidden'>
2828                  <value>http://jabber.org/protocol/pubsub#node_config</value>
2829                </field>
2830                <field var='pubsub#deliver_payloads'><value>0</value></field>
2831                <field var='x-myfield'><value>1</value></field>
2832              </x>
2833            </configure>
2834          </pubsub>
2835        </iq>
2836        """
2837
2838        def getConfigurationOptions():
2839            return {
2840                "pubsub#persist_items":
2841                    {"type": "boolean",
2842                     "label": "Persist items to storage"},
2843                "pubsub#deliver_payloads":
2844                    {"type": "boolean",
2845                     "label": "Deliver payloads with event notifications"}
2846                }
2847
2848        def configureSet(request):
2849            self.assertEquals(['pubsub#deliver_payloads'],
2850                              request.options.fields.keys())
2851
2852        self.resource.getConfigurationOptions = getConfigurationOptions
2853        self.resource.configureSet = configureSet
2854        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2855        return self.handleRequest(xml)
2856
2857
2858    def test_on_configureSetBadFormType(self):
2859        """
2860        On a node configuration set request unknown fields should be ignored.
2861        """
2862
2863        xml = """
2864        <iq type='set' to='pubsub.example.org'
2865                       from='user@example.org'>
2866          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2867            <configure node='test'>
2868              <x xmlns='jabber:x:data' type='result'>
2869                <field var='FORM_TYPE' type='hidden'>
2870                  <value>http://jabber.org/protocol/pubsub#node_config</value>
2871                </field>
2872                <field var='pubsub#deliver_payloads'><value>0</value></field>
2873                <field var='x-myfield'><value>1</value></field>
2874              </x>
2875            </configure>
2876          </pubsub>
2877        </iq>
2878        """
2879
2880        def cb(result):
2881            self.assertEquals('bad-request', result.condition)
2882            self.assertEqual("Unexpected form type 'result'", result.text)
2883
2884        d = self.handleRequest(xml)
2885        self.assertFailure(d, error.StanzaError)
2886        d.addCallback(cb)
2887        return d
2888
2889
2890    def test_on_items(self):
2891        """
2892        On a items request, return all items for the given node.
2893        """
2894        xml = """
2895        <iq type='get' to='pubsub.example.org'
2896                       from='user@example.org'>
2897          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2898            <items node='test'/>
2899          </pubsub>
2900        </iq>
2901        """
2902
2903        def items(request):
2904            return defer.succeed([pubsub.Item('current')])
2905
2906        def cb(element):
2907            self.assertEqual(NS_PUBSUB, element.uri)
2908            self.assertEqual(NS_PUBSUB, element.items.uri)
2909            self.assertEqual(1, len(element.items.children))
2910            item = element.items.children[-1]
2911            self.assertTrue(domish.IElement.providedBy(item))
2912            self.assertEqual('item', item.name)
2913            self.assertIn(item.uri, (NS_PUBSUB, None))
2914            self.assertEqual('current', item['id'])
2915
2916        self.resource.items = items
2917        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2918        d = self.handleRequest(xml)
2919        d.addCallback(cb)
2920        return d
2921
2922
2923    def test_on_retract(self):
2924        """
2925        A retract request should result in L{PubSubResource.retract}
2926        being called.
2927        """
2928
2929        xml = """
2930        <iq type='set' to='pubsub.example.org'
2931                       from='user@example.org'>
2932          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2933            <retract node='test'>
2934              <item id='item1'/>
2935              <item id='item2'/>
2936            </retract>
2937          </pubsub>
2938        </iq>
2939        """
2940
2941        def retract(request):
2942            return defer.succeed(None)
2943
2944        self.resource.retract = retract
2945        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2946        return self.handleRequest(xml)
2947
2948
2949    def test_on_purge(self):
2950        """
2951        A purge request should result in L{PubSubResource.purge} being
2952        called.
2953        """
2954
2955        xml = """
2956        <iq type='set' to='pubsub.example.org'
2957                       from='user@example.org'>
2958          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2959            <purge node='test'/>
2960          </pubsub>
2961        </iq>
2962        """
2963
2964        def purge(request):
2965            return defer.succeed(None)
2966
2967        self.resource.purge = purge
2968        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2969        return self.handleRequest(xml)
2970
2971
2972    def test_on_delete(self):
2973        """
2974        A delete request should result in L{PubSubResource.delete} being
2975        called.
2976        """
2977
2978        xml = """
2979        <iq type='set' to='pubsub.example.org'
2980                       from='user@example.org'>
2981          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2982            <delete node='test'/>
2983          </pubsub>
2984        </iq>
2985        """
2986
2987        def delete(request):
2988            return defer.succeed(None)
2989
2990        self.resource.delete = delete
2991        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2992        return self.handleRequest(xml)
2993
2994
2995    def test_notifyDelete(self):
2996        """
2997        Subscribers should be sent a delete notification.
2998        """
2999        subscriptions = [JID('user@example.org')]
3000        self.service.notifyDelete(JID('pubsub.example.org'), 'test',
3001                                  subscriptions)
3002        message = self.stub.output[-1]
3003
3004        self.assertEquals('message', message.name)
3005        self.assertIdentical(None, message.uri)
3006        self.assertEquals('user@example.org', message['to'])
3007        self.assertEquals('pubsub.example.org', message['from'])
3008        self.assertTrue(message.event)
3009        self.assertEqual(NS_PUBSUB_EVENT, message.event.uri)
3010        self.assertTrue(message.event.delete)
3011        self.assertEqual(NS_PUBSUB_EVENT, message.event.delete.uri)
3012        self.assertTrue(message.event.delete.hasAttribute('node'))
3013        self.assertEqual('test', message.event.delete['node'])
3014
3015
3016    def test_notifyDeleteRedirect(self):
3017        """
3018        Subscribers should be sent a delete notification with redirect.
3019        """
3020        redirectURI = 'xmpp:pubsub.example.org?;node=test2'
3021        subscriptions = [JID('user@example.org')]
3022        self.service.notifyDelete(JID('pubsub.example.org'), 'test',
3023                                  subscriptions, redirectURI)
3024        message = self.stub.output[-1]
3025
3026        self.assertEquals('message', message.name)
3027        self.assertIdentical(None, message.uri)
3028        self.assertEquals('user@example.org', message['to'])
3029        self.assertEquals('pubsub.example.org', message['from'])
3030        self.assertTrue(message.event)
3031        self.assertEqual(NS_PUBSUB_EVENT, message.event.uri)
3032        self.assertTrue(message.event.delete)
3033        self.assertEqual(NS_PUBSUB_EVENT, message.event.delete.uri)
3034        self.assertTrue(message.event.delete.hasAttribute('node'))
3035        self.assertEqual('test', message.event.delete['node'])
3036        self.assertTrue(message.event.delete.redirect)
3037        self.assertEqual(NS_PUBSUB_EVENT, message.event.delete.redirect.uri)
3038        self.assertTrue(message.event.delete.redirect.hasAttribute('uri'))
3039        self.assertEqual(redirectURI, message.event.delete.redirect['uri'])
3040
3041
3042    def test_on_subscriptionsGet(self):
3043        """
3044        Getting subscription options is not supported.
3045        """
3046
3047        xml = """
3048        <iq type='get' to='pubsub.example.org'
3049                       from='user@example.org'>
3050          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3051            <subscriptions/>
3052          </pubsub>
3053        </iq>
3054        """
3055
3056        def cb(result):
3057            self.assertEquals('feature-not-implemented', result.condition)
3058            self.assertEquals('unsupported', result.appCondition.name)
3059            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3060            self.assertEquals('manage-subscriptions',
3061                              result.appCondition['feature'])
3062
3063        d = self.handleRequest(xml)
3064        self.assertFailure(d, error.StanzaError)
3065        d.addCallback(cb)
3066        return d
3067
3068
3069    def test_on_subscriptionsSet(self):
3070        """
3071        Setting subscription options is not supported.
3072        """
3073
3074        xml = """
3075        <iq type='set' to='pubsub.example.org'
3076                       from='user@example.org'>
3077          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3078            <subscriptions/>
3079          </pubsub>
3080        </iq>
3081        """
3082
3083        def cb(result):
3084            self.assertEquals('feature-not-implemented', result.condition)
3085            self.assertEquals('unsupported', result.appCondition.name)
3086            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3087            self.assertEquals('manage-subscriptions',
3088                              result.appCondition['feature'])
3089
3090        d = self.handleRequest(xml)
3091        self.assertFailure(d, error.StanzaError)
3092        d.addCallback(cb)
3093        return d
3094
3095
3096    def test_on_affiliationsGet(self):
3097        """
3098        Getting subscription options is not supported.
3099        """
3100
3101        xml = """
3102        <iq type='get' to='pubsub.example.org'
3103                       from='user@example.org'>
3104          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3105            <affiliations/>
3106          </pubsub>
3107        </iq>
3108        """
3109
3110        def cb(result):
3111            self.assertEquals('feature-not-implemented', result.condition)
3112            self.assertEquals('unsupported', result.appCondition.name)
3113            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3114            self.assertEquals('modify-affiliations',
3115                              result.appCondition['feature'])
3116
3117        d = self.handleRequest(xml)
3118        self.assertFailure(d, error.StanzaError)
3119        d.addCallback(cb)
3120        return d
3121
3122
3123    def test_on_affiliationsSet(self):
3124        """
3125        Setting subscription options is not supported.
3126        """
3127
3128        xml = """
3129        <iq type='set' to='pubsub.example.org'
3130                       from='user@example.org'>
3131          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3132            <affiliations/>
3133          </pubsub>
3134        </iq>
3135        """
3136
3137        def cb(result):
3138            self.assertEquals('feature-not-implemented', result.condition)
3139            self.assertEquals('unsupported', result.appCondition.name)
3140            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3141            self.assertEquals('modify-affiliations',
3142                              result.appCondition['feature'])
3143
3144        d = self.handleRequest(xml)
3145        self.assertFailure(d, error.StanzaError)
3146        d.addCallback(cb)
3147        return d
3148
3149
3150
3151class PubSubServiceWithoutResourceTest(unittest.TestCase, TestableRequestHandlerMixin):
3152
3153    def setUp(self):
3154        self.stub = XmlStreamStub()
3155        self.service = pubsub.PubSubService()
3156        self.service.send = self.stub.xmlstream.send
3157
3158
3159    def test_getDiscoInfo(self):
3160        """
3161        Test getDiscoInfo calls getNodeInfo and returns some minimal info.
3162        """
3163        def cb(info):
3164            discoInfo = disco.DiscoInfo()
3165            for item in info:
3166                discoInfo.append(item)
3167            self.assertIn(('pubsub', 'service'), discoInfo.identities)
3168            self.assertIn(disco.NS_DISCO_ITEMS, discoInfo.features)
3169
3170        d = self.service.getDiscoInfo(JID('user@example.org/home'),
3171                                      JID('pubsub.example.org'), '')
3172        d.addCallback(cb)
3173        return d
3174
3175
3176    def test_publish(self):
3177        """
3178        Non-overridden L{PubSubService.publish} yields unsupported error.
3179        """
3180
3181        xml = """
3182        <iq type='set' to='pubsub.example.org'
3183                       from='user@example.org'>
3184          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3185            <publish node='mynode'/>
3186          </pubsub>
3187        </iq>
3188        """
3189
3190        def cb(result):
3191            self.assertEquals('feature-not-implemented', result.condition)
3192            self.assertEquals('unsupported', result.appCondition.name)
3193            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3194            self.assertEquals('publish', result.appCondition['feature'])
3195
3196        d = self.handleRequest(xml)
3197        self.assertFailure(d, error.StanzaError)
3198        d.addCallback(cb)
3199        return d
3200
3201
3202    def test_subscribe(self):
3203        """
3204        Non-overridden L{PubSubService.subscribe} yields unsupported error.
3205        """
3206
3207        xml = """
3208        <iq type='set' to='pubsub.example.org'
3209                       from='user@example.org'>
3210          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3211            <subscribe node='test' jid='user@example.org/Home'/>
3212          </pubsub>
3213        </iq>
3214        """
3215
3216        def cb(result):
3217            self.assertEquals('feature-not-implemented', result.condition)
3218            self.assertEquals('unsupported', result.appCondition.name)
3219            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3220            self.assertEquals('subscribe', result.appCondition['feature'])
3221
3222        d = self.handleRequest(xml)
3223        self.assertFailure(d, error.StanzaError)
3224        d.addCallback(cb)
3225        return d
3226
3227
3228    def test_unsubscribe(self):
3229        """
3230        Non-overridden L{PubSubService.unsubscribe} yields unsupported error.
3231        """
3232
3233        xml = """
3234        <iq type='set' to='pubsub.example.org'
3235                       from='user@example.org'>
3236          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3237            <unsubscribe node='test' jid='user@example.org/Home'/>
3238          </pubsub>
3239        </iq>
3240        """
3241
3242        def cb(result):
3243            self.assertEquals('feature-not-implemented', result.condition)
3244            self.assertEquals('unsupported', result.appCondition.name)
3245            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3246            self.assertEquals('subscribe', result.appCondition['feature'])
3247
3248        d = self.handleRequest(xml)
3249        self.assertFailure(d, error.StanzaError)
3250        d.addCallback(cb)
3251        return d
3252
3253
3254    def test_subscriptions(self):
3255        """
3256        Non-overridden L{PubSubService.subscriptions} yields unsupported error.
3257        """
3258
3259        xml = """
3260        <iq type='get' to='pubsub.example.org'
3261                       from='user@example.org'>
3262          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3263            <subscriptions/>
3264          </pubsub>
3265        </iq>
3266        """
3267
3268        def cb(result):
3269            self.assertEquals('feature-not-implemented', result.condition)
3270            self.assertEquals('unsupported', result.appCondition.name)
3271            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3272            self.assertEquals('retrieve-subscriptions',
3273                              result.appCondition['feature'])
3274
3275        d = self.handleRequest(xml)
3276        self.assertFailure(d, error.StanzaError)
3277        d.addCallback(cb)
3278        return d
3279
3280
3281    def test_affiliations(self):
3282        """
3283        Non-overridden L{PubSubService.affiliations} yields unsupported error.
3284        """
3285
3286        xml = """
3287        <iq type='get' to='pubsub.example.org'
3288                       from='user@example.org'>
3289          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3290            <affiliations/>
3291          </pubsub>
3292        </iq>
3293        """
3294
3295        def cb(result):
3296            self.assertEquals('feature-not-implemented', result.condition)
3297            self.assertEquals('unsupported', result.appCondition.name)
3298            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3299            self.assertEquals('retrieve-affiliations',
3300                              result.appCondition['feature'])
3301
3302        d = self.handleRequest(xml)
3303        self.assertFailure(d, error.StanzaError)
3304        d.addCallback(cb)
3305        return d
3306
3307
3308    def test_create(self):
3309        """
3310        Non-overridden L{PubSubService.create} yields unsupported error.
3311        """
3312
3313        xml = """
3314        <iq type='set' to='pubsub.example.org'
3315                       from='user@example.org'>
3316          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3317            <create node='mynode'/>
3318          </pubsub>
3319        </iq>
3320        """
3321
3322        def cb(result):
3323            self.assertEquals('feature-not-implemented', result.condition)
3324            self.assertEquals('unsupported', result.appCondition.name)
3325            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3326            self.assertEquals('create-nodes', result.appCondition['feature'])
3327
3328        d = self.handleRequest(xml)
3329        self.assertFailure(d, error.StanzaError)
3330        d.addCallback(cb)
3331        return d
3332
3333
3334    def test_getDefaultConfiguration(self):
3335        """
3336        Non-overridden L{PubSubService.getDefaultConfiguration} yields
3337        unsupported error.
3338        """
3339
3340        xml = """
3341        <iq type='get' to='pubsub.example.org'
3342                       from='user@example.org'>
3343          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3344            <default/>
3345          </pubsub>
3346        </iq>
3347        """
3348
3349        def cb(result):
3350            self.assertEquals('feature-not-implemented', result.condition)
3351            self.assertEquals('unsupported', result.appCondition.name)
3352            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3353            self.assertEquals('retrieve-default', result.appCondition['feature'])
3354
3355        d = self.handleRequest(xml)
3356        self.assertFailure(d, error.StanzaError)
3357        d.addCallback(cb)
3358        return d
3359
3360
3361    def test_getConfiguration(self):
3362        """
3363        Non-overridden L{PubSubService.getConfiguration} yields unsupported
3364        error.
3365        """
3366
3367        xml = """
3368        <iq type='get' to='pubsub.example.org'
3369                       from='user@example.org'>
3370          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3371            <configure/>
3372          </pubsub>
3373        </iq>
3374        """
3375
3376        def cb(result):
3377            self.assertEquals('feature-not-implemented', result.condition)
3378            self.assertEquals('unsupported', result.appCondition.name)
3379            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3380            self.assertEquals('config-node', result.appCondition['feature'])
3381
3382        d = self.handleRequest(xml)
3383        self.assertFailure(d, error.StanzaError)
3384        d.addCallback(cb)
3385        return d
3386
3387
3388    def test_setConfiguration(self):
3389        """
3390        Non-overridden L{PubSubService.setConfiguration} yields unsupported
3391        error.
3392        """
3393
3394        xml = """
3395        <iq type='set' to='pubsub.example.org'
3396                       from='user@example.org'>
3397          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3398            <configure node='test'>
3399              <x xmlns='jabber:x:data' type='submit'>
3400                <field var='FORM_TYPE' type='hidden'>
3401                  <value>http://jabber.org/protocol/pubsub#node_config</value>
3402                </field>
3403                <field var='pubsub#deliver_payloads'><value>0</value></field>
3404                <field var='pubsub#persist_items'><value>1</value></field>
3405              </x>
3406            </configure>
3407          </pubsub>
3408        </iq>
3409        """
3410
3411        def cb(result):
3412            self.assertEquals('feature-not-implemented', result.condition)
3413            self.assertEquals('unsupported', result.appCondition.name)
3414            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3415            self.assertEquals('config-node', result.appCondition['feature'])
3416
3417        d = self.handleRequest(xml)
3418        self.assertFailure(d, error.StanzaError)
3419        d.addCallback(cb)
3420        return d
3421
3422
3423    def test_setConfigurationOptionsDict(self):
3424        """
3425        Options should be passed as a dictionary, not a form.
3426        """
3427
3428        xml = """
3429        <iq type='set' to='pubsub.example.org'
3430                       from='user@example.org'>
3431          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3432            <configure node='test'>
3433              <x xmlns='jabber:x:data' type='submit'>
3434                <field var='FORM_TYPE' type='hidden'>
3435                  <value>http://jabber.org/protocol/pubsub#node_config</value>
3436                </field>
3437                <field var='pubsub#deliver_payloads'><value>0</value></field>
3438                <field var='pubsub#persist_items'><value>1</value></field>
3439              </x>
3440            </configure>
3441          </pubsub>
3442        </iq>
3443        """
3444
3445        def getConfigurationOptions():
3446            return {
3447                "pubsub#persist_items":
3448                    {"type": "boolean",
3449                     "label": "Persist items to storage"},
3450                "pubsub#deliver_payloads":
3451                    {"type": "boolean",
3452                     "label": "Deliver payloads with event notifications"}
3453                }
3454
3455        def setConfiguration(requestor, service, nodeIdentifier, options):
3456            self.assertEquals({'pubsub#deliver_payloads': False,
3457                               'pubsub#persist_items': True}, options)
3458
3459
3460        self.service.getConfigurationOptions = getConfigurationOptions
3461        self.service.setConfiguration = setConfiguration
3462        return self.handleRequest(xml)
3463
3464
3465    def test_items(self):
3466        """
3467        Non-overridden L{PubSubService.items} yields unsupported error.
3468        """
3469        xml = """
3470        <iq type='get' to='pubsub.example.org'
3471                       from='user@example.org'>
3472          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3473            <items node='test'/>
3474          </pubsub>
3475        </iq>
3476        """
3477
3478        def cb(result):
3479            self.assertEquals('feature-not-implemented', result.condition)
3480            self.assertEquals('unsupported', result.appCondition.name)
3481            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3482            self.assertEquals('retrieve-items', result.appCondition['feature'])
3483
3484        d = self.handleRequest(xml)
3485        self.assertFailure(d, error.StanzaError)
3486        d.addCallback(cb)
3487        return d
3488
3489
3490    def test_retract(self):
3491        """
3492        Non-overridden L{PubSubService.retract} yields unsupported error.
3493        """
3494        xml = """
3495        <iq type='set' to='pubsub.example.org'
3496                       from='user@example.org'>
3497          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3498            <retract node='test'>
3499              <item id='item1'/>
3500              <item id='item2'/>
3501            </retract>
3502          </pubsub>
3503        </iq>
3504        """
3505
3506        def cb(result):
3507            self.assertEquals('feature-not-implemented', result.condition)
3508            self.assertEquals('unsupported', result.appCondition.name)
3509            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3510            self.assertEquals('retract-items', result.appCondition['feature'])
3511
3512        d = self.handleRequest(xml)
3513        self.assertFailure(d, error.StanzaError)
3514        d.addCallback(cb)
3515        return d
3516
3517
3518    def test_purge(self):
3519        """
3520        Non-overridden L{PubSubService.purge} yields unsupported error.
3521        """
3522        xml = """
3523        <iq type='set' to='pubsub.example.org'
3524                       from='user@example.org'>
3525          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3526            <purge node='test'/>
3527          </pubsub>
3528        </iq>
3529        """
3530
3531        def cb(result):
3532            self.assertEquals('feature-not-implemented', result.condition)
3533            self.assertEquals('unsupported', result.appCondition.name)
3534            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3535            self.assertEquals('purge-nodes', result.appCondition['feature'])
3536
3537        d = self.handleRequest(xml)
3538        self.assertFailure(d, error.StanzaError)
3539        d.addCallback(cb)
3540        return d
3541
3542
3543    def test_delete(self):
3544        """
3545        Non-overridden L{PubSubService.delete} yields unsupported error.
3546        """
3547        xml = """
3548        <iq type='set' to='pubsub.example.org'
3549                       from='user@example.org'>
3550          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3551            <delete node='test'/>
3552          </pubsub>
3553        </iq>
3554        """
3555
3556        def cb(result):
3557            self.assertEquals('feature-not-implemented', result.condition)
3558            self.assertEquals('unsupported', result.appCondition.name)
3559            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3560            self.assertEquals('delete-nodes', result.appCondition['feature'])
3561
3562        d = self.handleRequest(xml)
3563        self.assertFailure(d, error.StanzaError)
3564        d.addCallback(cb)
3565        return d
3566
3567
3568
3569class PubSubResourceTest(unittest.TestCase):
3570
3571    def setUp(self):
3572        self.resource = pubsub.PubSubResource()
3573
3574
3575    def test_interface(self):
3576        """
3577        Do instances of L{pubsub.PubSubResource} provide L{iwokkel.IPubSubResource}?
3578        """
3579        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
3580
3581
3582    def test_getNodes(self):
3583        """
3584        Default getNodes returns an empty list.
3585        """
3586        def cb(nodes):
3587            self.assertEquals([], nodes)
3588
3589        d = self.resource.getNodes(JID('user@example.org/home'),
3590                                   JID('pubsub.example.org'),
3591                                   '')
3592        d.addCallback(cb)
3593        return d
3594
3595
3596    def test_publish(self):
3597        """
3598        Non-overridden L{PubSubResource.publish} yields unsupported
3599        error.
3600        """
3601
3602        def cb(result):
3603            self.assertEquals('feature-not-implemented', result.condition)
3604            self.assertEquals('unsupported', result.appCondition.name)
3605            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3606            self.assertEquals('publish', result.appCondition['feature'])
3607
3608        d = self.resource.publish(pubsub.PubSubRequest())
3609        self.assertFailure(d, error.StanzaError)
3610        d.addCallback(cb)
3611        return d
3612
3613
3614    def test_subscribe(self):
3615        """
3616        Non-overridden subscriptions yields unsupported error.
3617        """
3618
3619        def cb(result):
3620            self.assertEquals('feature-not-implemented', result.condition)
3621            self.assertEquals('unsupported', result.appCondition.name)
3622            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3623            self.assertEquals('subscribe', result.appCondition['feature'])
3624
3625        d = self.resource.subscribe(pubsub.PubSubRequest())
3626        self.assertFailure(d, error.StanzaError)
3627        d.addCallback(cb)
3628        return d
3629
3630
3631    def test_unsubscribe(self):
3632        """
3633        Non-overridden unsubscribe yields unsupported error.
3634        """
3635
3636        def cb(result):
3637            self.assertEquals('feature-not-implemented', result.condition)
3638            self.assertEquals('unsupported', result.appCondition.name)
3639            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3640            self.assertEquals('subscribe', result.appCondition['feature'])
3641
3642        d = self.resource.unsubscribe(pubsub.PubSubRequest())
3643        self.assertFailure(d, error.StanzaError)
3644        d.addCallback(cb)
3645        return d
3646
3647
3648    def test_subscriptions(self):
3649        """
3650        Non-overridden subscriptions yields unsupported error.
3651        """
3652
3653        def cb(result):
3654            self.assertEquals('feature-not-implemented', result.condition)
3655            self.assertEquals('unsupported', result.appCondition.name)
3656            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3657            self.assertEquals('retrieve-subscriptions',
3658                              result.appCondition['feature'])
3659
3660        d = self.resource.subscriptions(pubsub.PubSubRequest())
3661        self.assertFailure(d, error.StanzaError)
3662        d.addCallback(cb)
3663        return d
3664
3665
3666    def test_affiliations(self):
3667        """
3668        Non-overridden affiliations yields unsupported error.
3669        """
3670
3671        def cb(result):
3672            self.assertEquals('feature-not-implemented', result.condition)
3673            self.assertEquals('unsupported', result.appCondition.name)
3674            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3675            self.assertEquals('retrieve-affiliations',
3676                              result.appCondition['feature'])
3677
3678        d = self.resource.affiliations(pubsub.PubSubRequest())
3679        self.assertFailure(d, error.StanzaError)
3680        d.addCallback(cb)
3681        return d
3682
3683
3684    def test_create(self):
3685        """
3686        Non-overridden create yields unsupported error.
3687        """
3688
3689        def cb(result):
3690            self.assertEquals('feature-not-implemented', result.condition)
3691            self.assertEquals('unsupported', result.appCondition.name)
3692            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3693            self.assertEquals('create-nodes', result.appCondition['feature'])
3694
3695        d = self.resource.create(pubsub.PubSubRequest())
3696        self.assertFailure(d, error.StanzaError)
3697        d.addCallback(cb)
3698        return d
3699
3700
3701    def test_default(self):
3702        """
3703        Non-overridden default yields unsupported error.
3704        """
3705
3706        def cb(result):
3707            self.assertEquals('feature-not-implemented', result.condition)
3708            self.assertEquals('unsupported', result.appCondition.name)
3709            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3710            self.assertEquals('retrieve-default',
3711                              result.appCondition['feature'])
3712
3713        d = self.resource.default(pubsub.PubSubRequest())
3714        self.assertFailure(d, error.StanzaError)
3715        d.addCallback(cb)
3716        return d
3717
3718
3719    def test_configureGet(self):
3720        """
3721        Non-overridden configureGet yields unsupported
3722        error.
3723        """
3724
3725        def cb(result):
3726            self.assertEquals('feature-not-implemented', result.condition)
3727            self.assertEquals('unsupported', result.appCondition.name)
3728            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3729            self.assertEquals('config-node', result.appCondition['feature'])
3730
3731        d = self.resource.configureGet(pubsub.PubSubRequest())
3732        self.assertFailure(d, error.StanzaError)
3733        d.addCallback(cb)
3734        return d
3735
3736
3737    def test_configureSet(self):
3738        """
3739        Non-overridden configureSet yields unsupported error.
3740        """
3741
3742        def cb(result):
3743            self.assertEquals('feature-not-implemented', result.condition)
3744            self.assertEquals('unsupported', result.appCondition.name)
3745            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3746            self.assertEquals('config-node', result.appCondition['feature'])
3747
3748        d = self.resource.configureSet(pubsub.PubSubRequest())
3749        self.assertFailure(d, error.StanzaError)
3750        d.addCallback(cb)
3751        return d
3752
3753
3754    def test_items(self):
3755        """
3756        Non-overridden items yields unsupported error.
3757        """
3758
3759        def cb(result):
3760            self.assertEquals('feature-not-implemented', result.condition)
3761            self.assertEquals('unsupported', result.appCondition.name)
3762            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3763            self.assertEquals('retrieve-items', result.appCondition['feature'])
3764
3765        d = self.resource.items(pubsub.PubSubRequest())
3766        self.assertFailure(d, error.StanzaError)
3767        d.addCallback(cb)
3768        return d
3769
3770
3771    def test_retract(self):
3772        """
3773        Non-overridden retract yields unsupported error.
3774        """
3775
3776        def cb(result):
3777            self.assertEquals('feature-not-implemented', result.condition)
3778            self.assertEquals('unsupported', result.appCondition.name)
3779            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3780            self.assertEquals('retract-items', result.appCondition['feature'])
3781
3782        d = self.resource.retract(pubsub.PubSubRequest())
3783        self.assertFailure(d, error.StanzaError)
3784        d.addCallback(cb)
3785        return d
3786
3787
3788    def test_purge(self):
3789        """
3790        Non-overridden purge yields unsupported error.
3791        """
3792
3793        def cb(result):
3794            self.assertEquals('feature-not-implemented', result.condition)
3795            self.assertEquals('unsupported', result.appCondition.name)
3796            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3797            self.assertEquals('purge-nodes', result.appCondition['feature'])
3798
3799        d = self.resource.purge(pubsub.PubSubRequest())
3800        self.assertFailure(d, error.StanzaError)
3801        d.addCallback(cb)
3802        return d
3803
3804
3805    def test_delete(self):
3806        """
3807        Non-overridden delete yields unsupported error.
3808        """
3809
3810        def cb(result):
3811            self.assertEquals('feature-not-implemented', result.condition)
3812            self.assertEquals('unsupported', result.appCondition.name)
3813            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3814            self.assertEquals('delete-nodes', result.appCondition['feature'])
3815
3816        d = self.resource.delete(pubsub.PubSubRequest())
3817        self.assertFailure(d, error.StanzaError)
3818        d.addCallback(cb)
3819        return d
Note: See TracBrowser for help on using the repository browser.