source: wokkel/test/test_pubsub.py @ 220:c8a97efc6fa6

Last change on this file since 220:c8a97efc6fa6 was 220:c8a97efc6fa6, checked in by souliane <souliane@…>, 5 years ago

implement item retrieval by IDs

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