source: wokkel/test/test_pubsub.py @ 95:2d57501b5c68

Last change on this file since 95:2d57501b5c68 was 95:2d57501b5c68, checked in by Ralph Meijer <ralphm@…>, 9 years ago

Clean up some tests around retrieving default node configuration.

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