source: wokkel/test/test_pubsub.py @ 94:c0473c62802d

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

Catch KeyError? for unsupported verbs in legacy PubSubService? usage.

Author: ralphm.
Fixes: #70.

Because requests are now parsed by PubSubRequest?, it can happen that a request
is succesfully parsed, but there is no legacy handler available. This used
to raise a KeyError?, resulting in a internal-server-error being returned.
Now it returns a feature-not-implemented error.

File size: 137.7 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        Test parsing a request for the default node configuration.
1665        """
1666
1667        xml = """
1668        <iq type='get' to='pubsub.example.org'
1669                       from='user@example.org'>
1670          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1671            <default/>
1672          </pubsub>
1673        </iq>
1674        """
1675
1676        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1677        self.assertEqual('default', request.verb)
1678        self.assertEqual(JID('user@example.org'), request.sender)
1679        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1680        self.assertEqual('leaf', request.nodeType)
1681
1682
1683    def test_fromElementDefaultCollection(self):
1684        """
1685        Parsing a request for the default configuration extracts the node type.
1686        """
1687
1688        xml = """
1689        <iq type='get' to='pubsub.example.org'
1690                       from='user@example.org'>
1691          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1692            <default>
1693              <x xmlns='jabber:x:data' type='submit'>
1694                <field var='FORM_TYPE' type='hidden'>
1695                  <value>http://jabber.org/protocol/pubsub#node_config</value>
1696                </field>
1697                <field var='pubsub#node_type'>
1698                  <value>collection</value>
1699                </field>
1700              </x>
1701            </default>
1702
1703          </pubsub>
1704        </iq>
1705        """
1706
1707        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1708        self.assertEqual('collection', request.nodeType)
1709
1710
1711    def test_fromElementConfigureGet(self):
1712        """
1713        Test parsing a node configuration get request.
1714        """
1715
1716        xml = """
1717        <iq type='get' to='pubsub.example.org'
1718                       from='user@example.org'>
1719          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1720            <configure node='test'/>
1721          </pubsub>
1722        </iq>
1723        """
1724
1725        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1726        self.assertEqual('configureGet', request.verb)
1727        self.assertEqual(JID('user@example.org'), request.sender)
1728        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1729        self.assertEqual('test', request.nodeIdentifier)
1730
1731
1732    def test_fromElementConfigureSet(self):
1733        """
1734        On a node configuration set request the Data Form is parsed.
1735        """
1736
1737        xml = """
1738        <iq type='set' to='pubsub.example.org'
1739                       from='user@example.org'>
1740          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1741            <configure node='test'>
1742              <x xmlns='jabber:x:data' type='submit'>
1743                <field var='FORM_TYPE' type='hidden'>
1744                  <value>http://jabber.org/protocol/pubsub#node_config</value>
1745                </field>
1746                <field var='pubsub#deliver_payloads'><value>0</value></field>
1747                <field var='pubsub#persist_items'><value>1</value></field>
1748              </x>
1749            </configure>
1750          </pubsub>
1751        </iq>
1752        """
1753
1754        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1755        self.assertEqual('configureSet', request.verb)
1756        self.assertEqual(JID('user@example.org'), request.sender)
1757        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1758        self.assertEqual('test', request.nodeIdentifier)
1759        self.assertEqual({'pubsub#deliver_payloads': '0',
1760                          'pubsub#persist_items': '1'},
1761                         request.options.getValues())
1762
1763
1764    def test_fromElementConfigureSetCancel(self):
1765        """
1766        The node configuration is cancelled, so no options.
1767        """
1768
1769        xml = """
1770        <iq type='set' to='pubsub.example.org'
1771                       from='user@example.org'>
1772          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1773            <configure node='test'>
1774              <x xmlns='jabber:x:data' type='cancel'/>
1775            </configure>
1776          </pubsub>
1777        </iq>
1778        """
1779
1780        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1781        self.assertEqual('cancel', request.options.formType)
1782
1783
1784    def test_fromElementConfigureSetBadFormType(self):
1785        """
1786        The form of a node configuraton set request should have the right type.
1787        """
1788
1789        xml = """
1790        <iq type='set' to='pubsub.example.org'
1791                       from='user@example.org'>
1792          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1793            <configure node='test'>
1794              <x xmlns='jabber:x:data' type='result'>
1795                <field var='FORM_TYPE' type='hidden'>
1796                  <value>http://jabber.org/protocol/pubsub#node_config</value>
1797                </field>
1798                <field var='pubsub#deliver_payloads'><value>0</value></field>
1799                <field var='x-myfield'><value>1</value></field>
1800              </x>
1801            </configure>
1802          </pubsub>
1803        </iq>
1804        """
1805
1806        err = self.assertRaises(error.StanzaError,
1807                                pubsub.PubSubRequest.fromElement,
1808                                parseXml(xml))
1809        self.assertEqual('bad-request', err.condition)
1810        self.assertEqual("Unexpected form type 'result'", err.text)
1811        self.assertEqual(None, err.appCondition)
1812
1813
1814    def test_fromElementConfigureSetNoForm(self):
1815        """
1816        On a node configuration set request a form is required.
1817        """
1818
1819        xml = """
1820        <iq type='set' to='pubsub.example.org'
1821                       from='user@example.org'>
1822          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1823            <configure node='test'/>
1824          </pubsub>
1825        </iq>
1826        """
1827        err = self.assertRaises(error.StanzaError,
1828                                pubsub.PubSubRequest.fromElement,
1829                                parseXml(xml))
1830        self.assertEqual('bad-request', err.condition)
1831        self.assertEqual(None, err.appCondition)
1832
1833
1834    def test_fromElementItems(self):
1835        """
1836        Test parsing an items request.
1837        """
1838        xml = """
1839        <iq type='get' to='pubsub.example.org'
1840                       from='user@example.org'>
1841          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1842            <items node='test'/>
1843          </pubsub>
1844        </iq>
1845        """
1846
1847        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1848        self.assertEqual('items', request.verb)
1849        self.assertEqual(JID('user@example.org'), request.sender)
1850        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1851        self.assertEqual('test', request.nodeIdentifier)
1852        self.assertIdentical(None, request.maxItems)
1853        self.assertIdentical(None, request.subscriptionIdentifier)
1854        self.assertEqual([], request.itemIdentifiers)
1855
1856
1857    def test_fromElementItemsSubscriptionIdentifier(self):
1858        """
1859        Test parsing an items request with subscription identifier.
1860        """
1861        xml = """
1862        <iq type='get' to='pubsub.example.org'
1863                       from='user@example.org'>
1864          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1865            <items node='test' subid='1234'/>
1866          </pubsub>
1867        </iq>
1868        """
1869
1870        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1871        self.assertEqual('1234', request.subscriptionIdentifier)
1872
1873
1874    def test_fromElementRetract(self):
1875        """
1876        Test parsing a retract request.
1877        """
1878
1879        xml = """
1880        <iq type='set' to='pubsub.example.org'
1881                       from='user@example.org'>
1882          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
1883            <retract node='test'>
1884              <item id='item1'/>
1885              <item id='item2'/>
1886            </retract>
1887          </pubsub>
1888        </iq>
1889        """
1890
1891        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1892        self.assertEqual('retract', request.verb)
1893        self.assertEqual(JID('user@example.org'), request.sender)
1894        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1895        self.assertEqual('test', request.nodeIdentifier)
1896        self.assertEqual(['item1', 'item2'], request.itemIdentifiers)
1897
1898
1899    def test_fromElementPurge(self):
1900        """
1901        Test parsing a purge request.
1902        """
1903
1904        xml = """
1905        <iq type='set' to='pubsub.example.org'
1906                       from='user@example.org'>
1907          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1908            <purge node='test'/>
1909          </pubsub>
1910        </iq>
1911        """
1912
1913        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1914        self.assertEqual('purge', request.verb)
1915        self.assertEqual(JID('user@example.org'), request.sender)
1916        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1917        self.assertEqual('test', request.nodeIdentifier)
1918
1919
1920    def test_fromElementDelete(self):
1921        """
1922        Test parsing a delete request.
1923        """
1924
1925        xml = """
1926        <iq type='set' to='pubsub.example.org'
1927                       from='user@example.org'>
1928          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
1929            <delete node='test'/>
1930          </pubsub>
1931        </iq>
1932        """
1933
1934        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
1935        self.assertEqual('delete', request.verb)
1936        self.assertEqual(JID('user@example.org'), request.sender)
1937        self.assertEqual(JID('pubsub.example.org'), request.recipient)
1938        self.assertEqual('test', request.nodeIdentifier)
1939
1940
1941
1942class PubSubServiceTest(unittest.TestCase, TestableRequestHandlerMixin):
1943    """
1944    Tests for L{pubsub.PubSubService}.
1945    """
1946
1947    def setUp(self):
1948        self.stub = XmlStreamStub()
1949        self.resource = pubsub.PubSubResource()
1950        self.service = pubsub.PubSubService(self.resource)
1951        self.service.send = self.stub.xmlstream.send
1952
1953    def test_interface(self):
1954        """
1955        Do instances of L{pubsub.PubSubService} provide L{iwokkel.IPubSubService}?
1956        """
1957        verify.verifyObject(iwokkel.IPubSubService, self.service)
1958
1959
1960    def test_interfaceIDisco(self):
1961        """
1962        Do instances of L{pubsub.PubSubService} provide L{iwokkel.IDisco}?
1963        """
1964        verify.verifyObject(iwokkel.IDisco, self.service)
1965
1966
1967    def test_connectionMade(self):
1968        """
1969        Verify setup of observers in L{pubsub.connectionMade}.
1970        """
1971        requests = []
1972
1973        def handleRequest(iq):
1974            requests.append(iq)
1975
1976        self.service.xmlstream = self.stub.xmlstream
1977        self.service.handleRequest = handleRequest
1978        self.service.connectionMade()
1979
1980        for namespace in (NS_PUBSUB, NS_PUBSUB_OWNER):
1981            for stanzaType in ('get', 'set'):
1982                iq = domish.Element((None, 'iq'))
1983                iq['type'] = stanzaType
1984                iq.addElement((namespace, 'pubsub'))
1985                self.stub.xmlstream.dispatch(iq)
1986
1987        self.assertEqual(4, len(requests))
1988
1989
1990    def test_getDiscoInfo(self):
1991        """
1992        Test getDiscoInfo calls getNodeInfo and returns some minimal info.
1993        """
1994        def cb(info):
1995            discoInfo = disco.DiscoInfo()
1996            for item in info:
1997                discoInfo.append(item)
1998            self.assertIn(('pubsub', 'service'), discoInfo.identities)
1999            self.assertIn(disco.NS_DISCO_ITEMS, discoInfo.features)
2000
2001        d = self.service.getDiscoInfo(JID('user@example.org/home'),
2002                                      JID('pubsub.example.org'), '')
2003        d.addCallback(cb)
2004        return d
2005
2006
2007    def test_getDiscoInfoNodeType(self):
2008        """
2009        Test getDiscoInfo with node type.
2010        """
2011        def cb(info):
2012            discoInfo = disco.DiscoInfo()
2013            for item in info:
2014                discoInfo.append(item)
2015            self.assertIn(('pubsub', 'collection'), discoInfo.identities)
2016
2017        def getInfo(requestor, target, nodeIdentifier):
2018            return defer.succeed({'type': 'collection',
2019                                  'meta-data': {}})
2020
2021        self.resource.getInfo = getInfo
2022        d = self.service.getDiscoInfo(JID('user@example.org/home'),
2023                                      JID('pubsub.example.org'), '')
2024        d.addCallback(cb)
2025        return d
2026
2027
2028    def test_getDiscoInfoMetaData(self):
2029        """
2030        Test getDiscoInfo with returned meta data.
2031        """
2032        def cb(info):
2033            discoInfo = disco.DiscoInfo()
2034            for item in info:
2035                discoInfo.append(item)
2036
2037            self.assertIn(('pubsub', 'leaf'), discoInfo.identities)
2038            self.assertIn(NS_PUBSUB_META_DATA, discoInfo.extensions)
2039            form = discoInfo.extensions[NS_PUBSUB_META_DATA]
2040            self.assertIn('pubsub#node_type', form.fields)
2041
2042        def getInfo(requestor, target, nodeIdentifier):
2043            metaData = [{'var': 'pubsub#persist_items',
2044                         'label': 'Persist items to storage',
2045                         'value': True}]
2046            return defer.succeed({'type': 'leaf', 'meta-data': metaData})
2047
2048        self.resource.getInfo = getInfo
2049        d = self.service.getDiscoInfo(JID('user@example.org/home'),
2050                                      JID('pubsub.example.org'), '')
2051        d.addCallback(cb)
2052        return d
2053
2054
2055    def test_getDiscoInfoResourceFeatures(self):
2056        """
2057        Test getDiscoInfo with the resource features.
2058        """
2059        def cb(info):
2060            discoInfo = disco.DiscoInfo()
2061            for item in info:
2062                discoInfo.append(item)
2063            self.assertIn('http://jabber.org/protocol/pubsub#publish',
2064                          discoInfo.features)
2065
2066        self.resource.features = ['publish']
2067        d = self.service.getDiscoInfo(JID('user@example.org/home'),
2068                                      JID('pubsub.example.org'), '')
2069        d.addCallback(cb)
2070        return d
2071
2072
2073    def test_getDiscoInfoBadResponse(self):
2074        """
2075        If getInfo returns invalid response, it should be logged, then ignored.
2076        """
2077        def cb(info):
2078            self.assertEquals([], info)
2079            self.assertEqual(1, len(self.flushLoggedErrors(TypeError)))
2080
2081        def getInfo(requestor, target, nodeIdentifier):
2082            return defer.succeed('bad response')
2083
2084        self.resource.getInfo = getInfo
2085        d = self.service.getDiscoInfo(JID('user@example.org/home'),
2086                                      JID('pubsub.example.org'), 'test')
2087        d.addCallback(cb)
2088        return d
2089
2090
2091    def test_getDiscoInfoException(self):
2092        """
2093        If getInfo returns invalid response, it should be logged, then ignored.
2094        """
2095        def cb(info):
2096            self.assertEquals([], info)
2097            self.assertEqual(1, len(self.flushLoggedErrors(NotImplementedError)))
2098
2099        def getInfo(requestor, target, nodeIdentifier):
2100            return defer.fail(NotImplementedError())
2101
2102        self.resource.getInfo = getInfo
2103        d = self.service.getDiscoInfo(JID('user@example.org/home'),
2104                                      JID('pubsub.example.org'), 'test')
2105        d.addCallback(cb)
2106        return d
2107
2108
2109    def test_getDiscoItemsRoot(self):
2110        """
2111        Test getDiscoItems on the root node.
2112        """
2113        def getNodes(requestor, service, nodeIdentifier):
2114            return defer.succeed(['node1', 'node2'])
2115
2116        def cb(items):
2117            self.assertEqual(2, len(items))
2118            item1, item2 = items
2119
2120            self.assertEqual(JID('pubsub.example.org'), item1.entity)
2121            self.assertEqual('node1', item1.nodeIdentifier)
2122
2123            self.assertEqual(JID('pubsub.example.org'), item2.entity)
2124            self.assertEqual('node2', item2.nodeIdentifier)
2125
2126        self.resource.getNodes = getNodes
2127        d = self.service.getDiscoItems(JID('user@example.org/home'),
2128                                       JID('pubsub.example.org'),
2129                                       '')
2130        d.addCallback(cb)
2131        return d
2132
2133
2134    def test_getDiscoItemsRootHideNodes(self):
2135        """
2136        Test getDiscoItems on the root node.
2137        """
2138        def getNodes(requestor, service, nodeIdentifier):
2139            raise Exception("Unexpected call to getNodes")
2140
2141        def cb(items):
2142            self.assertEqual([], items)
2143
2144        self.service.hideNodes = True
2145        self.resource.getNodes = getNodes
2146        d = self.service.getDiscoItems(JID('user@example.org/home'),
2147                                       JID('pubsub.example.org'),
2148                                       '')
2149        d.addCallback(cb)
2150        return d
2151
2152
2153    def test_getDiscoItemsNonRoot(self):
2154        """
2155        Test getDiscoItems on a non-root node.
2156        """
2157        def getNodes(requestor, service, nodeIdentifier):
2158            return defer.succeed(['node1', 'node2'])
2159
2160        def cb(items):
2161            self.assertEqual(2, len(items))
2162
2163        self.resource.getNodes = getNodes
2164        d = self.service.getDiscoItems(JID('user@example.org/home'),
2165                                       JID('pubsub.example.org'),
2166                                       'test')
2167        d.addCallback(cb)
2168        return d
2169
2170
2171    def test_on_publish(self):
2172        """
2173        A publish request should result in L{PubSubService.publish} being
2174        called.
2175        """
2176
2177        xml = """
2178        <iq type='set' to='pubsub.example.org'
2179                       from='user@example.org'>
2180          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2181            <publish node='test'/>
2182          </pubsub>
2183        </iq>
2184        """
2185
2186        def publish(request):
2187            return defer.succeed(None)
2188
2189        self.resource.publish = publish
2190        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2191        return self.handleRequest(xml)
2192
2193
2194    def test_on_subscribe(self):
2195        """
2196        A successful subscription should return the current subscription.
2197        """
2198
2199        xml = """
2200        <iq type='set' to='pubsub.example.org'
2201                       from='user@example.org'>
2202          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2203            <subscribe node='test' jid='user@example.org/Home'/>
2204          </pubsub>
2205        </iq>
2206        """
2207
2208        def subscribe(request):
2209            return defer.succeed(pubsub.Subscription(request.nodeIdentifier,
2210                                                     request.subscriber,
2211                                                     'subscribed'))
2212
2213        def cb(element):
2214            self.assertEqual('pubsub', element.name)
2215            self.assertEqual(NS_PUBSUB, element.uri)
2216            subscription = element.subscription
2217            self.assertIn(subscription.uri, (None, NS_PUBSUB))
2218            self.assertEqual('test', subscription['node'])
2219            self.assertEqual('user@example.org/Home', subscription['jid'])
2220            self.assertEqual('subscribed', subscription['subscription'])
2221
2222        self.resource.subscribe = subscribe
2223        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2224        d = self.handleRequest(xml)
2225        d.addCallback(cb)
2226        return d
2227
2228
2229    def test_on_subscribeEmptyNode(self):
2230        """
2231        A successful subscription on root node should return no node attribute.
2232        """
2233
2234        xml = """
2235        <iq type='set' to='pubsub.example.org'
2236                       from='user@example.org'>
2237          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2238            <subscribe jid='user@example.org/Home'/>
2239          </pubsub>
2240        </iq>
2241        """
2242
2243        def subscribe(request):
2244            return defer.succeed(pubsub.Subscription(request.nodeIdentifier,
2245                                                     request.subscriber,
2246                                                     'subscribed'))
2247
2248        def cb(element):
2249            self.assertFalse(element.subscription.hasAttribute('node'))
2250
2251        self.resource.subscribe = subscribe
2252        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2253        d = self.handleRequest(xml)
2254        d.addCallback(cb)
2255        return d
2256
2257
2258    def test_on_subscribeSubscriptionIdentifier(self):
2259        """
2260        If a subscription returns a subid, this should be available.
2261        """
2262
2263        xml = """
2264        <iq type='set' to='pubsub.example.org'
2265                       from='user@example.org'>
2266          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2267            <subscribe node='test' jid='user@example.org/Home'/>
2268          </pubsub>
2269        </iq>
2270        """
2271
2272        def subscribe(request):
2273            subscription = pubsub.Subscription(request.nodeIdentifier,
2274                                               request.subscriber,
2275                                               'subscribed',
2276                                               subscriptionIdentifier='1234')
2277            return defer.succeed(subscription)
2278
2279        def cb(element):
2280            self.assertEqual('1234', element.subscription.getAttribute('subid'))
2281
2282        self.resource.subscribe = subscribe
2283        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2284        d = self.handleRequest(xml)
2285        d.addCallback(cb)
2286        return d
2287
2288
2289    def test_on_unsubscribe(self):
2290        """
2291        A successful unsubscription should return an empty response.
2292        """
2293
2294        xml = """
2295        <iq type='set' to='pubsub.example.org'
2296                       from='user@example.org'>
2297          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2298            <unsubscribe node='test' jid='user@example.org/Home'/>
2299          </pubsub>
2300        </iq>
2301        """
2302
2303        def unsubscribe(request):
2304            return defer.succeed(None)
2305
2306        def cb(element):
2307            self.assertIdentical(None, element)
2308
2309        self.resource.unsubscribe = unsubscribe
2310        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2311        d = self.handleRequest(xml)
2312        d.addCallback(cb)
2313        return d
2314
2315
2316    def test_on_unsubscribeSubscriptionIdentifier(self):
2317        """
2318        A successful unsubscription with subid should return an empty response.
2319        """
2320
2321        xml = """
2322        <iq type='set' to='pubsub.example.org'
2323                       from='user@example.org'>
2324          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2325            <unsubscribe node='test' jid='user@example.org/Home' subid='1234'/>
2326          </pubsub>
2327        </iq>
2328        """
2329
2330        def unsubscribe(request):
2331            self.assertEqual('1234', request.subscriptionIdentifier)
2332            return defer.succeed(None)
2333
2334        def cb(element):
2335            self.assertIdentical(None, element)
2336
2337        self.resource.unsubscribe = unsubscribe
2338        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2339        d = self.handleRequest(xml)
2340        d.addCallback(cb)
2341        return d
2342
2343
2344    def test_on_optionsGet(self):
2345        """
2346        Getting subscription options is not supported.
2347        """
2348
2349        xml = """
2350        <iq type='get' to='pubsub.example.org'
2351                       from='user@example.org'>
2352          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2353            <options node='test' jid='user@example.org/Home'/>
2354          </pubsub>
2355        </iq>
2356        """
2357
2358        def cb(result):
2359            self.assertEquals('feature-not-implemented', result.condition)
2360            self.assertEquals('unsupported', result.appCondition.name)
2361            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
2362
2363        d = self.handleRequest(xml)
2364        self.assertFailure(d, error.StanzaError)
2365        d.addCallback(cb)
2366        return d
2367
2368
2369    def test_on_optionsSet(self):
2370        """
2371        Setting subscription options is not supported.
2372        """
2373
2374        xml = """
2375        <iq type='set' to='pubsub.example.org'
2376                       from='user@example.org'>
2377          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2378            <options node='test' jid='user@example.org/Home'>
2379              <x xmlns='jabber:x:data' type='submit'>
2380                <field var='FORM_TYPE' type='hidden'>
2381                  <value>http://jabber.org/protocol/pubsub#subscribe_options</value>
2382                </field>
2383                <field var='pubsub#deliver'><value>1</value></field>
2384              </x>
2385            </options>
2386          </pubsub>
2387        </iq>
2388        """
2389
2390        def cb(result):
2391            self.assertEquals('feature-not-implemented', result.condition)
2392            self.assertEquals('unsupported', result.appCondition.name)
2393            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
2394
2395        d = self.handleRequest(xml)
2396        self.assertFailure(d, error.StanzaError)
2397        d.addCallback(cb)
2398        return d
2399
2400
2401    def test_on_subscriptions(self):
2402        """
2403        A subscriptions request should result in
2404        L{PubSubService.subscriptions} being called and the result prepared
2405        for the response.
2406        """
2407
2408        xml = """
2409        <iq type='get' to='pubsub.example.org'
2410                       from='user@example.org'>
2411          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2412            <subscriptions/>
2413          </pubsub>
2414        </iq>
2415        """
2416
2417        def subscriptions(request):
2418            subscription = pubsub.Subscription('test', JID('user@example.org'),
2419                                               'subscribed')
2420            return defer.succeed([subscription])
2421
2422        def cb(element):
2423            self.assertEqual('pubsub', element.name)
2424            self.assertEqual(NS_PUBSUB, element.uri)
2425            self.assertEqual(NS_PUBSUB, element.subscriptions.uri)
2426            children = list(element.subscriptions.elements())
2427            self.assertEqual(1, len(children))
2428            subscription = children[0]
2429            self.assertEqual('subscription', subscription.name)
2430            self.assertIn(subscription.uri, (None, NS_PUBSUB))
2431            self.assertEqual('user@example.org', subscription['jid'])
2432            self.assertEqual('test', subscription['node'])
2433            self.assertEqual('subscribed', subscription['subscription'])
2434
2435        self.resource.subscriptions = subscriptions
2436        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2437        d = self.handleRequest(xml)
2438        d.addCallback(cb)
2439        return d
2440
2441
2442    def test_on_subscriptionsWithSubscriptionIdentifier(self):
2443        """
2444        A subscriptions request response should include subids, if set.
2445        """
2446
2447        xml = """
2448        <iq type='get' to='pubsub.example.org'
2449                       from='user@example.org'>
2450          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2451            <subscriptions/>
2452          </pubsub>
2453        </iq>
2454        """
2455
2456        def subscriptions(request):
2457            subscription = pubsub.Subscription('test', JID('user@example.org'),
2458                                               'subscribed',
2459                                               subscriptionIdentifier='1234')
2460            return defer.succeed([subscription])
2461
2462        def cb(element):
2463            subscription = element.subscriptions.subscription
2464            self.assertEqual('1234', subscription['subid'])
2465
2466        self.resource.subscriptions = subscriptions
2467        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2468        d = self.handleRequest(xml)
2469        d.addCallback(cb)
2470        return d
2471
2472
2473    def test_on_affiliations(self):
2474        """
2475        A subscriptions request should result in
2476        L{PubSubService.affiliations} being called and the result prepared
2477        for the response.
2478        """
2479
2480        xml = """
2481        <iq type='get' to='pubsub.example.org'
2482                       from='user@example.org'>
2483          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2484            <affiliations/>
2485          </pubsub>
2486        </iq>
2487        """
2488
2489        def affiliations(request):
2490            affiliation = ('test', 'owner')
2491            return defer.succeed([affiliation])
2492
2493        def cb(element):
2494            self.assertEqual('pubsub', element.name)
2495            self.assertEqual(NS_PUBSUB, element.uri)
2496            self.assertEqual(NS_PUBSUB, element.affiliations.uri)
2497            children = list(element.affiliations.elements())
2498            self.assertEqual(1, len(children))
2499            affiliation = children[0]
2500            self.assertEqual('affiliation', affiliation.name)
2501            self.assertEqual(NS_PUBSUB, affiliation.uri)
2502            self.assertEqual('test', affiliation['node'])
2503            self.assertEqual('owner', affiliation['affiliation'])
2504
2505        self.resource.affiliations = affiliations
2506        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2507        d = self.handleRequest(xml)
2508        d.addCallback(cb)
2509        return d
2510
2511
2512    def test_on_create(self):
2513        """
2514        Replies to create node requests don't return the created node.
2515        """
2516
2517        xml = """
2518        <iq type='set' to='pubsub.example.org'
2519                       from='user@example.org'>
2520          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2521            <create node='mynode'/>
2522          </pubsub>
2523        </iq>
2524        """
2525
2526        def create(request):
2527            return defer.succeed(request.nodeIdentifier)
2528
2529        def cb(element):
2530            self.assertIdentical(None, element)
2531
2532        self.resource.create = create
2533        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2534        d = self.handleRequest(xml)
2535        d.addCallback(cb)
2536        return d
2537
2538
2539    def test_on_createChanged(self):
2540        """
2541        Replies to create node requests return the created node if changed.
2542        """
2543
2544        xml = """
2545        <iq type='set' to='pubsub.example.org'
2546                       from='user@example.org'>
2547          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2548            <create node='mynode'/>
2549          </pubsub>
2550        </iq>
2551        """
2552
2553        def create(request):
2554            return defer.succeed(u'myrenamednode')
2555
2556        def cb(element):
2557            self.assertEqual('pubsub', element.name)
2558            self.assertEqual(NS_PUBSUB, element.uri)
2559            self.assertEqual(NS_PUBSUB, element.create.uri)
2560            self.assertEqual(u'myrenamednode',
2561                             element.create.getAttribute('node'))
2562
2563        self.resource.create = create
2564        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2565        d = self.handleRequest(xml)
2566        d.addCallback(cb)
2567        return d
2568
2569
2570    def test_on_createInstant(self):
2571        """
2572        Replies to create instant node requests return the created node.
2573        """
2574
2575        xml = """
2576        <iq type='set' to='pubsub.example.org'
2577                       from='user@example.org'>
2578          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2579            <create/>
2580          </pubsub>
2581        </iq>
2582        """
2583
2584        def create(request):
2585            return defer.succeed(u'random')
2586
2587        def cb(element):
2588            self.assertEqual('pubsub', element.name)
2589            self.assertEqual(NS_PUBSUB, element.uri)
2590            self.assertEqual(NS_PUBSUB, element.create.uri)
2591            self.assertEqual(u'random', element.create.getAttribute('node'))
2592
2593        self.resource.create = create
2594        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2595        d = self.handleRequest(xml)
2596        d.addCallback(cb)
2597        return d
2598
2599
2600    def test_on_createWithConfig(self):
2601        """
2602        On a node create with configuration request the Data Form is parsed and
2603        L{PubSubResource.create} is called with the passed options.
2604        """
2605
2606        xml = """
2607        <iq type='set' to='pubsub.example.org'
2608                       from='user@example.org'>
2609          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2610            <create node='mynode'/>
2611            <configure>
2612              <x xmlns='jabber:x:data' type='submit'>
2613                <field var='FORM_TYPE' type='hidden'>
2614                  <value>http://jabber.org/protocol/pubsub#node_config</value>
2615                </field>
2616                <field var='pubsub#deliver_payloads'><value>0</value></field>
2617                <field var='pubsub#persist_items'><value>1</value></field>
2618              </x>
2619            </configure>
2620          </pubsub>
2621        </iq>
2622        """
2623
2624        def getConfigurationOptions():
2625            return {
2626                "pubsub#persist_items":
2627                    {"type": "boolean",
2628                     "label": "Persist items to storage"},
2629                "pubsub#deliver_payloads":
2630                    {"type": "boolean",
2631                     "label": "Deliver payloads with event notifications"}
2632                }
2633
2634        def create(request):
2635            self.assertEqual({'pubsub#deliver_payloads': False,
2636                              'pubsub#persist_items': True},
2637                             request.options.getValues())
2638            return defer.succeed(None)
2639
2640        self.resource.getConfigurationOptions = getConfigurationOptions
2641        self.resource.create = create
2642        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2643        return self.handleRequest(xml)
2644
2645
2646    def test_on_default(self):
2647        """
2648        A default request should result in
2649        L{PubSubService.getDefaultConfiguration} being called.
2650        """
2651
2652        xml = """
2653        <iq type='get' to='pubsub.example.org'
2654                       from='user@example.org'>
2655          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2656            <default/>
2657          </pubsub>
2658        </iq>
2659        """
2660
2661        def getConfigurationOptions():
2662            return {
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 default(request):
2672            return defer.succeed({})
2673
2674        def cb(element):
2675            self.assertEqual('pubsub', element.name)
2676            self.assertEqual(NS_PUBSUB_OWNER, element.uri)
2677            self.assertEqual(NS_PUBSUB_OWNER, element.default.uri)
2678            form = data_form.Form.fromElement(element.default.x)
2679            self.assertEqual(NS_PUBSUB_NODE_CONFIG, form.formNamespace)
2680
2681        self.resource.getConfigurationOptions = getConfigurationOptions
2682        self.resource.default = default
2683        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2684        d = self.handleRequest(xml)
2685        d.addCallback(cb)
2686        return d
2687
2688
2689    def test_on_defaultCollection(self):
2690        """
2691        Responses to default requests should depend on passed node type.
2692        """
2693
2694        xml = """
2695        <iq type='get' to='pubsub.example.org'
2696                       from='user@example.org'>
2697          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2698            <default>
2699              <x xmlns='jabber:x:data' type='submit'>
2700                <field var='FORM_TYPE' type='hidden'>
2701                  <value>http://jabber.org/protocol/pubsub#node_config</value>
2702                </field>
2703                <field var='pubsub#node_type'>
2704                  <value>collection</value>
2705                </field>
2706              </x>
2707            </default>
2708
2709          </pubsub>
2710        </iq>
2711        """
2712
2713        def getConfigurationOptions():
2714            return {
2715                "pubsub#deliver_payloads":
2716                    {"type": "boolean",
2717                     "label": "Deliver payloads with event notifications"}
2718                }
2719
2720        def default(request):
2721            return defer.succeed({})
2722
2723        self.resource.getConfigurationOptions = getConfigurationOptions
2724        self.resource.default = default
2725        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2726        return self.handleRequest(xml)
2727
2728
2729    def test_on_defaultUnknownNodeType(self):
2730        """
2731        A default request should result in
2732        L{PubSubResource.default} being called.
2733        """
2734
2735        xml = """
2736        <iq type='get' to='pubsub.example.org'
2737                       from='user@example.org'>
2738          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2739            <default>
2740              <x xmlns='jabber:x:data' type='submit'>
2741                <field var='FORM_TYPE' type='hidden'>
2742                  <value>http://jabber.org/protocol/pubsub#node_config</value>
2743                </field>
2744                <field var='pubsub#node_type'>
2745                  <value>unknown</value>
2746                </field>
2747              </x>
2748            </default>
2749
2750          </pubsub>
2751        </iq>
2752        """
2753
2754        def default(request):
2755            self.fail("Unexpected call to getConfiguration")
2756
2757        def cb(result):
2758            self.assertEquals('not-acceptable', result.condition)
2759
2760        self.resource.default = default
2761        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2762        d = self.handleRequest(xml)
2763        self.assertFailure(d, error.StanzaError)
2764        d.addCallback(cb)
2765        return d
2766
2767
2768    def test_on_configureGet(self):
2769        """
2770        On a node configuration get
2771        requestL{PubSubResource.configureGet} is called and results in a
2772        data form with the configuration.
2773        """
2774
2775        xml = """
2776        <iq type='get' to='pubsub.example.org'
2777                       from='user@example.org'>
2778          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2779            <configure node='test'/>
2780          </pubsub>
2781        </iq>
2782        """
2783
2784        def getConfigurationOptions():
2785            return {
2786                "pubsub#persist_items":
2787                    {"type": "boolean",
2788                     "label": "Persist items to storage"},
2789                "pubsub#deliver_payloads":
2790                    {"type": "boolean",
2791                     "label": "Deliver payloads with event notifications"},
2792                "pubsub#owner":
2793                    {"type": "jid-single",
2794                     "label": "Owner of the node"}
2795                }
2796
2797        def configureGet(request):
2798            return defer.succeed({'pubsub#deliver_payloads': '0',
2799                                  'pubsub#persist_items': '1',
2800                                  'pubsub#owner': JID('user@example.org'),
2801                                  'x-myfield': 'a'})
2802
2803        def cb(element):
2804            self.assertEqual('pubsub', element.name)
2805            self.assertEqual(NS_PUBSUB_OWNER, element.uri)
2806            self.assertEqual(NS_PUBSUB_OWNER, element.configure.uri)
2807            form = data_form.Form.fromElement(element.configure.x)
2808            self.assertEqual(NS_PUBSUB_NODE_CONFIG, form.formNamespace)
2809            fields = form.fields
2810
2811            self.assertIn('pubsub#deliver_payloads', fields)
2812            field = fields['pubsub#deliver_payloads']
2813            self.assertEqual('boolean', field.fieldType)
2814            field.typeCheck()
2815            self.assertEqual(False, field.value)
2816
2817            self.assertIn('pubsub#persist_items', fields)
2818            field = fields['pubsub#persist_items']
2819            self.assertEqual('boolean', field.fieldType)
2820            field.typeCheck()
2821            self.assertEqual(True, field.value)
2822
2823            self.assertIn('pubsub#owner', fields)
2824            field = fields['pubsub#owner']
2825            self.assertEqual('jid-single', field.fieldType)
2826            field.typeCheck()
2827            self.assertEqual(JID('user@example.org'), field.value)
2828
2829            self.assertNotIn('x-myfield', fields)
2830
2831        self.resource.getConfigurationOptions = getConfigurationOptions
2832        self.resource.configureGet = configureGet
2833        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2834        d = self.handleRequest(xml)
2835        d.addCallback(cb)
2836        return d
2837
2838
2839    def test_on_configureSet(self):
2840        """
2841        On a node configuration set request the Data Form is parsed and
2842        L{PubSubResource.configureSet} is called with the passed options.
2843        """
2844
2845        xml = """
2846        <iq type='set' to='pubsub.example.org'
2847                       from='user@example.org'>
2848          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2849            <configure node='test'>
2850              <x xmlns='jabber:x:data' type='submit'>
2851                <field var='FORM_TYPE' type='hidden'>
2852                  <value>http://jabber.org/protocol/pubsub#node_config</value>
2853                </field>
2854                <field var='pubsub#deliver_payloads'><value>0</value></field>
2855                <field var='pubsub#persist_items'><value>1</value></field>
2856              </x>
2857            </configure>
2858          </pubsub>
2859        </iq>
2860        """
2861
2862        def getConfigurationOptions():
2863            return {
2864                "pubsub#persist_items":
2865                    {"type": "boolean",
2866                     "label": "Persist items to storage"},
2867                "pubsub#deliver_payloads":
2868                    {"type": "boolean",
2869                     "label": "Deliver payloads with event notifications"}
2870                }
2871
2872        def configureSet(request):
2873            self.assertEqual({'pubsub#deliver_payloads': False,
2874                              'pubsub#persist_items': True},
2875                             request.options.getValues())
2876            return defer.succeed(None)
2877
2878        self.resource.getConfigurationOptions = getConfigurationOptions
2879        self.resource.configureSet = configureSet
2880        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2881        return self.handleRequest(xml)
2882
2883
2884    def test_on_configureSetCancel(self):
2885        """
2886        The node configuration is cancelled,
2887        L{PubSubResource.configureSet} not called.
2888        """
2889
2890        xml = """
2891        <iq type='set' to='pubsub.example.org'
2892                       from='user@example.org'>
2893          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2894            <configure node='test'>
2895              <x xmlns='jabber:x:data' type='cancel'>
2896                <field var='FORM_TYPE' type='hidden'>
2897                  <value>http://jabber.org/protocol/pubsub#node_config</value>
2898                </field>
2899              </x>
2900            </configure>
2901          </pubsub>
2902        </iq>
2903        """
2904
2905        def configureSet(request):
2906            self.fail("Unexpected call to setConfiguration")
2907
2908        self.resource.configureSet = configureSet
2909        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2910        return self.handleRequest(xml)
2911
2912
2913    def test_on_configureSetIgnoreUnknown(self):
2914        """
2915        On a node configuration set request unknown fields should be ignored.
2916        """
2917
2918        xml = """
2919        <iq type='set' to='pubsub.example.org'
2920                       from='user@example.org'>
2921          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2922            <configure node='test'>
2923              <x xmlns='jabber:x:data' type='submit'>
2924                <field var='FORM_TYPE' type='hidden'>
2925                  <value>http://jabber.org/protocol/pubsub#node_config</value>
2926                </field>
2927                <field var='pubsub#deliver_payloads'><value>0</value></field>
2928                <field var='x-myfield'><value>1</value></field>
2929              </x>
2930            </configure>
2931          </pubsub>
2932        </iq>
2933        """
2934
2935        def getConfigurationOptions():
2936            return {
2937                "pubsub#persist_items":
2938                    {"type": "boolean",
2939                     "label": "Persist items to storage"},
2940                "pubsub#deliver_payloads":
2941                    {"type": "boolean",
2942                     "label": "Deliver payloads with event notifications"}
2943                }
2944
2945        def configureSet(request):
2946            self.assertEquals(['pubsub#deliver_payloads'],
2947                              request.options.fields.keys())
2948
2949        self.resource.getConfigurationOptions = getConfigurationOptions
2950        self.resource.configureSet = configureSet
2951        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
2952        return self.handleRequest(xml)
2953
2954
2955    def test_on_configureSetBadFormType(self):
2956        """
2957        On a node configuration set request unknown fields should be ignored.
2958        """
2959
2960        xml = """
2961        <iq type='set' to='pubsub.example.org'
2962                       from='user@example.org'>
2963          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
2964            <configure node='test'>
2965              <x xmlns='jabber:x:data' type='result'>
2966                <field var='FORM_TYPE' type='hidden'>
2967                  <value>http://jabber.org/protocol/pubsub#node_config</value>
2968                </field>
2969                <field var='pubsub#deliver_payloads'><value>0</value></field>
2970                <field var='x-myfield'><value>1</value></field>
2971              </x>
2972            </configure>
2973          </pubsub>
2974        </iq>
2975        """
2976
2977        def cb(result):
2978            self.assertEquals('bad-request', result.condition)
2979            self.assertEqual("Unexpected form type 'result'", result.text)
2980
2981        d = self.handleRequest(xml)
2982        self.assertFailure(d, error.StanzaError)
2983        d.addCallback(cb)
2984        return d
2985
2986
2987    def test_on_items(self):
2988        """
2989        On a items request, return all items for the given node.
2990        """
2991        xml = """
2992        <iq type='get' to='pubsub.example.org'
2993                       from='user@example.org'>
2994          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
2995            <items node='test'/>
2996          </pubsub>
2997        </iq>
2998        """
2999
3000        def items(request):
3001            return defer.succeed([pubsub.Item('current')])
3002
3003        def cb(element):
3004            self.assertEqual(NS_PUBSUB, element.uri)
3005            self.assertEqual(NS_PUBSUB, element.items.uri)
3006            self.assertEqual(1, len(element.items.children))
3007            item = element.items.children[-1]
3008            self.assertTrue(domish.IElement.providedBy(item))
3009            self.assertEqual('item', item.name)
3010            self.assertIn(item.uri, (NS_PUBSUB, None))
3011            self.assertEqual('current', item['id'])
3012
3013        self.resource.items = items
3014        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
3015        d = self.handleRequest(xml)
3016        d.addCallback(cb)
3017        return d
3018
3019
3020    def test_on_retract(self):
3021        """
3022        A retract request should result in L{PubSubResource.retract}
3023        being called.
3024        """
3025
3026        xml = """
3027        <iq type='set' to='pubsub.example.org'
3028                       from='user@example.org'>
3029          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3030            <retract node='test'>
3031              <item id='item1'/>
3032              <item id='item2'/>
3033            </retract>
3034          </pubsub>
3035        </iq>
3036        """
3037
3038        def retract(request):
3039            return defer.succeed(None)
3040
3041        self.resource.retract = retract
3042        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
3043        return self.handleRequest(xml)
3044
3045
3046    def test_on_purge(self):
3047        """
3048        A purge request should result in L{PubSubResource.purge} being
3049        called.
3050        """
3051
3052        xml = """
3053        <iq type='set' to='pubsub.example.org'
3054                       from='user@example.org'>
3055          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3056            <purge node='test'/>
3057          </pubsub>
3058        </iq>
3059        """
3060
3061        def purge(request):
3062            return defer.succeed(None)
3063
3064        self.resource.purge = purge
3065        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
3066        return self.handleRequest(xml)
3067
3068
3069    def test_on_delete(self):
3070        """
3071        A delete request should result in L{PubSubResource.delete} being
3072        called.
3073        """
3074
3075        xml = """
3076        <iq type='set' to='pubsub.example.org'
3077                       from='user@example.org'>
3078          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3079            <delete node='test'/>
3080          </pubsub>
3081        </iq>
3082        """
3083
3084        def delete(request):
3085            return defer.succeed(None)
3086
3087        self.resource.delete = delete
3088        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
3089        return self.handleRequest(xml)
3090
3091
3092    def test_notifyDelete(self):
3093        """
3094        Subscribers should be sent a delete notification.
3095        """
3096        subscriptions = [JID('user@example.org')]
3097        self.service.notifyDelete(JID('pubsub.example.org'), 'test',
3098                                  subscriptions)
3099        message = self.stub.output[-1]
3100
3101        self.assertEquals('message', message.name)
3102        self.assertIdentical(None, message.uri)
3103        self.assertEquals('user@example.org', message['to'])
3104        self.assertEquals('pubsub.example.org', message['from'])
3105        self.assertTrue(message.event)
3106        self.assertEqual(NS_PUBSUB_EVENT, message.event.uri)
3107        self.assertTrue(message.event.delete)
3108        self.assertEqual(NS_PUBSUB_EVENT, message.event.delete.uri)
3109        self.assertTrue(message.event.delete.hasAttribute('node'))
3110        self.assertEqual('test', message.event.delete['node'])
3111
3112
3113    def test_notifyDeleteRedirect(self):
3114        """
3115        Subscribers should be sent a delete notification with redirect.
3116        """
3117        redirectURI = 'xmpp:pubsub.example.org?;node=test2'
3118        subscriptions = [JID('user@example.org')]
3119        self.service.notifyDelete(JID('pubsub.example.org'), 'test',
3120                                  subscriptions, redirectURI)
3121        message = self.stub.output[-1]
3122
3123        self.assertEquals('message', message.name)
3124        self.assertIdentical(None, message.uri)
3125        self.assertEquals('user@example.org', message['to'])
3126        self.assertEquals('pubsub.example.org', message['from'])
3127        self.assertTrue(message.event)
3128        self.assertEqual(NS_PUBSUB_EVENT, message.event.uri)
3129        self.assertTrue(message.event.delete)
3130        self.assertEqual(NS_PUBSUB_EVENT, message.event.delete.uri)
3131        self.assertTrue(message.event.delete.hasAttribute('node'))
3132        self.assertEqual('test', message.event.delete['node'])
3133        self.assertTrue(message.event.delete.redirect)
3134        self.assertEqual(NS_PUBSUB_EVENT, message.event.delete.redirect.uri)
3135        self.assertTrue(message.event.delete.redirect.hasAttribute('uri'))
3136        self.assertEqual(redirectURI, message.event.delete.redirect['uri'])
3137
3138
3139    def test_on_subscriptionsGet(self):
3140        """
3141        Getting subscription options is not supported.
3142        """
3143
3144        xml = """
3145        <iq type='get' 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_subscriptionsSet(self):
3167        """
3168        Setting subscription options is not supported.
3169        """
3170
3171        xml = """
3172        <iq type='set' to='pubsub.example.org'
3173                       from='user@example.org'>
3174          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3175            <subscriptions/>
3176          </pubsub>
3177        </iq>
3178        """
3179
3180        def cb(result):
3181            self.assertEquals('feature-not-implemented', result.condition)
3182            self.assertEquals('unsupported', result.appCondition.name)
3183            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3184            self.assertEquals('manage-subscriptions',
3185                              result.appCondition['feature'])
3186
3187        d = self.handleRequest(xml)
3188        self.assertFailure(d, error.StanzaError)
3189        d.addCallback(cb)
3190        return d
3191
3192
3193    def test_on_affiliationsGet(self):
3194        """
3195        Getting node affiliations should have.
3196        """
3197
3198        xml = """
3199        <iq type='get' to='pubsub.example.org'
3200                       from='user@example.org'>
3201          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3202            <affiliations node='test'/>
3203          </pubsub>
3204        </iq>
3205        """
3206
3207        def affiliationsGet(request):
3208            self.assertEquals('test', request.nodeIdentifier)
3209            return defer.succeed({JID('user@example.org'): 'owner'})
3210
3211        def cb(element):
3212            self.assertEquals(u'pubsub', element.name)
3213            self.assertEquals(NS_PUBSUB_OWNER, element.uri)
3214            self.assertEquals(NS_PUBSUB_OWNER, element.affiliations.uri)
3215            self.assertEquals(u'test', element.affiliations[u'node'])
3216            children = list(element.affiliations.elements())
3217            self.assertEquals(1, len(children))
3218            affiliation = children[0]
3219            self.assertEquals(u'affiliation', affiliation.name)
3220            self.assertEquals(NS_PUBSUB_OWNER, affiliation.uri)
3221            self.assertEquals(u'user@example.org', affiliation[u'jid'])
3222            self.assertEquals(u'owner', affiliation[u'affiliation'])
3223
3224        self.resource.affiliationsGet = affiliationsGet
3225        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
3226        d = self.handleRequest(xml)
3227        d.addCallback(cb)
3228        return d
3229
3230
3231    def test_on_affiliationsGetEmptyNode(self):
3232        """
3233        Getting node affiliations without node should assume empty node.
3234        """
3235
3236        xml = """
3237        <iq type='get' to='pubsub.example.org'
3238                       from='user@example.org'>
3239          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3240            <affiliations/>
3241          </pubsub>
3242        </iq>
3243        """
3244
3245        def affiliationsGet(request):
3246            self.assertIdentical('', request.nodeIdentifier)
3247            return defer.succeed({})
3248
3249        def cb(element):
3250            self.assertFalse(element.affiliations.hasAttribute(u'node'))
3251
3252        self.resource.affiliationsGet = affiliationsGet
3253        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
3254        d = self.handleRequest(xml)
3255        d.addCallback(cb)
3256        return d
3257
3258
3259    def test_on_affiliationsSet(self):
3260        """
3261        Setting node affiliations has the affiliations to be modified.
3262        """
3263
3264        xml = """
3265        <iq type='set' to='pubsub.example.org'
3266                       from='user@example.org'>
3267          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3268            <affiliations node='test'>
3269              <affiliation jid='other@example.org' affiliation='publisher'/>
3270            </affiliations>
3271          </pubsub>
3272        </iq>
3273        """
3274
3275        def affiliationsSet(request):
3276            self.assertEquals(u'test', request.nodeIdentifier)
3277            otherJID = JID(u'other@example.org')
3278            self.assertIn(otherJID, request.affiliations)
3279            self.assertEquals(u'publisher', request.affiliations[otherJID])
3280
3281        self.resource.affiliationsSet = affiliationsSet
3282        return self.handleRequest(xml)
3283
3284
3285    def test_on_affiliationsSetBareJID(self):
3286        """
3287        Affiliations are always on the bare JID.
3288        """
3289
3290        xml = """
3291        <iq type='set' to='pubsub.example.org'
3292                       from='user@example.org'>
3293          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3294            <affiliations node='test'>
3295              <affiliation jid='other@example.org/Home'
3296                           affiliation='publisher'/>
3297            </affiliations>
3298          </pubsub>
3299        </iq>
3300        """
3301
3302        def affiliationsSet(request):
3303            otherJID = JID(u'other@example.org')
3304            self.assertIn(otherJID, request.affiliations)
3305
3306        self.resource.affiliationsSet = affiliationsSet
3307        return self.handleRequest(xml)
3308
3309
3310    def test_on_affiliationsSetMultipleForSameEntity(self):
3311        """
3312        Setting node affiliations can only have one item per entity.
3313        """
3314
3315        xml = """
3316        <iq type='set' to='pubsub.example.org'
3317                       from='user@example.org'>
3318          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3319            <affiliations node='test'>
3320              <affiliation jid='other@example.org' affiliation='publisher'/>
3321              <affiliation jid='other@example.org' affiliation='owner'/>
3322            </affiliations>
3323          </pubsub>
3324        </iq>
3325        """
3326
3327        def cb(result):
3328            self.assertEquals('bad-request', result.condition)
3329
3330        d = self.handleRequest(xml)
3331        self.assertFailure(d, error.StanzaError)
3332        d.addCallback(cb)
3333        return d
3334
3335
3336    def test_on_affiliationsSetMissingJID(self):
3337        """
3338        Setting node affiliations must include a JID per affiliation.
3339        """
3340
3341        xml = """
3342        <iq type='set' to='pubsub.example.org'
3343                       from='user@example.org'>
3344          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3345            <affiliations node='test'>
3346              <affiliation affiliation='publisher'/>
3347            </affiliations>
3348          </pubsub>
3349        </iq>
3350        """
3351
3352        def cb(result):
3353            self.assertEquals('bad-request', result.condition)
3354
3355        d = self.handleRequest(xml)
3356        self.assertFailure(d, error.StanzaError)
3357        d.addCallback(cb)
3358        return d
3359
3360
3361    def test_on_affiliationsSetMissingAffiliation(self):
3362        """
3363        Setting node affiliations must include an affiliation.
3364        """
3365
3366        xml = """
3367        <iq type='set' to='pubsub.example.org'
3368                       from='user@example.org'>
3369          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3370            <affiliations node='test'>
3371              <affiliation jid='other@example.org'/>
3372            </affiliations>
3373          </pubsub>
3374        </iq>
3375        """
3376
3377        def cb(result):
3378            self.assertEquals('bad-request', result.condition)
3379
3380        d = self.handleRequest(xml)
3381        self.assertFailure(d, error.StanzaError)
3382        d.addCallback(cb)
3383        return d
3384
3385
3386
3387class PubSubServiceWithoutResourceTest(unittest.TestCase, TestableRequestHandlerMixin):
3388
3389    def setUp(self):
3390        self.stub = XmlStreamStub()
3391        self.service = pubsub.PubSubService()
3392        self.service.send = self.stub.xmlstream.send
3393
3394
3395    def test_getDiscoInfo(self):
3396        """
3397        Test getDiscoInfo calls getNodeInfo and returns some minimal info.
3398        """
3399        def cb(info):
3400            discoInfo = disco.DiscoInfo()
3401            for item in info:
3402                discoInfo.append(item)
3403            self.assertIn(('pubsub', 'service'), discoInfo.identities)
3404            self.assertIn(disco.NS_DISCO_ITEMS, discoInfo.features)
3405
3406        d = self.service.getDiscoInfo(JID('user@example.org/home'),
3407                                      JID('pubsub.example.org'), '')
3408        d.addCallback(cb)
3409        return d
3410
3411
3412    def test_publish(self):
3413        """
3414        Non-overridden L{PubSubService.publish} yields unsupported error.
3415        """
3416
3417        xml = """
3418        <iq type='set' to='pubsub.example.org'
3419                       from='user@example.org'>
3420          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3421            <publish node='mynode'/>
3422          </pubsub>
3423        </iq>
3424        """
3425
3426        def cb(result):
3427            self.assertEquals('feature-not-implemented', result.condition)
3428            self.assertEquals('unsupported', result.appCondition.name)
3429            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3430            self.assertEquals('publish', result.appCondition['feature'])
3431
3432        d = self.handleRequest(xml)
3433        self.assertFailure(d, error.StanzaError)
3434        d.addCallback(cb)
3435        return d
3436
3437
3438    def test_subscribe(self):
3439        """
3440        Non-overridden L{PubSubService.subscribe} yields unsupported error.
3441        """
3442
3443        xml = """
3444        <iq type='set' to='pubsub.example.org'
3445                       from='user@example.org'>
3446          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3447            <subscribe node='test' jid='user@example.org/Home'/>
3448          </pubsub>
3449        </iq>
3450        """
3451
3452        def cb(result):
3453            self.assertEquals('feature-not-implemented', result.condition)
3454            self.assertEquals('unsupported', result.appCondition.name)
3455            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3456            self.assertEquals('subscribe', result.appCondition['feature'])
3457
3458        d = self.handleRequest(xml)
3459        self.assertFailure(d, error.StanzaError)
3460        d.addCallback(cb)
3461        return d
3462
3463
3464    def test_unsubscribe(self):
3465        """
3466        Non-overridden L{PubSubService.unsubscribe} yields unsupported error.
3467        """
3468
3469        xml = """
3470        <iq type='set' to='pubsub.example.org'
3471                       from='user@example.org'>
3472          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3473            <unsubscribe node='test' jid='user@example.org/Home'/>
3474          </pubsub>
3475        </iq>
3476        """
3477
3478        def cb(result):
3479            self.assertEquals('feature-not-implemented', result.condition)
3480            self.assertEquals('unsupported', result.appCondition.name)
3481            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3482            self.assertEquals('subscribe', 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_subscriptions(self):
3491        """
3492        Non-overridden L{PubSubService.subscriptions} 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            <subscriptions/>
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-subscriptions',
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_affiliations(self):
3518        """
3519        Non-overridden L{PubSubService.affiliations} yields unsupported error.
3520        """
3521
3522        xml = """
3523        <iq type='get' to='pubsub.example.org'
3524                       from='user@example.org'>
3525          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3526            <affiliations/>
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('retrieve-affiliations',
3536                              result.appCondition['feature'])
3537
3538        d = self.handleRequest(xml)
3539        self.assertFailure(d, error.StanzaError)
3540        d.addCallback(cb)
3541        return d
3542
3543
3544    def test_create(self):
3545        """
3546        Non-overridden L{PubSubService.create} yields unsupported error.
3547        """
3548
3549        xml = """
3550        <iq type='set' to='pubsub.example.org'
3551                       from='user@example.org'>
3552          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3553            <create node='mynode'/>
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('create-nodes', 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_getDefaultConfiguration(self):
3571        """
3572        Non-overridden L{PubSubService.getDefaultConfiguration} yields
3573        unsupported 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            <default/>
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('retrieve-default', 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_getConfiguration(self):
3598        """
3599        Non-overridden L{PubSubService.getConfiguration} yields unsupported
3600        error.
3601        """
3602
3603        xml = """
3604        <iq type='get' to='pubsub.example.org'
3605                       from='user@example.org'>
3606          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3607            <configure/>
3608          </pubsub>
3609        </iq>
3610        """
3611
3612        def cb(result):
3613            self.assertEquals('feature-not-implemented', result.condition)
3614            self.assertEquals('unsupported', result.appCondition.name)
3615            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3616            self.assertEquals('config-node', result.appCondition['feature'])
3617
3618        d = self.handleRequest(xml)
3619        self.assertFailure(d, error.StanzaError)
3620        d.addCallback(cb)
3621        return d
3622
3623
3624    def test_setConfiguration(self):
3625        """
3626        Non-overridden L{PubSubService.setConfiguration} yields unsupported
3627        error.
3628        """
3629
3630        xml = """
3631        <iq type='set' to='pubsub.example.org'
3632                       from='user@example.org'>
3633          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3634            <configure node='test'>
3635              <x xmlns='jabber:x:data' type='submit'>
3636                <field var='FORM_TYPE' type='hidden'>
3637                  <value>http://jabber.org/protocol/pubsub#node_config</value>
3638                </field>
3639                <field var='pubsub#deliver_payloads'><value>0</value></field>
3640                <field var='pubsub#persist_items'><value>1</value></field>
3641              </x>
3642            </configure>
3643          </pubsub>
3644        </iq>
3645        """
3646
3647        def cb(result):
3648            self.assertEquals('feature-not-implemented', result.condition)
3649            self.assertEquals('unsupported', result.appCondition.name)
3650            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3651            self.assertEquals('config-node', result.appCondition['feature'])
3652
3653        d = self.handleRequest(xml)
3654        self.assertFailure(d, error.StanzaError)
3655        d.addCallback(cb)
3656        return d
3657
3658
3659    def test_setConfigurationOptionsDict(self):
3660        """
3661        Options should be passed as a dictionary, not a form.
3662        """
3663
3664        xml = """
3665        <iq type='set' to='pubsub.example.org'
3666                       from='user@example.org'>
3667          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3668            <configure node='test'>
3669              <x xmlns='jabber:x:data' type='submit'>
3670                <field var='FORM_TYPE' type='hidden'>
3671                  <value>http://jabber.org/protocol/pubsub#node_config</value>
3672                </field>
3673                <field var='pubsub#deliver_payloads'><value>0</value></field>
3674                <field var='pubsub#persist_items'><value>1</value></field>
3675              </x>
3676            </configure>
3677          </pubsub>
3678        </iq>
3679        """
3680
3681        def getConfigurationOptions():
3682            return {
3683                "pubsub#persist_items":
3684                    {"type": "boolean",
3685                     "label": "Persist items to storage"},
3686                "pubsub#deliver_payloads":
3687                    {"type": "boolean",
3688                     "label": "Deliver payloads with event notifications"}
3689                }
3690
3691        def setConfiguration(requestor, service, nodeIdentifier, options):
3692            self.assertEquals({'pubsub#deliver_payloads': False,
3693                               'pubsub#persist_items': True}, options)
3694
3695
3696        self.service.getConfigurationOptions = getConfigurationOptions
3697        self.service.setConfiguration = setConfiguration
3698        return self.handleRequest(xml)
3699
3700
3701    def test_items(self):
3702        """
3703        Non-overridden L{PubSubService.items} yields unsupported error.
3704        """
3705        xml = """
3706        <iq type='get' to='pubsub.example.org'
3707                       from='user@example.org'>
3708          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3709            <items node='test'/>
3710          </pubsub>
3711        </iq>
3712        """
3713
3714        def cb(result):
3715            self.assertEquals('feature-not-implemented', result.condition)
3716            self.assertEquals('unsupported', result.appCondition.name)
3717            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3718            self.assertEquals('retrieve-items', result.appCondition['feature'])
3719
3720        d = self.handleRequest(xml)
3721        self.assertFailure(d, error.StanzaError)
3722        d.addCallback(cb)
3723        return d
3724
3725
3726    def test_retract(self):
3727        """
3728        Non-overridden L{PubSubService.retract} yields unsupported error.
3729        """
3730        xml = """
3731        <iq type='set' to='pubsub.example.org'
3732                       from='user@example.org'>
3733          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
3734            <retract node='test'>
3735              <item id='item1'/>
3736              <item id='item2'/>
3737            </retract>
3738          </pubsub>
3739        </iq>
3740        """
3741
3742        def cb(result):
3743            self.assertEquals('feature-not-implemented', result.condition)
3744            self.assertEquals('unsupported', result.appCondition.name)
3745            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3746            self.assertEquals('retract-items', result.appCondition['feature'])
3747
3748        d = self.handleRequest(xml)
3749        self.assertFailure(d, error.StanzaError)
3750        d.addCallback(cb)
3751        return d
3752
3753
3754    def test_purge(self):
3755        """
3756        Non-overridden L{PubSubService.purge} yields unsupported error.
3757        """
3758        xml = """
3759        <iq type='set' to='pubsub.example.org'
3760                       from='user@example.org'>
3761          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3762            <purge node='test'/>
3763          </pubsub>
3764        </iq>
3765        """
3766
3767        def cb(result):
3768            self.assertEquals('feature-not-implemented', result.condition)
3769            self.assertEquals('unsupported', result.appCondition.name)
3770            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3771            self.assertEquals('purge-nodes', result.appCondition['feature'])
3772
3773        d = self.handleRequest(xml)
3774        self.assertFailure(d, error.StanzaError)
3775        d.addCallback(cb)
3776        return d
3777
3778
3779    def test_delete(self):
3780        """
3781        Non-overridden L{PubSubService.delete} yields unsupported error.
3782        """
3783        xml = """
3784        <iq type='set' to='pubsub.example.org'
3785                       from='user@example.org'>
3786          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3787            <delete node='test'/>
3788          </pubsub>
3789        </iq>
3790        """
3791
3792        def cb(result):
3793            self.assertEquals('feature-not-implemented', result.condition)
3794            self.assertEquals('unsupported', result.appCondition.name)
3795            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3796            self.assertEquals('delete-nodes', result.appCondition['feature'])
3797
3798        d = self.handleRequest(xml)
3799        self.assertFailure(d, error.StanzaError)
3800        d.addCallback(cb)
3801        return d
3802
3803
3804    def test_unknown(self):
3805        """
3806        Unknown verb yields unsupported error.
3807        """
3808        xml = """
3809        <iq type='get' to='pubsub.example.org'
3810                       from='user@example.org'>
3811          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
3812            <affiliations node='test'/>
3813          </pubsub>
3814        </iq>
3815        """
3816
3817        def cb(result):
3818            self.assertEquals('feature-not-implemented', result.condition)
3819            self.assertEquals('unsupported', result.appCondition.name)
3820            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3821
3822        d = self.handleRequest(xml)
3823        self.assertFailure(d, error.StanzaError)
3824        d.addCallback(cb)
3825        return d
3826
3827
3828
3829class PubSubResourceTest(unittest.TestCase):
3830
3831    def setUp(self):
3832        self.resource = pubsub.PubSubResource()
3833
3834
3835    def test_interface(self):
3836        """
3837        Do instances of L{pubsub.PubSubResource} provide L{iwokkel.IPubSubResource}?
3838        """
3839        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
3840
3841
3842    def test_getNodes(self):
3843        """
3844        Default getNodes returns an empty list.
3845        """
3846        def cb(nodes):
3847            self.assertEquals([], nodes)
3848
3849        d = self.resource.getNodes(JID('user@example.org/home'),
3850                                   JID('pubsub.example.org'),
3851                                   '')
3852        d.addCallback(cb)
3853        return d
3854
3855
3856    def test_publish(self):
3857        """
3858        Non-overridden L{PubSubResource.publish} yields unsupported
3859        error.
3860        """
3861
3862        def cb(result):
3863            self.assertEquals('feature-not-implemented', result.condition)
3864            self.assertEquals('unsupported', result.appCondition.name)
3865            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3866            self.assertEquals('publish', result.appCondition['feature'])
3867
3868        d = self.resource.publish(pubsub.PubSubRequest())
3869        self.assertFailure(d, error.StanzaError)
3870        d.addCallback(cb)
3871        return d
3872
3873
3874    def test_subscribe(self):
3875        """
3876        Non-overridden subscriptions yields unsupported error.
3877        """
3878
3879        def cb(result):
3880            self.assertEquals('feature-not-implemented', result.condition)
3881            self.assertEquals('unsupported', result.appCondition.name)
3882            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3883            self.assertEquals('subscribe', result.appCondition['feature'])
3884
3885        d = self.resource.subscribe(pubsub.PubSubRequest())
3886        self.assertFailure(d, error.StanzaError)
3887        d.addCallback(cb)
3888        return d
3889
3890
3891    def test_unsubscribe(self):
3892        """
3893        Non-overridden unsubscribe yields unsupported error.
3894        """
3895
3896        def cb(result):
3897            self.assertEquals('feature-not-implemented', result.condition)
3898            self.assertEquals('unsupported', result.appCondition.name)
3899            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3900            self.assertEquals('subscribe', result.appCondition['feature'])
3901
3902        d = self.resource.unsubscribe(pubsub.PubSubRequest())
3903        self.assertFailure(d, error.StanzaError)
3904        d.addCallback(cb)
3905        return d
3906
3907
3908    def test_subscriptions(self):
3909        """
3910        Non-overridden subscriptions yields unsupported error.
3911        """
3912
3913        def cb(result):
3914            self.assertEquals('feature-not-implemented', result.condition)
3915            self.assertEquals('unsupported', result.appCondition.name)
3916            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3917            self.assertEquals('retrieve-subscriptions',
3918                              result.appCondition['feature'])
3919
3920        d = self.resource.subscriptions(pubsub.PubSubRequest())
3921        self.assertFailure(d, error.StanzaError)
3922        d.addCallback(cb)
3923        return d
3924
3925
3926    def test_affiliations(self):
3927        """
3928        Non-overridden affiliations yields unsupported error.
3929        """
3930
3931        def cb(result):
3932            self.assertEquals('feature-not-implemented', result.condition)
3933            self.assertEquals('unsupported', result.appCondition.name)
3934            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3935            self.assertEquals('retrieve-affiliations',
3936                              result.appCondition['feature'])
3937
3938        d = self.resource.affiliations(pubsub.PubSubRequest())
3939        self.assertFailure(d, error.StanzaError)
3940        d.addCallback(cb)
3941        return d
3942
3943
3944    def test_create(self):
3945        """
3946        Non-overridden create yields unsupported error.
3947        """
3948
3949        def cb(result):
3950            self.assertEquals('feature-not-implemented', result.condition)
3951            self.assertEquals('unsupported', result.appCondition.name)
3952            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3953            self.assertEquals('create-nodes', result.appCondition['feature'])
3954
3955        d = self.resource.create(pubsub.PubSubRequest())
3956        self.assertFailure(d, error.StanzaError)
3957        d.addCallback(cb)
3958        return d
3959
3960
3961    def test_default(self):
3962        """
3963        Non-overridden default yields unsupported error.
3964        """
3965
3966        def cb(result):
3967            self.assertEquals('feature-not-implemented', result.condition)
3968            self.assertEquals('unsupported', result.appCondition.name)
3969            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3970            self.assertEquals('retrieve-default',
3971                              result.appCondition['feature'])
3972
3973        d = self.resource.default(pubsub.PubSubRequest())
3974        self.assertFailure(d, error.StanzaError)
3975        d.addCallback(cb)
3976        return d
3977
3978
3979    def test_configureGet(self):
3980        """
3981        Non-overridden configureGet yields unsupported
3982        error.
3983        """
3984
3985        def cb(result):
3986            self.assertEquals('feature-not-implemented', result.condition)
3987            self.assertEquals('unsupported', result.appCondition.name)
3988            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
3989            self.assertEquals('config-node', result.appCondition['feature'])
3990
3991        d = self.resource.configureGet(pubsub.PubSubRequest())
3992        self.assertFailure(d, error.StanzaError)
3993        d.addCallback(cb)
3994        return d
3995
3996
3997    def test_configureSet(self):
3998        """
3999        Non-overridden configureSet yields unsupported error.
4000        """
4001
4002        def cb(result):
4003            self.assertEquals('feature-not-implemented', result.condition)
4004            self.assertEquals('unsupported', result.appCondition.name)
4005            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4006            self.assertEquals('config-node', result.appCondition['feature'])
4007
4008        d = self.resource.configureSet(pubsub.PubSubRequest())
4009        self.assertFailure(d, error.StanzaError)
4010        d.addCallback(cb)
4011        return d
4012
4013
4014    def test_items(self):
4015        """
4016        Non-overridden items yields unsupported error.
4017        """
4018
4019        def cb(result):
4020            self.assertEquals('feature-not-implemented', result.condition)
4021            self.assertEquals('unsupported', result.appCondition.name)
4022            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4023            self.assertEquals('retrieve-items', result.appCondition['feature'])
4024
4025        d = self.resource.items(pubsub.PubSubRequest())
4026        self.assertFailure(d, error.StanzaError)
4027        d.addCallback(cb)
4028        return d
4029
4030
4031    def test_retract(self):
4032        """
4033        Non-overridden retract yields unsupported error.
4034        """
4035
4036        def cb(result):
4037            self.assertEquals('feature-not-implemented', result.condition)
4038            self.assertEquals('unsupported', result.appCondition.name)
4039            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4040            self.assertEquals('retract-items', result.appCondition['feature'])
4041
4042        d = self.resource.retract(pubsub.PubSubRequest())
4043        self.assertFailure(d, error.StanzaError)
4044        d.addCallback(cb)
4045        return d
4046
4047
4048    def test_purge(self):
4049        """
4050        Non-overridden purge yields unsupported error.
4051        """
4052
4053        def cb(result):
4054            self.assertEquals('feature-not-implemented', result.condition)
4055            self.assertEquals('unsupported', result.appCondition.name)
4056            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4057            self.assertEquals('purge-nodes', result.appCondition['feature'])
4058
4059        d = self.resource.purge(pubsub.PubSubRequest())
4060        self.assertFailure(d, error.StanzaError)
4061        d.addCallback(cb)
4062        return d
4063
4064
4065    def test_delete(self):
4066        """
4067        Non-overridden delete yields unsupported error.
4068        """
4069
4070        def cb(result):
4071            self.assertEquals('feature-not-implemented', result.condition)
4072            self.assertEquals('unsupported', result.appCondition.name)
4073            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4074            self.assertEquals('delete-nodes', result.appCondition['feature'])
4075
4076        d = self.resource.delete(pubsub.PubSubRequest())
4077        self.assertFailure(d, error.StanzaError)
4078        d.addCallback(cb)
4079        return d
4080
4081
4082    def test_affiliationsGet(self):
4083        """
4084        Non-overridden owner affiliations get yields unsupported error.
4085        """
4086
4087        def cb(result):
4088            self.assertEquals('feature-not-implemented', result.condition)
4089            self.assertEquals('unsupported', result.appCondition.name)
4090            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4091            self.assertEquals('modify-affiliations',
4092                              result.appCondition['feature'])
4093
4094        d = self.resource.affiliationsGet(pubsub.PubSubRequest())
4095        self.assertFailure(d, error.StanzaError)
4096        d.addCallback(cb)
4097        return d
4098
4099
4100    def test_affiliationsSet(self):
4101        """
4102        Non-overridden owner affiliations set yields unsupported error.
4103        """
4104
4105        def cb(result):
4106            self.assertEquals('feature-not-implemented', result.condition)
4107            self.assertEquals('unsupported', result.appCondition.name)
4108            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
4109            self.assertEquals('modify-affiliations',
4110                              result.appCondition['feature'])
4111
4112        d = self.resource.affiliationsSet(pubsub.PubSubRequest())
4113        self.assertFailure(d, error.StanzaError)
4114        d.addCallback(cb)
4115        return d
Note: See TracBrowser for help on using the repository browser.