source: wokkel/test/test_pubsub.py @ 202:645fbb5f02f4

Last change on this file since 202:645fbb5f02f4 was 202:645fbb5f02f4, checked in by Ralph Meijer <ralphm@…>, 4 years ago

imported patch py3-pubsub.patch

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