source: wokkel/test/test_pubsub.py @ 90:1ffd4dd005e4

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

Ignore error messages in PubSubClient?.

Author: ralphm
Reviewer: arjan
Fixes: #69

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