source: wokkel/test/test_pubsub.py @ 226:2532cfb12c7c

Last change on this file since 226:2532cfb12c7c was 226:2532cfb12c7c, checked in by Ralph Meijer <ralphm@…>, 4 years ago

Merge branch 'master' into item-retract

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