source: wokkel/test/test_pubsub.py @ 88:58b00aeed1a6

Last change on this file since 88:58b00aeed1a6 was 88:58b00aeed1a6, checked in by Ralph Meijer <ralphm@…>, 11 years ago

Service Discovery fixes for PubSubService?.

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