source: wokkel/test/test_pubsub.py @ 83:81daaca3d75f

Last change on this file since 83:81daaca3d75f was 83:81daaca3d75f, checked in by Ralph Meijer <ralphm@…>, 13 years ago

Add support for subscription options in subscribe requests

Fixes #63.

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