Changeset 5:231bc3e8b810 in ralphm-patches


Ignore:
Timestamp:
Apr 1, 2009, 2:17:03 PM (12 years ago)
Author:
Ralph Meijer <ralphm@…>
Branch:
default
Message:

A gazillion changes.

Files:
4 edited

Legend:

Unmodified
Added
Removed
  • compat-pre-twisted-8.0.0.patch

    r1 r5  
    1 diff -r 9c14d48c54b2 wokkel/compat.py
    2 --- a/wokkel/compat.py  Wed Feb 04 14:41:26 2009 +0100
    3 +++ b/wokkel/compat.py  Wed Feb 04 14:42:14 2009 +0100
    4 @@ -6,40 +6,6 @@
    5  from twisted.internet import protocol
     1diff -r 6fa0283e522b wokkel/compat.py
     2--- a/wokkel/compat.py  Wed Mar 25 18:14:08 2009 +0100
     3+++ b/wokkel/compat.py  Wed Mar 25 18:15:15 2009 +0100
     4@@ -7,40 +7,6 @@
    65 from twisted.words.protocols.jabber import xmlstream
    76 from twisted.words.xish import domish
    8 -
     7 
    98-def toResponse(stanza, stanzaType=None):
    109-    """
     
    4039-
    4140-
    42  
     41-
    4342 class BootstrapMixin(object):
    4443     """
    45 diff -r 9c14d48c54b2 wokkel/subprotocols.py
    46 --- a/wokkel/subprotocols.py    Wed Feb 04 14:41:26 2009 +0100
    47 +++ b/wokkel/subprotocols.py    Wed Feb 04 14:42:14 2009 +0100
     44     XmlStream factory mixin to install bootstrap event observers.
     45diff -r 6fa0283e522b wokkel/subprotocols.py
     46--- a/wokkel/subprotocols.py    Wed Mar 25 18:14:08 2009 +0100
     47+++ b/wokkel/subprotocols.py    Wed Mar 25 18:15:15 2009 +0100
    4848@@ -1,6 +1,6 @@
    4949 # -*- test-case-name: wokkel.test.test_subprotocols -*-
     
    5454 
    5555 """
    56 @@ -12,13 +12,9 @@
     56@@ -12,14 +12,10 @@
    5757 from twisted.internet import defer
    5858 from twisted.python import log
     
    6161 from twisted.words.xish import xpath
    6262 from twisted.words.xish.domish import IElement
    63 -
     63 
    6464-try:
    6565-    from twisted.words.protocols.jabber.xmlstream import toResponse
    6666-except ImportError:
    6767-    from wokkel.compat import toResponse
    68  
     68-
    6969 from wokkel.iwokkel import IXMPPHandler, IXMPPHandlerCollection
    7070 
    71 diff -r 9c14d48c54b2 wokkel/test/test_compat.py
    72 --- a/wokkel/test/test_compat.py        Wed Feb 04 14:41:26 2009 +0100
    73 +++ b/wokkel/test/test_compat.py        Wed Feb 04 14:42:14 2009 +0100
     71 class XMPPHandler(object):
     72diff -r 6fa0283e522b wokkel/test/test_compat.py
     73--- a/wokkel/test/test_compat.py        Wed Mar 25 18:14:08 2009 +0100
     74+++ b/wokkel/test/test_compat.py        Wed Mar 25 18:15:15 2009 +0100
    7475@@ -1,5 +1,5 @@
    7576-# Copyright (c) 2001-2007 Twisted Matrix Laboratories.
     
    8990 class DummyProtocol(protocol.Protocol, utility.EventDispatcher):
    9091     """
    91 @@ -77,75 +77,6 @@
    92  
    93          dispatcher.dispatch(None, '//event/myevent')
    94          self.assertFalse(called)
    95 -
    96 -
    97 -
     92@@ -80,75 +80,6 @@
     93 
     94 
     95 
    9896-class ToResponseTest(unittest.TestCase):
    9997-
     
    162160-        response = toResponse(stanza)
    163161-        self.failIf(response.hasAttribute('type'))
    164  
    165  
    166  
    167 diff -r 9c14d48c54b2 wokkel/test/test_disco.py
    168 --- a/wokkel/test/test_disco.py Wed Feb 04 14:41:26 2009 +0100
    169 +++ b/wokkel/test/test_disco.py Wed Feb 04 14:42:14 2009 +0100
    170 @@ -10,17 +10,13 @@
     162-
     163-
     164-
     165 class XmlStreamServerFactoryTest(BootstrapMixinTest):
     166     """
     167     Tests for L{XmlStreamServerFactory}.
     168diff -r 6fa0283e522b wokkel/test/test_disco.py
     169--- a/wokkel/test/test_disco.py Wed Mar 25 18:14:08 2009 +0100
     170+++ b/wokkel/test/test_disco.py Wed Mar 25 18:15:15 2009 +0100
     171@@ -10,6 +10,7 @@
    171172 from twisted.internet import defer
    172173 from twisted.trial import unittest
     
    176177 
    177178 from wokkel import data_form, disco
    178  from wokkel.generic import parseXml
     179@@ -17,11 +18,6 @@
    179180 from wokkel.subprotocols import XMPPHandler
    180181 from wokkel.test.helpers import TestableRequestHandlerMixin, XmlStreamStub
    181 -
     182 
    182183-try:
    183184-    from twisted.words.protocols.jabber.xmlstream import toResponse
    184185-except ImportError:
    185186-    from wokkel.compat import toResponse
    186  
     187-
    187188 NS_DISCO_INFO = 'http://jabber.org/protocol/disco#info'
    188189 NS_DISCO_ITEMS = 'http://jabber.org/protocol/disco#items'
    189 diff -r 9c14d48c54b2 wokkel/test/test_pubsub.py
    190 --- a/wokkel/test/test_pubsub.py        Wed Feb 04 14:41:26 2009 +0100
    191 +++ b/wokkel/test/test_pubsub.py        Wed Feb 04 14:42:14 2009 +0100
     190 
     191diff -r 6fa0283e522b wokkel/test/test_pubsub.py
     192--- a/wokkel/test/test_pubsub.py        Wed Mar 25 18:14:08 2009 +0100
     193+++ b/wokkel/test/test_pubsub.py        Wed Mar 25 18:15:15 2009 +0100
    192194@@ -1,4 +1,4 @@
    193195-# Copyright (c) 2003-2008 Ralph Meijer
     
    196198 
    197199 """
    198 @@ -12,14 +12,10 @@
     200@@ -12,16 +12,12 @@
    199201 from twisted.words.xish import domish
    200202 from twisted.words.protocols.jabber import error
     
    202204+from twisted.words.protocols.jabber.xmlstream import toResponse
    203205 
    204  from wokkel import data_form, iwokkel, pubsub, shim
     206 from wokkel import data_form, disco, iwokkel, pubsub, shim
     207 from wokkel.generic import parseXml
    205208 from wokkel.test.helpers import TestableRequestHandlerMixin, XmlStreamStub
    206 -
     209 
    207210-try:
    208211-    from twisted.words.protocols.jabber.xmlstream import toResponse
    209212-except ImportError:
    210213-    from wokkel.compat import toResponse
    211  
     214-
    212215 NS_PUBSUB = 'http://jabber.org/protocol/pubsub'
    213216 NS_PUBSUB_CONFIG = 'http://jabber.org/protocol/pubsub#node_config'
     217 NS_PUBSUB_ERRORS = 'http://jabber.org/protocol/pubsub#errors'
  • pubsub_client_sender.patch

    r4 r5  
    1 diff -r 8be0600d2c32 wokkel/pubsub.py
    2 --- a/wokkel/pubsub.py  Mon Mar 23 09:00:16 2009 +0100
    3 +++ b/wokkel/pubsub.py  Mon Mar 23 09:00:24 2009 +0100
     1diff -r 5a91781194ab wokkel/pubsub.py
     2--- a/wokkel/pubsub.py  Mon Mar 23 21:43:25 2009 +0100
     3+++ b/wokkel/pubsub.py  Mon Mar 23 21:50:36 2009 +0100
    44@@ -605,7 +605,7 @@
    55         pass
     
    9292         def cb(iq):
    9393             items = []
    94 diff -r 8be0600d2c32 wokkel/test/test_pubsub.py
    95 --- a/wokkel/test/test_pubsub.py        Mon Mar 23 09:00:16 2009 +0100
    96 +++ b/wokkel/test/test_pubsub.py        Mon Mar 23 09:00:24 2009 +0100
    97 @@ -257,6 +257,22 @@
     94diff -r 5a91781194ab wokkel/test/test_pubsub.py
     95--- a/wokkel/test/test_pubsub.py        Mon Mar 23 21:43:25 2009 +0100
     96+++ b/wokkel/test/test_pubsub.py        Mon Mar 23 21:50:36 2009 +0100
     97@@ -258,6 +258,22 @@
    9898         return d
    9999 
     
    118118         """
    119119         Test sending delete request.
    120 @@ -280,6 +296,22 @@
     120@@ -281,6 +297,22 @@
    121121         return d
    122122 
     
    141141         """
    142142         Test sending publish request.
    143 @@ -331,6 +363,23 @@
     143@@ -332,6 +364,23 @@
    144144         return d
    145145 
     
    165165         """
    166166         Test sending subscription request.
    167 @@ -400,6 +449,27 @@
     167@@ -401,6 +450,27 @@
    168168         return d
    169169 
     
    193193         """
    194194         Test sending unsubscription request.
    195 @@ -423,6 +493,20 @@
     195@@ -424,6 +494,20 @@
    196196         return d
    197197 
     
    214214         """
    215215         Test sending items request.
    216 @@ -489,6 +573,25 @@
     216@@ -490,6 +574,25 @@
    217217         return d
    218218 
     
    238238+
    239239 
    240  class PubSubServiceTest(unittest.TestCase, TestableRequestHandlerMixin):
    241      """
     240 class PubSubRequestTest(unittest.TestCase):
     241 
  • pubsub_request.patch

    r4 r5  
    1111that is passed to the corresponding handler methods.
    1212
    13 diff -r 884ac8d88411 wokkel/generic.py
    14 --- a/wokkel/generic.py Thu Mar 05 16:29:12 2009 +0100
    15 +++ b/wokkel/generic.py Wed Mar 18 09:26:20 2009 +0100
     13diff -r bcbcbc4aa868 wokkel/generic.py
     14--- a/wokkel/generic.py Tue Mar 24 09:25:36 2009 +0100
     15+++ b/wokkel/generic.py Wed Mar 25 18:13:56 2009 +0100
    1616@@ -10,7 +10,7 @@
    1717 from zope.interface import implements
     
    5858+            self.recipient = jid.internJID(element['to'])
    5959+        self.stanzaType = element.getAttribute('type')
    60 diff -r 884ac8d88411 wokkel/iwokkel.py
    61 --- a/wokkel/iwokkel.py Thu Mar 05 16:29:12 2009 +0100
    62 +++ b/wokkel/iwokkel.py Wed Mar 18 09:26:20 2009 +0100
     60diff -r bcbcbc4aa868 wokkel/iwokkel.py
     61--- a/wokkel/iwokkel.py Tue Mar 24 09:25:36 2009 +0100
     62+++ b/wokkel/iwokkel.py Wed Mar 25 18:13:56 2009 +0100
    6363@@ -278,6 +278,7 @@
    6464                              C{list} of L{domish.Element})
     
    340340+        @rtype: L{defer.Deferred}
    341341         """
    342 diff -r 884ac8d88411 wokkel/pubsub.py
    343 --- a/wokkel/pubsub.py  Thu Mar 05 16:29:12 2009 +0100
    344 +++ b/wokkel/pubsub.py  Wed Mar 18 09:26:20 2009 +0100
     342diff -r bcbcbc4aa868 wokkel/pubsub.py
     343--- a/wokkel/pubsub.py  Tue Mar 24 09:25:36 2009 +0100
     344+++ b/wokkel/pubsub.py  Wed Mar 25 18:13:56 2009 +0100
    345345@@ -16,7 +16,7 @@
    346346 from twisted.words.protocols.jabber import jid, error, xmlstream
     
    352352 from wokkel.iwokkel import IPubSubClient, IPubSubService
    353353 
    354 @@ -32,42 +32,10 @@
     354@@ -31,43 +31,12 @@
     355 NS_PUBSUB_OWNER = NS_PUBSUB + "#owner"
    355356 NS_PUBSUB_NODE_CONFIG = NS_PUBSUB + "#node_config"
    356357 NS_PUBSUB_META_DATA = NS_PUBSUB + "#meta-data"
     358+NS_PUBSUB_SUBSCRIBE_OPTIONS = NS_PUBSUB + "#subscribe_options"
    357359 
    358360-# In publish-subscribe namespace XPath query selector.
     
    399401 class SubscriptionPending(Exception):
    400402     """
    401 @@ -167,40 +135,350 @@
     403@@ -98,12 +67,18 @@
     404 
     405 
     406 
     407-class BadRequest(PubSubError):
     408+class BadRequest(error.StanzaError):
     409     """
     410     Bad request stanza error.
     411     """
     412     def __init__(self, pubsubCondition=None, text=None):
     413-        PubSubError.__init__(self, 'bad-request', pubsubCondition, text)
     414+        if pubsubCondition:
     415+            appCondition = domish.Element((NS_PUBSUB_ERRORS, pubsubCondition))
     416+        else:
     417+            appCondition = None
     418+        error.StanzaError.__init__(self, 'bad-request',
     419+                                         text=text,
     420+                                         appCondition=appCondition)
     421 
     422 
     423 
     424@@ -167,40 +142,362 @@
    402425 
    403426 
     
    500523+        'subscribe': ['nodeOrEmpty', 'jid'],
    501524+        'unsubscribe': ['nodeOrEmpty', 'jid'],
    502 +        'optionsGet': [],
    503 +        'optionsSet': [],
     525+        'optionsGet': ['nodeOrEmpty', 'jid'],
     526+        'optionsSet': ['nodeOrEmpty', 'jid', 'options'],
    504527+        'subscriptions': [],
    505528+        'affiliations': [],
     
    662685+                self.options = {}
    663686+            else:
    664 +                raise BadRequest("Unexpected form type %r" % form.formType)
     687+                raise BadRequest(text="Unexpected form type %r" % form.formType)
    665688+        else:
    666 +            raise BadRequest("Missing configuration form")
     689+            raise BadRequest(text="Missing configuration form")
    667690+
    668691+
     
    712735+            verbElement['max_items'] = unicode(self.maxItems)
    713736+
     737+
     738+    def _parse_options(self, verbElement):
     739+        form = PubSubRequest._findForm(verbElement, NS_PUBSUB_SUBSCRIBE_OPTIONS)
     740+        if form:
     741+            if form.formType == 'submit':
     742+                self.options = form.getValues()
     743+            elif form.formType == 'cancel':
     744+                self.options = {}
     745+            else:
     746+                raise BadRequest(text="Unexpected form type %r" % form.formType)
     747+        else:
     748+            raise BadRequest(text="Missing options form")
    714749+
    715750+    def parseElement(self, element):
     
    773808 
    774809 
    775 @@ -336,11 +614,9 @@
     810@@ -336,11 +633,9 @@
    776811         @param nodeIdentifier: Optional suggestion for the id of the node.
    777812         @type nodeIdentifier: C{unicode}
     
    788823         def cb(iq):
    789824             try:
    790 @@ -350,7 +626,9 @@
     825@@ -350,7 +645,9 @@
    791826                 new_node = nodeIdentifier
    792827             return new_node
     
    799834 
    800835     def deleteNode(self, service, nodeIdentifier):
    801 @@ -362,9 +640,10 @@
     836@@ -362,9 +659,10 @@
    802837         @param nodeIdentifier: The identifier of the node.
    803838         @type nodeIdentifier: C{unicode}
     
    813848 
    814849     def subscribe(self, service, nodeIdentifier, subscriber):
    815 @@ -379,10 +658,10 @@
     850@@ -379,10 +677,10 @@
    816851                            will get notifications of new published items.
    817852         @type subscriber: L{JID}
     
    828863         def cb(iq):
    829864             subscription = iq.pubsub.subscription["subscription"]
    830 @@ -397,7 +676,9 @@
     865@@ -397,7 +695,9 @@
    831866                 # yielded a stanza error.
    832867                 return None
     
    839874 
    840875     def unsubscribe(self, service, nodeIdentifier, subscriber):
    841 @@ -411,11 +692,11 @@
     876@@ -411,11 +711,11 @@
    842877         @param subscriber: The entity to unsubscribe from the node.
    843878         @type subscriber: L{JID}
     
    856891 
    857892     def publish(self, service, nodeIdentifier, items=None):
    858 @@ -429,13 +710,11 @@
     893@@ -429,13 +729,11 @@
    859894         @param items: Optional list of L{Item}s to publish.
    860895         @type items: C{list}
     
    875910 
    876911     def items(self, service, nodeIdentifier, maxItems=None):
    877 @@ -449,11 +728,11 @@
     912@@ -449,11 +747,11 @@
    878913         @param maxItems: Optional limit on the number of retrieved items.
    879914         @type maxItems: C{int}
     
    891926         def cb(iq):
    892927             items = []
    893 @@ -462,7 +741,9 @@
     928@@ -462,7 +760,9 @@
    894929                     items.append(element)
    895930             return items
     
    902937 
    903938 
    904 @@ -497,27 +778,7 @@
     939@@ -497,27 +797,7 @@
    905940     implements(IPubSubService)
    906941 
     
    931966 
    932967 
    933 @@ -530,10 +791,7 @@
     968@@ -530,10 +810,7 @@
    934969 
    935970 
     
    943978 
    944979     def getDiscoInfo(self, requestor, target, nodeIdentifier):
    945 @@ -585,92 +843,17 @@
     980@@ -585,92 +862,17 @@
    946981         return d
    947982 
     
    10431078         def toResponse(result):
    10441079             response = domish.Element((NS_PUBSUB, "pubsub"))
    1045 @@ -681,28 +864,24 @@
     1080@@ -681,28 +883,24 @@
    10461081             subscription["subscription"] = result.state
    10471082             return response
     
    10781113         def toResponse(result):
    10791114             response = domish.Element((NS_PUBSUB, 'pubsub'))
    1080 @@ -714,13 +893,12 @@
     1115@@ -714,13 +912,12 @@
    10811116                 item['subscription'] = subscription.state
    10821117             return response
     
    10941129         def toResponse(result):
    10951130             response = domish.Element((NS_PUBSUB, 'pubsub'))
    1096 @@ -733,17 +911,15 @@
     1131@@ -733,17 +930,15 @@
    10971132 
    10981133             return response
     
    11151150                 create = response.addElement('create')
    11161151                 create['node'] = result
    1117 @@ -751,7 +927,7 @@
     1152@@ -751,7 +946,7 @@
    11181153             else:
    11191154                 return None
     
    11241159         return d
    11251160 
    1126 @@ -771,6 +947,7 @@
     1161@@ -771,6 +966,7 @@
    11271162             fields.append(data_form.Field.fromDict(option))
    11281163         return fields
     
    11321167         options = self.getConfigurationOptions()
    11331168         fields = self._makeFields(options, values)
    1134 @@ -780,6 +957,7 @@
     1169@@ -780,6 +976,7 @@
    11351170 
    11361171         return form
     
    11401175         options = self.getConfigurationOptions()
    11411176         processedValues = {}
    1142 @@ -805,8 +983,7 @@
     1177@@ -805,8 +1002,7 @@
    11431178         return processedValues
    11441179 
     
    11501185         def toResponse(options):
    11511186             response = domish.Element((NS_PUBSUB_OWNER, "pubsub"))
    1152 @@ -814,127 +991,82 @@
     1187@@ -814,127 +1010,82 @@
    11531188             default.addChild(self._formFromConfiguration(options).toElement())
    11541189             return response
     
    13051340 
    13061341     # public methods
    1307 @@ -990,27 +1122,27 @@
     1342@@ -990,27 +1141,27 @@
    13081343         return []
    13091344 
     
    13391374 
    13401375 
    1341 @@ -1018,30 +1150,29 @@
     1376@@ -1018,30 +1169,29 @@
    13421377         return {}
    13431378 
     
    13771412+    def delete(self, request):
    13781413         raise Unsupported('delete-nodes')
    1379 diff -r 884ac8d88411 wokkel/test/test_pubsub.py
    1380 --- a/wokkel/test/test_pubsub.py        Thu Mar 05 16:29:12 2009 +0100
    1381 +++ b/wokkel/test/test_pubsub.py        Wed Mar 18 09:26:20 2009 +0100
    1382 @@ -507,6 +507,29 @@
     1414diff -r bcbcbc4aa868 wokkel/test/test_pubsub.py
     1415--- a/wokkel/test/test_pubsub.py        Tue Mar 24 09:25:36 2009 +0100
     1416+++ b/wokkel/test/test_pubsub.py        Wed Mar 25 18:13:56 2009 +0100
     1417@@ -14,6 +14,7 @@
     1418 from twisted.words.protocols.jabber.jid import JID
     1419 
     1420 from wokkel import data_form, iwokkel, pubsub, shim
     1421+from wokkel.generic import parseXml
     1422 from wokkel.test.helpers import TestableRequestHandlerMixin, XmlStreamStub
     1423 
     1424 try:
     1425@@ -490,6 +491,630 @@
     1426 
     1427 
     1428 
     1429+class PubSubRequestTest(unittest.TestCase):
     1430+
     1431+    def test_fromElementPublish(self):
     1432+        """
     1433+        Test parsing a publish request.
     1434+        """
     1435+
     1436+        xml = """
     1437+        <iq type='set' to='pubsub.example.org'
     1438+                       from='user@example.org'>
     1439+          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1440+            <publish node='test'/>
     1441+          </pubsub>
     1442+        </iq>
     1443+        """
     1444+
     1445+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     1446+        self.assertEqual('publish', request.verb)
     1447+        self.assertEqual(JID('user@example.org'), request.sender)
     1448+        self.assertEqual(JID('pubsub.example.org'), request.recipient)
     1449+        self.assertEqual('test', request.nodeIdentifier)
     1450+        self.assertEqual([], request.items)
     1451+
     1452+
     1453+    def test_fromElementPublishItems(self):
     1454+        """
     1455+        Test parsing a publish request with items.
     1456+        """
     1457+
     1458+        xml = """
     1459+        <iq type='set' to='pubsub.example.org'
     1460+                       from='user@example.org'>
     1461+          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1462+            <publish node='test'>
     1463+              <item id="item1"/>
     1464+              <item id="item2"/>
     1465+            </publish>
     1466+          </pubsub>
     1467+        </iq>
     1468+        """
     1469+
     1470+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     1471+        self.assertEqual(2, len(request.items))
     1472+        self.assertEqual(u'item1', request.items[0]["id"])
     1473+        self.assertEqual(u'item2', request.items[1]["id"])
     1474+
     1475+
     1476+    def test_fromElementPublishNoNode(self):
     1477+        """
     1478+        A publish request to the root node should raise an exception.
     1479+        """
     1480+        xml = """
     1481+        <iq type='set' to='pubsub.example.org'
     1482+                       from='user@example.org'>
     1483+          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1484+            <publish/>
     1485+          </pubsub>
     1486+        </iq>
     1487+        """
     1488+
     1489+        err = self.assertRaises(error.StanzaError,
     1490+                                pubsub.PubSubRequest.fromElement,
     1491+                                parseXml(xml))
     1492+        self.assertEqual('bad-request', err.condition)
     1493+        self.assertEqual(NS_PUBSUB_ERRORS, err.appCondition.uri)
     1494+        self.assertEqual('nodeid-required', err.appCondition.name)
     1495+
     1496+
     1497+    def test_fromElementSubscribe(self):
     1498+        """
     1499+        Test parsing a subscription request.
     1500+        """
     1501+
     1502+        xml = """
     1503+        <iq type='set' to='pubsub.example.org'
     1504+                       from='user@example.org'>
     1505+          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1506+            <subscribe node='test' jid='user@example.org/Home'/>
     1507+          </pubsub>
     1508+        </iq>
     1509+        """
     1510+
     1511+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     1512+        self.assertEqual('subscribe', request.verb)
     1513+        self.assertEqual(JID('user@example.org'), request.sender)
     1514+        self.assertEqual(JID('pubsub.example.org'), request.recipient)
     1515+        self.assertEqual('test', request.nodeIdentifier)
     1516+        self.assertEqual(JID('user@example.org/Home'), request.subscriber)
     1517+
     1518+
     1519+    def test_fromElementSubscribeEmptyNode(self):
     1520+        """
     1521+        Test parsing a subscription request to the root node.
     1522+        """
     1523+
     1524+        xml = """
     1525+        <iq type='set' to='pubsub.example.org'
     1526+                       from='user@example.org'>
     1527+          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1528+            <subscribe jid='user@example.org/Home'/>
     1529+          </pubsub>
     1530+        </iq>
     1531+        """
     1532+
     1533+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     1534+        self.assertEqual('', request.nodeIdentifier)
     1535+
     1536+
     1537+    def test_fromElementSubscribeNoJID(self):
     1538+        """
     1539+        Subscribe requests without a JID should raise a bad-request exception.
     1540+        """
     1541+        xml = """
     1542+        <iq type='set' to='pubsub.example.org'
     1543+                       from='user@example.org'>
     1544+          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1545+            <subscribe node='test'/>
     1546+          </pubsub>
     1547+        </iq>
     1548+        """
     1549+        err = self.assertRaises(error.StanzaError,
     1550+                                pubsub.PubSubRequest.fromElement,
     1551+                                parseXml(xml))
     1552+        self.assertEqual('bad-request', err.condition)
     1553+        self.assertEqual(NS_PUBSUB_ERRORS, err.appCondition.uri)
     1554+        self.assertEqual('jid-required', err.appCondition.name)
     1555+
     1556+    def test_fromElementUnsubscribe(self):
     1557+        """
     1558+        Test parsing an unsubscription request.
     1559+        """
     1560+
     1561+        xml = """
     1562+        <iq type='set' to='pubsub.example.org'
     1563+                       from='user@example.org'>
     1564+          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1565+            <unsubscribe node='test' jid='user@example.org/Home'/>
     1566+          </pubsub>
     1567+        </iq>
     1568+        """
     1569+
     1570+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     1571+        self.assertEqual('unsubscribe', request.verb)
     1572+        self.assertEqual(JID('user@example.org'), request.sender)
     1573+        self.assertEqual(JID('pubsub.example.org'), request.recipient)
     1574+        self.assertEqual('test', request.nodeIdentifier)
     1575+        self.assertEqual(JID('user@example.org/Home'), request.subscriber)
     1576+
     1577+
     1578+    def test_fromElementUnsubscribeNoJID(self):
     1579+        """
     1580+        Unsubscribe requests without a JID should raise a bad-request exception.
     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+            <unsubscribe node='test'/>
     1587+          </pubsub>
     1588+        </iq>
     1589+        """
     1590+        err = self.assertRaises(error.StanzaError,
     1591+                                pubsub.PubSubRequest.fromElement,
     1592+                                parseXml(xml))
     1593+        self.assertEqual('bad-request', err.condition)
     1594+        self.assertEqual(NS_PUBSUB_ERRORS, err.appCondition.uri)
     1595+        self.assertEqual('jid-required', err.appCondition.name)
     1596+
     1597+
     1598+    def test_fromElementOptionsGet(self):
     1599+        """
     1600+        Test parsing a request for getting subscription options.
     1601+        """
     1602+
     1603+        xml = """
     1604+        <iq type='get' to='pubsub.example.org'
     1605+                       from='user@example.org'>
     1606+          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1607+            <options node='test' jid='user@example.org/Home'/>
     1608+          </pubsub>
     1609+        </iq>
     1610+        """
     1611+
     1612+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     1613+        self.assertEqual('optionsGet', request.verb)
     1614+
     1615+
     1616+    def test_fromElementOptionsSet(self):
     1617+        """
     1618+        Test parsing a request for setting subscription options.
     1619+        """
     1620+
     1621+        xml = """
     1622+        <iq type='set' to='pubsub.example.org'
     1623+                       from='user@example.org'>
     1624+          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1625+            <options node='test' jid='user@example.org/Home'>
     1626+              <x xmlns='jabber:x:data' type='submit'>
     1627+                <field var='FORM_TYPE' type='hidden'>
     1628+                  <value>http://jabber.org/protocol/pubsub#subscribe_options</value>
     1629+                </field>
     1630+                <field var='pubsub#deliver'><value>1</value></field>
     1631+              </x>
     1632+            </options>
     1633+          </pubsub>
     1634+        </iq>
     1635+        """
     1636+
     1637+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     1638+        self.assertEqual('optionsSet', request.verb)
     1639+        self.assertEqual(JID('user@example.org'), request.sender)
     1640+        self.assertEqual(JID('pubsub.example.org'), request.recipient)
     1641+        self.assertEqual('test', request.nodeIdentifier)
     1642+        self.assertEqual(JID('user@example.org/Home'), request.subscriber)
     1643+        self.assertEqual({'pubsub#deliver': '1'}, request.options)
     1644+
     1645+
     1646+    def test_fromElementOptionsSetCancel(self):
     1647+        """
     1648+        Test parsing a request for cancelling setting subscription options.
     1649+        """
     1650+
     1651+        xml = """
     1652+        <iq type='set' to='pubsub.example.org'
     1653+                       from='user@example.org'>
     1654+          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1655+            <options node='test' jid='user@example.org/Home'>
     1656+              <x xmlns='jabber:x:data' type='cancel'/>
     1657+            </options>
     1658+          </pubsub>
     1659+        </iq>
     1660+        """
     1661+
     1662+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     1663+        self.assertEqual({}, request.options)
     1664+
     1665+
     1666+    def test_fromElementOptionsSetBadFormType(self):
     1667+        """
     1668+        On a options set request unknown fields should be ignored.
     1669+        """
     1670+
     1671+        xml = """
     1672+        <iq type='set' to='pubsub.example.org'
     1673+                       from='user@example.org'>
     1674+          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1675+            <options node='test' jid='user@example.org/Home'>
     1676+              <x xmlns='jabber:x:data' type='result'>
     1677+                <field var='FORM_TYPE' type='hidden'>
     1678+                  <value>http://jabber.org/protocol/pubsub#node_config</value>
     1679+                </field>
     1680+                <field var='pubsub#deliver'><value>1</value></field>
     1681+              </x>
     1682+            </options>
     1683+          </pubsub>
     1684+        </iq>
     1685+        """
     1686+
     1687+        err = self.assertRaises(error.StanzaError,
     1688+                                pubsub.PubSubRequest.fromElement,
     1689+                                parseXml(xml))
     1690+        self.assertEqual('bad-request', err.condition)
     1691+        self.assertEqual(None, err.appCondition)
     1692+
     1693+
     1694+    def test_fromElementOptionsSetNoForm(self):
     1695+        """
     1696+        On a options set request a form is required.
     1697+        """
     1698+
     1699+        xml = """
     1700+        <iq type='set' to='pubsub.example.org'
     1701+                       from='user@example.org'>
     1702+          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1703+            <options node='test' jid='user@example.org/Home'/>
     1704+          </pubsub>
     1705+        </iq>
     1706+        """
     1707+        err = self.assertRaises(error.StanzaError,
     1708+                                pubsub.PubSubRequest.fromElement,
     1709+                                parseXml(xml))
     1710+        self.assertEqual('bad-request', err.condition)
     1711+        self.assertEqual(None, err.appCondition)
     1712+
     1713+
     1714+    def test_fromElementSubscriptions(self):
     1715+        """
     1716+        Test parsing a request for all subscriptions.
     1717+        """
     1718+
     1719+        xml = """
     1720+        <iq type='get' to='pubsub.example.org'
     1721+                       from='user@example.org'>
     1722+          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1723+            <subscriptions/>
     1724+          </pubsub>
     1725+        </iq>
     1726+        """
     1727+
     1728+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     1729+        self.assertEqual('subscriptions', request.verb)
     1730+        self.assertEqual(JID('user@example.org'), request.sender)
     1731+        self.assertEqual(JID('pubsub.example.org'), request.recipient)
     1732+
     1733+
     1734+    def test_fromElementAffiliations(self):
     1735+        """
     1736+        Test parsing a request for all affiliations.
     1737+        """
     1738+
     1739+        xml = """
     1740+        <iq type='get' to='pubsub.example.org'
     1741+                       from='user@example.org'>
     1742+          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1743+            <affiliations/>
     1744+          </pubsub>
     1745+        </iq>
     1746+        """
     1747+
     1748+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     1749+        self.assertEqual('affiliations', request.verb)
     1750+        self.assertEqual(JID('user@example.org'), request.sender)
     1751+        self.assertEqual(JID('pubsub.example.org'), request.recipient)
     1752+
     1753+
     1754+    def test_fromElementCreate(self):
     1755+        """
     1756+        Test parsing a request to create a node.
     1757+        """
     1758+
     1759+        xml = """
     1760+        <iq type='set' to='pubsub.example.org'
     1761+                       from='user@example.org'>
     1762+          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1763+            <create node='mynode'/>
     1764+          </pubsub>
     1765+        </iq>
     1766+        """
     1767+
     1768+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     1769+        self.assertEqual('create', request.verb)
     1770+        self.assertEqual(JID('user@example.org'), request.sender)
     1771+        self.assertEqual(JID('pubsub.example.org'), request.recipient)
     1772+        self.assertEqual('mynode', request.nodeIdentifier)
     1773+
     1774+
     1775+    def test_fromElementCreateInstant(self):
     1776+        """
     1777+        Test parsing a request to create an instant node.
     1778+        """
     1779+
     1780+        xml = """
     1781+        <iq type='set' to='pubsub.example.org'
     1782+                       from='user@example.org'>
     1783+          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1784+            <create/>
     1785+          </pubsub>
     1786+        </iq>
     1787+        """
     1788+
     1789+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     1790+        self.assertIdentical(None, request.nodeIdentifier)
     1791+
     1792+
     1793+    def test_fromElementDefault(self):
     1794+        """
     1795+        Test parsing a request for the default node configuration.
     1796+        """
     1797+
     1798+        xml = """
     1799+        <iq type='get' to='pubsub.example.org'
     1800+                       from='user@example.org'>
     1801+          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
     1802+            <default/>
     1803+          </pubsub>
     1804+        </iq>
     1805+        """
     1806+
     1807+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     1808+        self.assertEqual('default', request.verb)
     1809+        self.assertEqual(JID('user@example.org'), request.sender)
     1810+        self.assertEqual(JID('pubsub.example.org'), request.recipient)
     1811+        self.assertEqual('leaf', request.nodeType)
     1812+
     1813+
     1814+    def test_fromElementDefaultCollection(self):
     1815+        """
     1816+        Parsing a request for the default configuration extracts the node type.
     1817+        """
     1818+
     1819+        xml = """
     1820+        <iq type='get' to='pubsub.example.org'
     1821+                       from='user@example.org'>
     1822+          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
     1823+            <default>
     1824+              <x xmlns='jabber:x:data' type='submit'>
     1825+                <field var='FORM_TYPE' type='hidden'>
     1826+                  <value>http://jabber.org/protocol/pubsub#node_config</value>
     1827+                </field>
     1828+                <field var='pubsub#node_type'>
     1829+                  <value>collection</value>
     1830+                </field>
     1831+              </x>
     1832+            </default>
     1833+
     1834+          </pubsub>
     1835+        </iq>
     1836+        """
     1837+
     1838+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     1839+        self.assertEqual('collection', request.nodeType)
     1840+
     1841+
     1842+    def test_fromElementConfigureGet(self):
     1843+        """
     1844+        Test parsing a node configuration get request.
     1845+        """
     1846+
     1847+        xml = """
     1848+        <iq type='get' to='pubsub.example.org'
     1849+                       from='user@example.org'>
     1850+          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
     1851+            <configure node='test'/>
     1852+          </pubsub>
     1853+        </iq>
     1854+        """
     1855+
     1856+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     1857+        self.assertEqual('configureGet', request.verb)
     1858+        self.assertEqual(JID('user@example.org'), request.sender)
     1859+        self.assertEqual(JID('pubsub.example.org'), request.recipient)
     1860+        self.assertEqual('test', request.nodeIdentifier)
     1861+
     1862+
     1863+    def test_fromElementConfigureSet(self):
     1864+        """
     1865+        On a node configuration set request the Data Form is parsed.
     1866+        """
     1867+
     1868+        xml = """
     1869+        <iq type='set' to='pubsub.example.org'
     1870+                       from='user@example.org'>
     1871+          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
     1872+            <configure node='test'>
     1873+              <x xmlns='jabber:x:data' type='submit'>
     1874+                <field var='FORM_TYPE' type='hidden'>
     1875+                  <value>http://jabber.org/protocol/pubsub#node_config</value>
     1876+                </field>
     1877+                <field var='pubsub#deliver_payloads'><value>0</value></field>
     1878+                <field var='pubsub#persist_items'><value>1</value></field>
     1879+              </x>
     1880+            </configure>
     1881+          </pubsub>
     1882+        </iq>
     1883+        """
     1884+
     1885+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     1886+        self.assertEqual('configureSet', request.verb)
     1887+        self.assertEqual(JID('user@example.org'), request.sender)
     1888+        self.assertEqual(JID('pubsub.example.org'), request.recipient)
     1889+        self.assertEqual('test', request.nodeIdentifier)
     1890+        self.assertEqual({'pubsub#deliver_payloads': '0',
     1891+                          'pubsub#persist_items': '1'}, request.options)
     1892+
     1893+
     1894+    def test_fromElementConfigureSetCancel(self):
     1895+        """
     1896+        The node configuration is cancelled, so no options.
     1897+        """
     1898+
     1899+        xml = """
     1900+        <iq type='set' to='pubsub.example.org'
     1901+                       from='user@example.org'>
     1902+          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
     1903+            <configure node='test'>
     1904+              <x xmlns='jabber:x:data' type='cancel'/>
     1905+            </configure>
     1906+          </pubsub>
     1907+        </iq>
     1908+        """
     1909+
     1910+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     1911+        self.assertEqual({}, request.options)
     1912+
     1913+
     1914+    def test_fromElementConfigureSetBadFormType(self):
     1915+        """
     1916+        On a node configuration set request unknown fields should be ignored.
     1917+        """
     1918+
     1919+        xml = """
     1920+        <iq type='set' to='pubsub.example.org'
     1921+                       from='user@example.org'>
     1922+          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
     1923+            <configure node='test'>
     1924+              <x xmlns='jabber:x:data' type='result'>
     1925+                <field var='FORM_TYPE' type='hidden'>
     1926+                  <value>http://jabber.org/protocol/pubsub#node_config</value>
     1927+                </field>
     1928+                <field var='pubsub#deliver_payloads'><value>0</value></field>
     1929+                <field var='x-myfield'><value>1</value></field>
     1930+              </x>
     1931+            </configure>
     1932+          </pubsub>
     1933+        </iq>
     1934+        """
     1935+
     1936+        err = self.assertRaises(error.StanzaError,
     1937+                                pubsub.PubSubRequest.fromElement,
     1938+                                parseXml(xml))
     1939+        self.assertEqual('bad-request', err.condition)
     1940+        self.assertEqual(None, err.appCondition)
     1941+
     1942+
     1943+    def test_fromElementConfigureSetNoForm(self):
     1944+        """
     1945+        On a node configuration set request a form is required.
     1946+        """
     1947+
     1948+        xml = """
     1949+        <iq type='set' to='pubsub.example.org'
     1950+                       from='user@example.org'>
     1951+          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
     1952+            <configure node='test'/>
     1953+          </pubsub>
     1954+        </iq>
     1955+        """
     1956+        err = self.assertRaises(error.StanzaError,
     1957+                                pubsub.PubSubRequest.fromElement,
     1958+                                parseXml(xml))
     1959+        self.assertEqual('bad-request', err.condition)
     1960+        self.assertEqual(None, err.appCondition)
     1961+
     1962+
     1963+    def test_fromElementItems(self):
     1964+        """
     1965+        Test parsing an items request.
     1966+        """
     1967+        xml = """
     1968+        <iq type='get' to='pubsub.example.org'
     1969+                       from='user@example.org'>
     1970+          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1971+            <items node='test'/>
     1972+          </pubsub>
     1973+        </iq>
     1974+        """
     1975+
     1976+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     1977+        self.assertEqual('items', request.verb)
     1978+        self.assertEqual(JID('user@example.org'), request.sender)
     1979+        self.assertEqual(JID('pubsub.example.org'), request.recipient)
     1980+        self.assertEqual('test', request.nodeIdentifier)
     1981+        self.assertIdentical(None, request.maxItems)
     1982+        self.assertEqual([], request.itemIdentifiers)
     1983+
     1984+
     1985+    def test_fromElementRetract(self):
     1986+        """
     1987+        Test parsing a retract request.
     1988+        """
     1989+
     1990+        xml = """
     1991+        <iq type='set' to='pubsub.example.org'
     1992+                       from='user@example.org'>
     1993+          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1994+            <retract node='test'>
     1995+              <item id='item1'/>
     1996+              <item id='item2'/>
     1997+            </retract>
     1998+          </pubsub>
     1999+        </iq>
     2000+        """
     2001+
     2002+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     2003+        self.assertEqual('retract', request.verb)
     2004+        self.assertEqual(JID('user@example.org'), request.sender)
     2005+        self.assertEqual(JID('pubsub.example.org'), request.recipient)
     2006+        self.assertEqual('test', request.nodeIdentifier)
     2007+        self.assertEqual(['item1', 'item2'], request.itemIdentifiers)
     2008+
     2009+
     2010+    def test_fromElementPurge(self):
     2011+        """
     2012+        Test parsing a purge request.
     2013+        """
     2014+
     2015+        xml = """
     2016+        <iq type='set' to='pubsub.example.org'
     2017+                       from='user@example.org'>
     2018+          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
     2019+            <purge node='test'/>
     2020+          </pubsub>
     2021+        </iq>
     2022+        """
     2023+
     2024+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     2025+        self.assertEqual('purge', request.verb)
     2026+        self.assertEqual(JID('user@example.org'), request.sender)
     2027+        self.assertEqual(JID('pubsub.example.org'), request.recipient)
     2028+        self.assertEqual('test', request.nodeIdentifier)
     2029+
     2030+
     2031+    def test_fromElementDelete(self):
     2032+        """
     2033+        Test parsing a delete request.
     2034+        """
     2035+
     2036+        xml = """
     2037+        <iq type='set' to='pubsub.example.org'
     2038+                       from='user@example.org'>
     2039+          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
     2040+            <delete node='test'/>
     2041+          </pubsub>
     2042+        </iq>
     2043+        """
     2044+
     2045+        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     2046+        self.assertEqual('delete', request.verb)
     2047+        self.assertEqual(JID('user@example.org'), request.sender)
     2048+        self.assertEqual(JID('pubsub.example.org'), request.recipient)
     2049+        self.assertEqual('test', request.nodeIdentifier)
     2050+
     2051+
     2052+
     2053 class PubSubServiceTest(unittest.TestCase, TestableRequestHandlerMixin):
     2054     """
     2055     Tests for L{pubsub.PubSubService}.
     2056@@ -507,6 +1132,29 @@
    13832057         verify.verifyObject(iwokkel.IPubSubService, self.service)
    13842058 
     
    14102084         """
    14112085         Test getDiscoInfo calls getNodeInfo and returns some minimal info.
    1412 @@ -561,20 +584,149 @@
     2086@@ -524,28 +1172,6 @@
     2087         return d
     2088 
     2089 
     2090-    def test_onPublishNoNode(self):
     2091-        """
     2092-        The root node is always a collection, publishing is a bad request.
     2093-        """
     2094-        xml = """
     2095-        <iq type='set' to='pubsub.example.org'
     2096-                       from='user@example.org'>
     2097-          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     2098-            <publish/>
     2099-          </pubsub>
     2100-        </iq>
     2101-        """
     2102-
     2103-        def cb(result):
     2104-            self.assertEquals('bad-request', result.condition)
     2105-
     2106-        d = self.handleRequest(xml)
     2107-        self.assertFailure(d, error.StanzaError)
     2108-        d.addCallback(cb)
     2109-        return d
     2110-
     2111-
     2112     def test_onPublish(self):
     2113         """
     2114         A publish request should result in L{PubSubService.publish} being
     2115@@ -561,27 +1187,147 @@
    14132116         </iq>
    14142117         """
     
    14202123-            self.assertEqual([], items)
    14212124+        def publish(request):
    1422 +            self.assertEqual(JID('user@example.org'), request.sender)
    1423 +            self.assertEqual(JID('pubsub.example.org'), request.recipient)
    1424 +            self.assertEqual('test', request.nodeIdentifier)
    1425 +            self.assertEqual([], request.items)
    14262125             return defer.succeed(None)
    14272126 
     
    14312130 
    14322131 
    1433 +    def test_onPublishItems(self):
    1434 +        """
    1435 +        A publish request with items should pass the items onto C{publish}.
    1436 +        """
    1437 +
    1438 +        xml = """
    1439 +        <iq type='set' to='pubsub.example.org'
    1440 +                       from='user@example.org'>
    1441 +          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
    1442 +            <publish node='test'>
    1443 +              <item id="item1"/>
    1444 +              <item id="item2"/>
    1445 +            </publish>
    1446 +          </pubsub>
    1447 +        </iq>
    1448 +        """
    1449 +
    1450 +        def publish(request):
    1451 +            self.assertEqual(2, len(request.items))
    1452 +            self.assertEqual(u'item1', request.items[0]["id"])
    1453 +            self.assertEqual(u'item2', request.items[1]["id"])
    1454 +            return defer.succeed(None)
    1455 +
    1456 +        self.service.publish = publish
    1457 +        verify.verifyObject(iwokkel.IPubSubService, self.service)
    1458 +        return self.handleRequest(xml)
    1459 +
    1460 +
    14612132+    def test_onSubscribe(self):
    14622133+        """
     
    14742145+
    14752146+        def subscribe(request):
    1476 +            self.assertEqual(JID('user@example.org'), request.sender)
    1477 +            self.assertEqual(JID('pubsub.example.org'), request.recipient)
    1478 +            self.assertEqual('test', request.nodeIdentifier)
    1479 +            self.assertEqual(JID('user@example.org/Home'), request.subscriber)
    14802147+            return defer.succeed(pubsub.Subscription(request.nodeIdentifier,
    14812148+                                                     request.subscriber,
     
    15132180+
    15142181+        def subscribe(request):
    1515 +            self.assertEqual('', request.nodeIdentifier)
    15162182+            return defer.succeed(pubsub.Subscription(request.nodeIdentifier,
    15172183+                                                     request.subscriber,
     
    15432209+
    15442210+        def unsubscribe(request):
    1545 +            self.assertEqual(JID('user@example.org'), request.sender)
    1546 +            self.assertEqual(JID('pubsub.example.org'), request.recipient)
    1547 +            self.assertEqual('test', request.nodeIdentifier)
    1548 +            self.assertEqual(JID('user@example.org/Home'), request.subscriber)
    15492211+            return defer.succeed(None)
    15502212+
     
    15662228 
    15672229         xml = """
    1568 @@ -597,6 +749,31 @@
    1569          return d
    1570  
    1571  
    1572 +    def test_onOptionsSet(self):
    1573 +        """
    1574 +        Setting subscription options is not supported.
    1575 +        """
    1576 +
    1577 +        xml = """
    1578 +        <iq type='set' to='pubsub.example.org'
    1579 +                       from='user@example.org'>
    1580 +          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
    1581 +            <options/>
     2230         <iq type='get' to='pubsub.example.org'
     2231                        from='user@example.org'>
     2232           <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     2233-            <options/>
     2234+            <options node='test' jid='user@example.org/Home'/>
    15822235+          </pubsub>
    15832236+        </iq>
     
    15952248+
    15962249+
    1597      def test_onSubscriptions(self):
    1598          """
    1599          A subscriptions request should result in
    1600 @@ -627,14 +804,149 @@
     2250+    def test_onOptionsSet(self):
     2251+        """
     2252+        Setting subscription options is not supported.
     2253+        """
     2254+
     2255+        xml = """
     2256+        <iq type='set' to='pubsub.example.org'
     2257+                       from='user@example.org'>
     2258+          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     2259+            <options node='test' jid='user@example.org/Home'>
     2260+              <x xmlns='jabber:x:data' type='submit'>
     2261+                <field var='FORM_TYPE' type='hidden'>
     2262+                  <value>http://jabber.org/protocol/pubsub#subscribe_options</value>
     2263+                </field>
     2264+                <field var='pubsub#deliver'><value>1</value></field>
     2265+              </x>
     2266+            </options>
     2267           </pubsub>
     2268         </iq>
     2269         """
     2270@@ -627,14 +1373,141 @@
    16012271             self.assertEqual('subscribed', subscription['subscription'])
    16022272 
     
    16062276-            self.assertEqual(JID('pubsub.example.org'), service)
    16072277+        def subscriptions(request):
    1608 +            self.assertEqual(JID('user@example.org'), request.sender)
    1609 +            self.assertEqual(JID('pubsub.example.org'), request.recipient)
    16102278             subscription = pubsub.Subscription('test', JID('user@example.org'),
    16112279                                                'subscribed')
     
    16492317+
    16502318+        def affiliations(request):
    1651 +            self.assertEqual(JID('user@example.org'), request.sender)
    1652 +            self.assertEqual(JID('pubsub.example.org'), request.recipient)
    16532319+            affiliation = ('test', 'owner')
    16542320+            return defer.succeed([affiliation])
     
    16762342+
    16772343+        def create(request):
    1678 +            self.assertEqual(JID('user@example.org'), request.sender)
    1679 +            self.assertEqual(JID('pubsub.example.org'), request.recipient)
    1680 +            self.assertEqual('mynode', request.nodeIdentifier)
    16812344+            return defer.succeed(request.nodeIdentifier)
    16822345+
     
    17372400+
    17382401+        def create(request):
    1739 +            self.assertIdentical(None, request.nodeIdentifier)
    17402402+            return defer.succeed(u'random')
    17412403+
     
    17512413         d.addCallback(cb)
    17522414         return d
    1753 @@ -665,10 +977,10 @@
     2415@@ -665,10 +1538,7 @@
    17542416                      "label": "Deliver payloads with event notifications"}
    17552417                 }
     
    17602422-            self.assertEqual('leaf', nodeType)
    17612423+        def getDefaultConfiguration(request):
    1762 +            self.assertEqual(JID('user@example.org'), request.sender)
    1763 +            self.assertEqual(JID('pubsub.example.org'), request.recipient)
    1764 +            self.assertEqual('leaf', request.nodeType)
    17652424             return defer.succeed({})
    17662425 
    17672426         def cb(element):
    1768 @@ -686,6 +998,95 @@
     2427@@ -686,6 +1556,85 @@
    17692428         return d
    17702429 
     
    18022461+
    18032462+        def getDefaultConfiguration(request):
    1804 +            self.assertEqual('collection', request.nodeType)
    18052463+            return defer.succeed({})
    1806 +
    1807 +        def cb(element):
    1808 +            self.assertEqual('pubsub', element.name)
    1809 +            self.assertEqual(NS_PUBSUB_OWNER, element.uri)
    1810 +            self.assertEqual(NS_PUBSUB_OWNER, element.default.uri)
    1811 +            form = data_form.Form.fromElement(element.default.x)
    1812 +            self.assertEqual(NS_PUBSUB_CONFIG, form.formNamespace)
    18132464+
    18142465+        self.service.getConfigurationOptions = getConfigurationOptions
    18152466+        self.service.getDefaultConfiguration = getDefaultConfiguration
    18162467+        verify.verifyObject(iwokkel.IPubSubService, self.service)
    1817 +        d = self.handleRequest(xml)
    1818 +        d.addCallback(cb)
    1819 +        return d
     2468+        return self.handleRequest(xml)
    18202469+
    18212470+
     
    18622511         """
    18632512         On a node configuration get request L{PubSubService.getConfiguration}
    1864 @@ -714,14 +1115,15 @@
     2513@@ -714,14 +1663,11 @@
    18652514                      "label": "Owner of the node"}
    18662515                 }
     
    18702519-            self.assertEqual(JID('pubsub.example.org'), service)
    18712520-            self.assertEqual('test', nodeIdentifier)
     2521-
    18722522+        def getConfiguration(request):
    1873 +            self.assertEqual(JID('user@example.org'), request.sender)
    1874 +            self.assertEqual(JID('pubsub.example.org'), request.recipient)
    1875 +            self.assertEqual('test', request.nodeIdentifier)
    1876  
    18772523             return defer.succeed({'pubsub#deliver_payloads': '0',
    18782524                                   'pubsub#persist_items': '1',
     
    18832529         def cb(element):
    18842530             self.assertEqual('pubsub', element.name)
    1885 @@ -749,8 +1151,12 @@
     2531@@ -749,8 +1695,12 @@
    18862532             field.typeCheck()
    18872533             self.assertEqual(JID('user@example.org'), field.value)
     
    18962542         d.addCallback(cb)
    18972543         return d
    1898 @@ -789,16 +1195,17 @@
     2544@@ -789,16 +1739,14 @@
    18992545                      "label": "Deliver payloads with event notifications"}
    19002546                 }
     
    19052551-            self.assertEqual('test', nodeIdentifier)
    19062552+        def setConfiguration(request):
    1907 +            self.assertEqual(JID('user@example.org'), request.sender)
    1908 +            self.assertEqual(JID('pubsub.example.org'), request.recipient)
    1909 +            self.assertEqual('test', request.nodeIdentifier)
    19102553             self.assertEqual({'pubsub#deliver_payloads': False,
    19112554-                              'pubsub#persist_items': True}, options)
     
    19192562 
    19202563 
    1921 @@ -823,10 +1230,11 @@
     2564@@ -823,10 +1771,11 @@
    19222565         </iq>
    19232566         """
     
    19322575 
    19332576 
    1934 @@ -862,14 +1270,47 @@
     2577@@ -862,14 +1811,47 @@
    19352578                      "label": "Deliver payloads with event notifications"}
    19362579                 }
     
    19822625         """
    19832626         On a items request, return all items for the given node.
    1984 @@ -883,12 +1324,12 @@
     2627@@ -883,12 +1865,7 @@
    19852628         </iq>
    19862629         """
     
    19932636-            self.assertEqual([], items)
    19942637+        def items(request):
    1995 +            self.assertEqual(JID('user@example.org'), request.sender)
    1996 +            self.assertEqual(JID('pubsub.example.org'), request.recipient)
    1997 +            self.assertEqual('test', request.nodeIdentifier)
    1998 +            self.assertIdentical(None, request.maxItems)
    1999 +            self.assertEqual([], request.itemIdentifiers)
    20002638             return defer.succeed([pubsub.Item('current')])
    20012639 
    20022640         def cb(element):
    2003 @@ -925,11 +1366,11 @@
     2641@@ -925,11 +1902,7 @@
    20042642         </iq>
    20052643         """
     
    20112649-            self.assertEqual(['item1', 'item2'], itemIdentifiers)
    20122650+        def retract(request):
    2013 +            self.assertEqual(JID('user@example.org'), request.sender)
    2014 +            self.assertEqual(JID('pubsub.example.org'), request.recipient)
    2015 +            self.assertEqual('test', request.nodeIdentifier)
    2016 +            self.assertEqual(['item1', 'item2'], request.itemIdentifiers)
    20172651             return defer.succeed(None)
    20182652 
    20192653         self.service.retract = retract
    2020 @@ -951,10 +1392,10 @@
     2654@@ -951,10 +1924,7 @@
    20212655         </iq>
    20222656         """
     
    20272661-            self.assertEqual('test', nodeIdentifier)
    20282662+        def purge(request):
    2029 +            self.assertEqual(JID('user@example.org'), request.sender)
    2030 +            self.assertEqual(JID('pubsub.example.org'), request.recipient)
    2031 +            self.assertEqual('test', request.nodeIdentifier)
    20322663             return defer.succeed(None)
    20332664 
    20342665         self.service.purge = purge
    2035 @@ -976,10 +1417,10 @@
     2666@@ -976,10 +1946,7 @@
    20362667         </iq>
    20372668         """
     
    20422673-            self.assertEqual('test', nodeIdentifier)
    20432674+        def delete(request):
    2044 +            self.assertEqual(JID('user@example.org'), request.sender)
    2045 +            self.assertEqual(JID('pubsub.example.org'), request.recipient)
    2046 +            self.assertEqual('test', request.nodeIdentifier)
    20472675             return defer.succeed(None)
    20482676 
    20492677         self.service.delete = delete
    2050 @@ -1031,3 +1472,461 @@
     2678@@ -1031,3 +1998,461 @@
    20512679         self.assertEqual(NS_PUBSUB_EVENT, message.event.delete.redirect.uri)
    20522680         self.assertTrue(message.event.delete.redirect.hasAttribute('uri'))
  • pubsub_resource.patch

    r4 r5  
    1 diff -r dc8ed1ff55d7 wokkel/iwokkel.py
    2 --- a/wokkel/iwokkel.py Wed Mar 18 09:26:24 2009 +0100
    3 +++ b/wokkel/iwokkel.py Wed Mar 18 20:51:58 2009 +0100
    4 @@ -297,76 +297,14 @@
     1diff -r 2ea6196efcdc wokkel/iwokkel.py
     2--- a/wokkel/iwokkel.py Wed Mar 25 18:14:07 2009 +0100
     3+++ b/wokkel/iwokkel.py Mon Mar 30 08:35:05 2009 +0200
     4@@ -297,75 +297,46 @@
    55         """
    66 
     
    1717         @type request: L{wokkel.pubsub.PubSubRequest}
    1818-        @return: deferred that fires on success.
    19 -        @rtype: L{defer.Deferred}
    20 -        """
    21 -
    22 -
     19+        """
     20+
     21+
     22+    def getInfo(requestor, service, nodeIdentifier):
     23+        """
     24+        Get node type and meta data.
     25+
     26+        @param requestor: The entity the request originated from.
     27+        @type requestor: L{jid.JID}
     28+        @param service: The publish-subscribe service entity.
     29+        @type service: L{jid.JID}
     30+        @param nodeIdentifier: Identifier of the node to request the info for.
     31+        @type nodeIdentifier: L{unicode}
     32+        @return: A deferred that fires with a dictionary. If not empty,
     33+                 it must have the keys C{'type'} and C{'meta-data'} to keep
     34+                 respectively the node type and a dictionary with the meta
     35+                 data for that node.
     36         @rtype: L{defer.Deferred}
     37         """
     38 
     39 
    2340-    def subscribe(request):
    24 -        """
     41+    def getNodes(requestor, service, nodeIdentifier):
     42         """
    2543-        Called when a subscribe request has been received.
    26 -
     44+        Get all nodes contained by this node.
     45 
    2746-        @param request: The publish-subscribe request.
    2847-        @type request: L{wokkel.pubsub.PubSubRequest}
     
    7998-        @return: A deferred that fires with a C{unicode} that represents
    8099-                 the identifier of the new node.
    81 -        @rtype: L{defer.Deferred}
    82          """
    83  
    84  
    85 @@ -406,7 +344,80 @@
     100+        @param requestor: The entity the request originated from.
     101+        @type requestor: L{jid.JID}
     102+        @param service: The publish-subscribe service entity.
     103+        @type service: L{jid.JID}
     104+        @param nodeIdentifier: Identifier of the node to request the childs for.
     105+        @type nodeIdentifier: L{unicode}
     106+        @return: A deferred that fires with a list of child node identifiers.
     107         @rtype: L{defer.Deferred}
     108         """
     109 
     110@@ -406,7 +377,80 @@
    86111         """
    87112 
    88113 
    89114-    def getDefaultConfiguration(request):
    90 +    def pubsub_publish(request):
     115+    def publish(request):
    91116+        """
    92117+        Called when a publish request has been received.
     
    99124+
    100125+
    101 +    def pubsub_subscribe(request):
     126+    def subscribe(request):
    102127+        """
    103128+        Called when a subscribe request has been received.
     
    111136+
    112137+
    113 +    def pubsub_unsubscribe(request):
     138+    def unsubscribe(request):
    114139+        """
    115140+        Called when a subscribe request has been received.
     
    123148+
    124149+
    125 +    def pubsub_subscriptions(request):
     150+    def subscriptions(request):
    126151+        """
    127152+        Called when a subscriptions retrieval request has been received.
     
    135160+
    136161+
    137 +    def pubsub_affiliations(request):
     162+    def affiliations(request):
    138163+        """
    139164+        Called when a affiliations retrieval request has been received.
     
    149174+
    150175+
    151 +    def pubsub_create(request):
     176+    def create(request):
    152177+        """
    153178+        Called when a node creation request has been received.
     
    161186+
    162187+
    163 +    def pubsub_default(request):
     188+    def default(request):
    164189         """
    165190         Called when a default node configuration request has been received.
    166191 
    167 @@ -420,7 +431,7 @@
     192@@ -420,7 +464,7 @@
    168193         """
    169194 
    170195 
    171196-    def getConfiguration(request):
    172 +    def pubsub_configureGet(request):
     197+    def configureGet(request):
    173198         """
    174199         Called when a node configuration retrieval request has been received.
    175200 
    176 @@ -433,7 +444,7 @@
     201@@ -433,7 +477,7 @@
    177202         """
    178203 
    179204 
    180205-    def setConfiguration(request):
    181 +    def pubsub_configureSet(request):
     206+    def configureSet(request):
    182207         """
    183208         Called when a node configuration change request has been received.
    184209 
    185 @@ -445,7 +456,7 @@
    186          """
    187  
    188  
    189 -    def items(request):
    190 +    def pubsub_items(request):
    191          """
    192          Called when a items retrieval request has been received.
    193  
    194 @@ -456,7 +467,7 @@
    195          """
    196  
    197  
    198 -    def retract(request):
    199 +    def pubsub_retract(request):
    200          """
    201          Called when a item retraction request has been received.
    202  
    203 @@ -468,7 +479,7 @@
    204          """
    205  
    206  
    207 -    def purge(request):
    208 +    def pubsub_purge(request):
    209          """
    210          Called when a node purge request has been received.
    211  
    212 @@ -480,7 +491,7 @@
    213          """
    214  
    215  
    216 -    def delete(request):
    217 +    def pubsub_delete(request):
    218          """
    219          Called when a node deletion request has been received.
    220  
    221 diff -r dc8ed1ff55d7 wokkel/pubsub.py
    222 --- a/wokkel/pubsub.py  Wed Mar 18 09:26:24 2009 +0100
    223 +++ b/wokkel/pubsub.py  Wed Mar 18 20:51:58 2009 +0100
    224 @@ -18,7 +18,7 @@
     210diff -r 2ea6196efcdc wokkel/pubsub.py
     211--- a/wokkel/pubsub.py  Wed Mar 25 18:14:07 2009 +0100
     212+++ b/wokkel/pubsub.py  Mon Mar 30 08:35:05 2009 +0200
     213@@ -13,12 +13,13 @@
     214 from zope.interface import implements
     215 
     216 from twisted.internet import defer
     217+from twisted.python import log
     218 from twisted.words.protocols.jabber import jid, error, xmlstream
     219 from twisted.words.xish import domish
    225220 
    226221 from wokkel import disco, data_form, generic, shim
     
    231226 # Iq get and set XPath queries
    232227 IQ_GET = '/iq[@type="get"]'
    233 @@ -77,11 +77,16 @@
     228@@ -84,11 +85,16 @@
    234229 
    235230 class Unsupported(PubSubError):
     
    248243 
    249244 class Subscription(object):
    250 @@ -228,9 +233,9 @@
     245@@ -235,9 +241,9 @@
    251246         'retract': ['node', 'itemIdentifiers'],
    252247         'purge': ['node'],
     
    260255     }
    261256 
    262 @@ -359,6 +364,9 @@
    263          else:
    264              self.nodeType = 'leaf'
    265  
    266 +        if self.nodeType not in ('leaf', 'collection'):
    267 +            raise error.StanzaError('not-acceptable')
    268 +
    269  
    270      def _parse_configure(self, verbElement):
    271          """
    272 @@ -787,8 +795,8 @@
     257@@ -806,13 +812,10 @@
    273258             '/*': '_onPubSubRequest',
    274259             }
    275260 
    276 -
     261+    hideNodes = False
     262 
    277263-    def __init__(self):
     264-        self.discoIdentity = {'category': 'pubsub',
     265-                              'type': 'generic',
     266-                              'name': 'Generic Publish-Subscribe Service'}
     267-
     268-        self.pubSubFeatures = []
    278269+    def __init__(self, resource):
    279270+        self.resource = resource
    280          self.discoIdentity = {'category': 'pubsub',
    281                                'type': 'generic',
    282                                'name': 'Generic Publish-Subscribe Service'}
    283 @@ -851,91 +859,80 @@
     271 
     272 
     273     def connectionMade(self):
     274@@ -820,19 +823,9 @@
     275 
     276 
     277     def getDiscoInfo(self, requestor, target, nodeIdentifier):
     278-        info = []
     279-
     280-        if not nodeIdentifier:
     281-            category, idType, name = self.discoIdentity
     282-            info.append(disco.DiscoIdentity(category, idType, name))
     283-
     284-            info.append(disco.DiscoFeature(disco.NS_DISCO_ITEMS))
     285-            info.extend([disco.DiscoFeature("%s#%s" % (NS_PUBSUB, feature))
     286-                         for feature in self.pubSubFeatures])
     287-
     288-        def toInfo(nodeInfo):
     289+        def toInfo(nodeInfo, info):
     290             if not nodeInfo:
     291-                return
     292+                return info
     293 
     294             (nodeType, metaData) = nodeInfo['type'], nodeInfo['meta-data']
     295             info.append(disco.DiscoIdentity('pubsub', nodeType))
     296@@ -852,17 +845,33 @@
     297 
     298                 info.append(form.toElement())
     299 
     300-        d = self.getNodeInfo(requestor, target, nodeIdentifier or '')
     301-        d.addCallback(toInfo)
     302-        d.addBoth(lambda result: info)
     303+            return info
     304+
     305+        info = []
     306+
     307+        request = PubSubRequest('discoInfo')
     308+        resource = self.resource.locateResource(request)
     309+
     310+        if not nodeIdentifier:
     311+            info.append(resource.discoIdentity)
     312+            info.append(disco.DiscoFeature(disco.NS_DISCO_ITEMS))
     313+            info.extend([disco.DiscoFeature("%s#%s" % (NS_PUBSUB, feature))
     314+                         for feature in resource.features])
     315+
     316+        d = resource.getInfo(requestor, target, nodeIdentifier or '')
     317+        d.addCallback(toInfo, info)
     318+        d.addErrback(log.err)
     319         return d
     320 
     321 
     322     def getDiscoItems(self, requestor, target, nodeIdentifier):
     323-        if nodeIdentifier or self.hideNodes:
     324+        request = PubSubRequest('discoInfo')
     325+        resource = self.resource.locateResource(request)
     326+
     327+        if self.hideNodes:
     328             return defer.succeed([])
     329 
     330-        d = self.getNodes(requestor, target)
     331+        d = resource.getNodes(requestor, target, nodeIdentifier)
     332         d.addCallback(lambda nodes: [disco.DiscoItem(target, node)
     333                                      for node in nodes])
     334         return d
     335@@ -870,91 +879,80 @@
    284336 
    285337     def _onPubSubRequest(self, iq):
     
    303355+        # Process the request itself,
    304356+        try:
    305 +            handler = getattr(resource, 'pubsub_%s' % request.verb)
     357+            handler = getattr(resource, request.verb)
    306358+        except AttributeError:
    307359+            # fix lookup feature
     
    430482 
    431483     def _makeFields(self, options, values):
    432 @@ -954,8 +951,8 @@
     484@@ -973,8 +971,8 @@
    433485         return fields
    434486 
     
    441493         form = data_form.Form(formType="form",
    442494                               formNamespace=NS_PUBSUB_NODE_CONFIG,
    443 @@ -964,8 +961,8 @@
     495@@ -983,8 +981,8 @@
    444496         return form
    445497 
     
    452504 
    453505         for key, value in values.iteritems():
    454 @@ -989,93 +986,45 @@
     506@@ -1008,93 +1006,52 @@
    455507         return processedValues
    456508 
    457509 
    458510-    def _on_default(self, request):
     511+    def _preProcess_default(self, resource, request):
     512+        if request.nodeType not in ('leaf', 'collection'):
     513+            raise error.StanzaError('not-acceptable')
     514+        else:
     515+            return request
     516 
     517-        def toResponse(options):
     518-            response = domish.Element((NS_PUBSUB_OWNER, "pubsub"))
     519-            default = response.addElement("default")
     520-            default.addChild(self._formFromConfiguration(options).toElement())
     521-            return response
     522 
     523-        if request.nodeType not in ('leaf', 'collection'):
     524-            return defer.fail(error.StanzaError('not-acceptable'))
    459525+    def _toResponse_default(self, options, resource, request):
    460526+        response = domish.Element((NS_PUBSUB_OWNER, "pubsub"))
     
    464530+        return response
    465531 
    466 -        def toResponse(options):
    467 -            response = domish.Element((NS_PUBSUB_OWNER, "pubsub"))
    468 -            default = response.addElement("default")
    469 -            default.addChild(self._formFromConfiguration(options).toElement())
    470 -            return response
    471  
    472 -        if request.nodeType not in ('leaf', 'collection'):
    473 -            return defer.fail(error.StanzaError('not-acceptable'))
     532-        d = self.getDefaultConfiguration(request)
     533-        d.addCallback(toResponse)
     534-        return d
     535 
    474536+    def _toResponse_configureGet(self, options, resource, request):
    475537+        response = domish.Element((NS_PUBSUB_OWNER, "pubsub"))
     
    477539+        form = self._formFromConfiguration(resource, options)
    478540+        configure.addChild(form.toElement())
    479  
    480 -        d = self.getDefaultConfiguration(request)
    481 -        d.addCallback(toResponse)
    482 -        return d
    483 +        if request.nodeIdentifier:
    484 +            configure["node"] = request.nodeIdentifier
    485  
    486 +        return response
    487541 
    488542-    def _on_configureGet(self, request):
     
    492546-            form = self._formFromConfiguration(options)
    493547-            configure.addChild(form.toElement())
     548+        if request.nodeIdentifier:
     549+            configure["node"] = request.nodeIdentifier
    494550 
    495551-            if request.nodeIdentifier:
    496552-                configure["node"] = request.nodeIdentifier
    497 -
     553+        return response
     554 
    498555-            return response
    499 -
     556 
    500557-        d = self.getConfiguration(request)
    501558-        d.addCallback(toResponse)
     
    571628     def _createNotification(self, eventType, service, nodeIdentifier,
    572629                                   subscriber, subscriptions=None):
    573 @@ -1099,6 +1048,8 @@
     630@@ -1118,6 +1075,8 @@
    574631 
    575632         return message
     
    580637         for subscriber, subscriptions, items in notifications:
    581638             message = self._createNotification('items', service,
    582 @@ -1120,65 +1071,90 @@
     639@@ -1139,65 +1098,96 @@
    583640             self.send(message)
    584641 
     
    586643-    def getNodeInfo(self, requestor, service, nodeIdentifier):
    587644-        return None
    588 +
     645 
    589646+class PubSubResource(object):
    590 +
     647 
     648-    def getNodes(self, requestor, service):
     649-        return []
    591650+    implements(IPubSubResource)
    592 +
     651 
     652+    features = []
     653+    discoIdentity = disco.DiscoIdentity('pubsub',
     654+                                        'service',
     655+                                        'Publish-Subscribe Service')
     656 
     657-    def publish(self, request):
     658-        raise Unsupported('publish')
     659 
    593660+    def locateResource(self, request):
    594661+        return self
    595 +
    596 +
     662 
     663-    def subscribe(self, request):
     664-        raise Unsupported('subscribe')
     665 
    597666+    def getInfo(self, requestor, service, nodeIdentifier):
    598667+        return defer.succeed(None)
    599668 
    600  
    601      def getNodes(self, requestor, service):
    602          return []
    603  
    604  
    605 -    def publish(self, request):
    606 -        raise Unsupported('publish')
    607 -
    608 -
    609 -    def subscribe(self, request):
    610 -        raise Unsupported('subscribe')
    611 -
    612 -
    613669-    def unsubscribe(self, request):
    614670-        raise Unsupported('subscribe')
    615 -
     671 
    616672-
    617673-    def subscriptions(self, request):
     
    625681-    def create(self, request):
    626682-        raise Unsupported('create-nodes')
    627 -
    628 -
     683+    def getNodes(self, requestor, service, nodeIdentifier):
     684+        return defer.succeed([])
     685 
     686 
    629687     def getConfigurationOptions(self):
    630688         return {}
     
    633691-    def getDefaultConfiguration(self, request):
    634692-        raise Unsupported('retrieve-default')
    635 +    def pubsub_publish(self, request):
     693+    def publish(self, request):
    636694+        return defer.fail(Unsupported('publish'))
    637695 
     
    639697-    def getConfiguration(self, request):
    640698-        raise Unsupported('config-node')
    641 +    def pubsub_subscribe(self, request):
     699+    def subscribe(self, request):
    642700+        return defer.fail(Unsupported('subscribe'))
    643701 
     
    645703-    def setConfiguration(self, request):
    646704-        raise Unsupported('config-node')
    647 +    def pubsub_unsubscribe(self, request):
     705+    def unsubscribe(self, request):
    648706+        return defer.fail(Unsupported('subscribe'))
    649  
    650  
    651 -    def items(self, request):
     707+
     708+
     709+    def subscriptions(self, request):
     710+        return defer.fail(Unsupported('retrieve-subscriptions'))
     711+
     712+
     713+    def affiliations(self, request):
     714+        return defer.fail(Unsupported('retrieve-affiliations'))
     715+
     716+
     717+    def create(self, request):
     718+        return defer.fail(Unsupported('create-nodes'))
     719+
     720+
     721+    def default(self, request):
     722+        return defer.fail(Unsupported('retrieve-default'))
     723+
     724+
     725+    def configureGet(self, request):
     726+        return defer.fail(Unsupported('config-node'))
     727+
     728+
     729+    def configureSet(self, request):
     730+        return defer.fail(Unsupported('config-node'))
     731 
     732 
     733     def items(self, request):
    652734-        raise Unsupported('retrieve-items')
    653 +    def pubsub_subscriptions(self, request):
    654 +        return defer.fail(Unsupported('retrieve-subscriptions'))
    655  
    656  
    657 -    def retract(self, request):
     735+        return defer.fail(Unsupported('retrieve-items'))
     736 
     737 
     738     def retract(self, request):
    658739-        raise Unsupported('retract-items')
    659 +    def pubsub_affiliations(self, request):
    660 +        return defer.fail(Unsupported('retrieve-affiliations'))
    661  
    662  
    663 -    def purge(self, request):
     740+        return defer.fail(Unsupported('retract-items'))
     741 
     742 
     743     def purge(self, request):
    664744-        raise Unsupported('purge-nodes')
    665 +    def pubsub_create(self, request):
    666 +        return defer.fail(Unsupported('create-nodes'))
    667  
    668  
    669 -    def delete(self, request):
     745+        return defer.fail(Unsupported('purge-nodes'))
     746 
     747 
     748     def delete(self, request):
    670749-        raise Unsupported('delete-nodes')
    671 +    def pubsub_default(self, request):
    672 +        return defer.fail(Unsupported('retrieve-default'))
    673 +
    674 +
    675 +    def pubsub_configureGet(self, request):
    676 +        return defer.fail(Unsupported('config-node'))
    677 +
    678 +
    679 +    def pubsub_configureSet(self, request):
    680 +        return defer.fail(Unsupported('config-node'))
    681 +
    682 +
    683 +    def pubsub_items(self, request):
    684 +        return defer.fail(Unsupported('retrieve-items'))
    685 +
    686 +
    687 +    def pubsub_retract(self, request):
    688 +        return defer.fail(Unsupported('retract-items'))
    689 +
    690 +
    691 +    def pubsub_purge(self, request):
    692 +        return defer.fail(Unsupported('purge-nodes'))
    693 +
    694 +
    695 +    def pubsub_delete(self, request):
    696750+        return defer.fail(Unsupported('delete-nodes'))
    697751+
    698752+
    699 +    def pubsub_affiliationsGet(self, request):
     753+    def affiliationsGet(self, request):
    700754+        return defer.fail(Unsupported('modify-affiliations'))
    701755+
    702756+
    703 +    def pubsub_affiliationsSet(self, request):
     757+    def affiliationsSet(self, request):
    704758+        return defer.fail(Unsupported('modify-affiliations'))
    705759+
    706760+
    707 +    def pubsub_subscriptionsGet(self, request):
     761+    def subscriptionsGet(self, request):
    708762+        return defer.fail(Unsupported('manage-subscriptions'))
    709763+
    710764+
    711 +    def pubsub_subscriptionsSet(self, request):
     765+    def subscriptionsSet(self, request):
    712766+        return defer.fail(Unsupported('manage-subscriptions'))
    713 diff -r dc8ed1ff55d7 wokkel/test/test_pubsub.py
    714 --- a/wokkel/test/test_pubsub.py        Wed Mar 18 09:26:24 2009 +0100
    715 +++ b/wokkel/test/test_pubsub.py        Wed Mar 18 20:51:58 2009 +0100
    716 @@ -600,7 +600,8 @@
     767diff -r 2ea6196efcdc wokkel/test/test_pubsub.py
     768--- a/wokkel/test/test_pubsub.py        Wed Mar 25 18:14:07 2009 +0100
     769+++ b/wokkel/test/test_pubsub.py        Mon Mar 30 08:35:05 2009 +0200
     770@@ -13,7 +13,7 @@
     771 from twisted.words.protocols.jabber import error
     772 from twisted.words.protocols.jabber.jid import JID
     773 
     774-from wokkel import data_form, iwokkel, pubsub, shim
     775+from wokkel import data_form, disco, iwokkel, pubsub, shim
     776 from wokkel.generic import parseXml
     777 from wokkel.test.helpers import TestableRequestHandlerMixin, XmlStreamStub
     778 
     779@@ -1225,7 +1225,8 @@
    717780 
    718781     def setUp(self):
     
    724787 
    725788     def test_interface(self):
    726 @@ -694,8 +695,8 @@
    727              self.assertEqual([], request.items)
     789@@ -1263,19 +1264,120 @@
     790         Test getDiscoInfo calls getNodeInfo and returns some minimal info.
     791         """
     792         def cb(info):
     793-            self.assertEqual(2, len(info))
     794+            discoInfo = disco.DiscoInfo()
     795+            for item in info:
     796+                discoInfo.append(item)
     797+            self.assertIn(('pubsub', 'service'), discoInfo.identities)
     798+            self.assertIn(disco.NS_DISCO_ITEMS, discoInfo.features)
     799 
     800-        def getNodeInfo(requestor, target, nodeIdentifier):
     801-            return defer.succeed(None)
     802-
     803-        self.service.getNodeInfo = getNodeInfo
     804         d = self.service.getDiscoInfo(JID('user@example.org/home'),
     805                                       JID('pubsub.example.org'), '')
     806         d.addCallback(cb)
     807         return d
     808 
     809 
     810-    def test_onPublish(self):
     811+    def test_getDiscoInfoNodeType(self):
     812+        """
     813+        Test getDiscoInfo calls getNodeInfo and returns some minimal info.
     814+        """
     815+        def cb(info):
     816+            discoInfo = disco.DiscoInfo()
     817+            for item in info:
     818+                discoInfo.append(item)
     819+            self.assertIn(('pubsub', 'collection'), discoInfo.identities)
     820+
     821+        def getInfo(requestor, target, nodeIdentifier):
     822+            return defer.succeed({'type': 'collection',
     823+                                  'meta-data': {}})
     824+
     825+        self.resource.getInfo = getInfo
     826+        d = self.service.getDiscoInfo(JID('user@example.org/home'),
     827+                                      JID('pubsub.example.org'), '')
     828+        d.addCallback(cb)
     829+        return d
     830+
     831+
     832+    def test_getDiscoInfoResourceFeatures(self):
     833+        """
     834+        Test getDiscoInfo calls getNodeInfo and returns some minimal info.
     835+        """
     836+        def cb(info):
     837+            discoInfo = disco.DiscoInfo()
     838+            for item in info:
     839+                discoInfo.append(item)
     840+            self.assertIn('http://jabber.org/protocol/pubsub#publish',
     841+                          discoInfo.features)
     842+
     843+        self.resource.features = ['publish']
     844+        d = self.service.getDiscoInfo(JID('user@example.org/home'),
     845+                                      JID('pubsub.example.org'), '')
     846+        d.addCallback(cb)
     847+        return d
     848+
     849+
     850+    def test_getDiscoItemsRoot(self):
     851+        """
     852+        Test getDiscoItems on the root node.
     853+        """
     854+        def getNodes(requestor, service, nodeIdentifier):
     855+            return defer.succeed(['node1', 'node2'])
     856+
     857+        def cb(items):
     858+            self.assertEqual(2, len(items))
     859+            item1, item2 = items
     860+
     861+            self.assertEqual(JID('pubsub.example.org'), item1.entity)
     862+            self.assertEqual('node1', item1.nodeIdentifier)
     863+
     864+            self.assertEqual(JID('pubsub.example.org'), item2.entity)
     865+            self.assertEqual('node2', item2.nodeIdentifier)
     866+
     867+        self.resource.getNodes = getNodes
     868+        d = self.service.getDiscoItems(JID('user@example.org/home'),
     869+                                       JID('pubsub.example.org'),
     870+                                       '')
     871+        d.addCallback(cb)
     872+        return d
     873+
     874+
     875+    def test_getDiscoItemsRootHideNodes(self):
     876+        """
     877+        Test getDiscoItems on the root node.
     878+        """
     879+        def getNodes(requestor, service, nodeIdentifier):
     880+            raise Exception("Unexpected call to getNodes")
     881+
     882+        def cb(items):
     883+            self.assertEqual([], items)
     884+
     885+        self.service.hideNodes = True
     886+        self.resource.getNodes = getNodes
     887+        d = self.service.getDiscoItems(JID('user@example.org/home'),
     888+                                       JID('pubsub.example.org'),
     889+                                       '')
     890+        d.addCallback(cb)
     891+        return d
     892+
     893+
     894+    def test_getDiscoItemsNonRoot(self):
     895+        """
     896+        Test getDiscoItems on a non-root node.
     897+        """
     898+        def getNodes(requestor, service, nodeIdentifier):
     899+            return defer.succeed(['node1', 'node2'])
     900+
     901+        def cb(items):
     902+            self.assertEqual(2, len(items))
     903+
     904+        self.resource.getNodes = getNodes
     905+        d = self.service.getDiscoItems(JID('user@example.org/home'),
     906+                                       JID('pubsub.example.org'),
     907+                                       'test')
     908+        d.addCallback(cb)
     909+        return d
     910+
     911+
     912+    def test_on_publish(self):
     913         """
     914         A publish request should result in L{PubSubService.publish} being
     915         called.
     916@@ -1293,12 +1395,12 @@
     917         def publish(request):
    728918             return defer.succeed(None)
    729919 
    730920-        self.service.publish = publish
    731921-        verify.verifyObject(iwokkel.IPubSubService, self.service)
    732 +        self.resource.pubsub_publish = publish
     922+        self.resource.publish = publish
    733923+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    734924         return self.handleRequest(xml)
    735925 
    736926 
    737 @@ -722,8 +723,8 @@
    738              self.assertEqual(u'item2', request.items[1]["id"])
    739              return defer.succeed(None)
    740  
    741 -        self.service.publish = publish
    742 -        verify.verifyObject(iwokkel.IPubSubService, self.service)
    743 +        self.resource.pubsub_publish = publish
    744 +        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    745          return self.handleRequest(xml)
    746  
    747  
    748 @@ -759,8 +760,8 @@
     927-    def test_onSubscribe(self):
     928+    def test_on_subscribe(self):
     929         """
     930         A successful subscription should return the current subscription.
     931         """
     932@@ -1326,14 +1428,14 @@
    749933             self.assertEqual('user@example.org/Home', subscription['jid'])
    750934             self.assertEqual('subscribed', subscription['subscription'])
     
    752936-        self.service.subscribe = subscribe
    753937-        verify.verifyObject(iwokkel.IPubSubService, self.service)
    754 +        self.resource.pubsub_subscribe = subscribe
     938+        self.resource.subscribe = subscribe
    755939+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    756940         d = self.handleRequest(xml)
    757941         d.addCallback(cb)
    758942         return d
    759 @@ -789,8 +790,8 @@
     943 
     944 
     945-    def test_onSubscribeEmptyNode(self):
     946+    def test_on_subscribeEmptyNode(self):
     947         """
     948         A successful subscription on root node should return no node attribute.
     949         """
     950@@ -1355,14 +1457,14 @@
    760951         def cb(element):
    761952             self.assertFalse(element.subscription.hasAttribute('node'))
     
    763954-        self.service.subscribe = subscribe
    764955-        verify.verifyObject(iwokkel.IPubSubService, self.service)
    765 +        self.resource.pubsub_subscribe = subscribe
     956+        self.resource.subscribe = subscribe
    766957+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    767958         d = self.handleRequest(xml)
    768959         d.addCallback(cb)
    769960         return d
    770 @@ -820,8 +821,8 @@
     961 
     962 
     963-    def test_onUnsubscribe(self):
     964+    def test_on_unsubscribe(self):
     965         """
     966         A successful unsubscription should return an empty response.
     967         """
     968@@ -1382,14 +1484,14 @@
    771969         def cb(element):
    772970             self.assertIdentical(None, element)
     
    774972-        self.service.unsubscribe = unsubscribe
    775973-        verify.verifyObject(iwokkel.IPubSubService, self.service)
    776 +        self.resource.pubsub_unsubscribe = unsubscribe
     974+        self.resource.unsubscribe = unsubscribe
    777975+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    778976         d = self.handleRequest(xml)
    779977         d.addCallback(cb)
    780978         return d
    781 @@ -914,8 +915,8 @@
    782                                                 'subscribed')
    783              return defer.succeed([subscription])
    784  
     979 
     980 
     981-    def test_onOptionsGet(self):
     982+    def test_on_optionsGet(self):
     983         """
     984         Getting subscription options is not supported.
     985         """
     986@@ -1414,7 +1516,7 @@
     987         return d
     988 
     989 
     990-    def test_onOptionsSet(self):
     991+    def test_on_optionsSet(self):
     992         """
     993         Setting subscription options is not supported.
     994         """
     995@@ -1446,7 +1548,7 @@
     996         return d
     997 
     998 
     999-    def test_onSubscriptions(self):
     1000+    def test_on_subscriptions(self):
     1001         """
     1002         A subscriptions request should result in
     1003         L{PubSubService.subscriptions} being called and the result prepared
     1004@@ -1462,6 +1564,11 @@
     1005         </iq>
     1006         """
     1007 
     1008+        def subscriptions(request):
     1009+            subscription = pubsub.Subscription('test', JID('user@example.org'),
     1010+                                               'subscribed')
     1011+            return defer.succeed([subscription])
     1012+
     1013         def cb(element):
     1014             self.assertEqual('pubsub', element.name)
     1015             self.assertEqual(NS_PUBSUB, element.uri)
     1016@@ -1475,20 +1582,14 @@
     1017             self.assertEqual('test', subscription['node'])
     1018             self.assertEqual('subscribed', subscription['subscription'])
     1019 
     1020-
     1021-        def subscriptions(request):
     1022-            subscription = pubsub.Subscription('test', JID('user@example.org'),
     1023-                                               'subscribed')
     1024-            return defer.succeed([subscription])
     1025-
    7851026-        self.service.subscriptions = subscriptions
    7861027-        verify.verifyObject(iwokkel.IPubSubService, self.service)
    787 +        self.resource.pubsub_subscriptions = subscriptions
     1028+        self.resource.subscriptions = subscriptions
    7881029+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    7891030         d = self.handleRequest(xml)
    7901031         d.addCallback(cb)
    7911032         return d
    792 @@ -956,8 +957,8 @@
    793              affiliation = ('test', 'owner')
    794              return defer.succeed([affiliation])
    795  
     1033 
     1034 
     1035-    def test_onAffiliations(self):
     1036+    def test_on_affiliations(self):
     1037         """
     1038         A subscriptions request should result in
     1039         L{PubSubService.affiliations} being called and the result prepared
     1040@@ -1504,6 +1605,10 @@
     1041         </iq>
     1042         """
     1043 
     1044+        def affiliations(request):
     1045+            affiliation = ('test', 'owner')
     1046+            return defer.succeed([affiliation])
     1047+
     1048         def cb(element):
     1049             self.assertEqual('pubsub', element.name)
     1050             self.assertEqual(NS_PUBSUB, element.uri)
     1051@@ -1516,19 +1621,14 @@
     1052             self.assertEqual('test', affiliation['node'])
     1053             self.assertEqual('owner', affiliation['affiliation'])
     1054 
     1055-
     1056-        def affiliations(request):
     1057-            affiliation = ('test', 'owner')
     1058-            return defer.succeed([affiliation])
     1059-
    7961060-        self.service.affiliations = affiliations
    7971061-        verify.verifyObject(iwokkel.IPubSubService, self.service)
    798 +        self.resource.pubsub_affiliations = affiliations
     1062+        self.resource.affiliations = affiliations
    7991063+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    8001064         d = self.handleRequest(xml)
    8011065         d.addCallback(cb)
    8021066         return d
    803 @@ -986,8 +987,8 @@
     1067 
     1068 
     1069-    def test_onCreate(self):
     1070+    def test_on_create(self):
     1071         """
     1072         Replies to create node requests don't return the created node.
     1073         """
     1074@@ -1548,14 +1648,14 @@
    8041075         def cb(element):
    8051076             self.assertIdentical(None, element)
     
    8071078-        self.service.create = create
    8081079-        verify.verifyObject(iwokkel.IPubSubService, self.service)
    809 +        self.resource.pubsub_create = create
     1080+        self.resource.create = create
    8101081+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    8111082         d = self.handleRequest(xml)
    8121083         d.addCallback(cb)
    8131084         return d
    814 @@ -1017,8 +1018,8 @@
     1085 
     1086 
     1087-    def test_onCreateChanged(self):
     1088+    def test_on_createChanged(self):
     1089         """
     1090         Replies to create node requests return the created node if changed.
     1091         """
     1092@@ -1579,14 +1679,14 @@
    8151093             self.assertEqual(u'myrenamednode',
    8161094                              element.create.getAttribute('node'))
     
    8181096-        self.service.create = create
    8191097-        verify.verifyObject(iwokkel.IPubSubService, self.service)
    820 +        self.resource.pubsub_create = create
     1098+        self.resource.create = create
    8211099+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    8221100         d = self.handleRequest(xml)
    8231101         d.addCallback(cb)
    8241102         return d
    825 @@ -1048,8 +1049,8 @@
     1103 
     1104 
     1105-    def test_onCreateInstant(self):
     1106+    def test_on_createInstant(self):
     1107         """
     1108         Replies to create instant node requests return the created node.
     1109         """
     1110@@ -1609,14 +1709,14 @@
    8261111             self.assertEqual(NS_PUBSUB, element.create.uri)
    8271112             self.assertEqual(u'random', element.create.getAttribute('node'))
     
    8291114-        self.service.create = create
    8301115-        verify.verifyObject(iwokkel.IPubSubService, self.service)
    831 +        self.resource.pubsub_create = create
     1116+        self.resource.create = create
    8321117+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    8331118         d = self.handleRequest(xml)
    8341119         d.addCallback(cb)
    8351120         return d
    836 @@ -1093,9 +1094,9 @@
     1121 
     1122 
     1123-    def test_onDefault(self):
     1124+    def test_on_default(self):
     1125         """
     1126         A default request should result in
     1127         L{PubSubService.getDefaultConfiguration} being called.
     1128@@ -1641,7 +1741,7 @@
     1129                      "label": "Deliver payloads with event notifications"}
     1130                 }
     1131 
     1132-        def getDefaultConfiguration(request):
     1133+        def default(request):
     1134             return defer.succeed({})
     1135 
     1136         def cb(element):
     1137@@ -1651,15 +1751,15 @@
    8371138             form = data_form.Form.fromElement(element.default.x)
    8381139             self.assertEqual(NS_PUBSUB_CONFIG, form.formNamespace)
     
    8421143-        verify.verifyObject(iwokkel.IPubSubService, self.service)
    8431144+        self.resource.getConfigurationOptions = getConfigurationOptions
    844 +        self.resource.pubsub_default = getDefaultConfiguration
     1145+        self.resource.default = default
    8451146+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    8461147         d = self.handleRequest(xml)
    8471148         d.addCallback(cb)
    8481149         return d
    849 @@ -1143,9 +1144,9 @@
    850              form = data_form.Form.fromElement(element.default.x)
    851              self.assertEqual(NS_PUBSUB_CONFIG, form.formNamespace)
     1150 
     1151 
     1152-    def test_onDefaultCollection(self):
     1153+    def test_on_defaultCollection(self):
     1154         """
     1155         Responses to default requests should depend on passed node type.
     1156         """
     1157@@ -1690,19 +1790,19 @@
     1158                      "label": "Deliver payloads with event notifications"}
     1159                 }
     1160 
     1161-        def getDefaultConfiguration(request):
     1162+        def default(request):
     1163             return defer.succeed({})
    8521164 
    8531165-        self.service.getConfigurationOptions = getConfigurationOptions
     
    8551167-        verify.verifyObject(iwokkel.IPubSubService, self.service)
    8561168+        self.resource.getConfigurationOptions = getConfigurationOptions
    857 +        self.resource.pubsub_default = getDefaultConfiguration
    858 +        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    859          d = self.handleRequest(xml)
    860          d.addCallback(cb)
    861          return d
    862 @@ -1182,8 +1183,8 @@
     1169+        self.resource.default = default
     1170+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
     1171         return self.handleRequest(xml)
     1172 
     1173 
     1174-    def test_onDefaultUnknownNodeType(self):
     1175+    def test_on_defaultUnknownNodeType(self):
     1176         """
     1177         A default request should result in
     1178-        L{PubSubService.getDefaultConfiguration} being called.
     1179+        L{PubSubResource.default} being called.
     1180         """
     1181 
     1182         xml = """
     1183@@ -1724,24 +1824,25 @@
     1184         </iq>
     1185         """
     1186 
     1187-        def getDefaultConfiguration(request):
     1188+        def default(request):
     1189             self.fail("Unexpected call to getConfiguration")
     1190 
    8631191         def cb(result):
    8641192             self.assertEquals('not-acceptable', result.condition)
     
    8661194-        self.service.getDefaultConfiguration = getDefaultConfiguration
    8671195-        verify.verifyObject(iwokkel.IPubSubService, self.service)
    868 +        self.resource.pubsub_default = getDefaultConfiguration
     1196+        self.resource.default = default
    8691197+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    8701198         d = self.handleRequest(xml)
    8711199         self.assertFailure(d, error.StanzaError)
    8721200         d.addCallback(cb)
    873 @@ -1257,9 +1258,9 @@
     1201         return d
     1202 
     1203 
     1204-    def test_onConfigureGet(self):
     1205+    def test_on_configureGet(self):
     1206         """
     1207-        On a node configuration get request L{PubSubService.getConfiguration}
     1208-        is called and results in a data form with the configuration.
     1209+        On a node configuration get
     1210+        requestL{PubSubResource.configureGet} is called and results in a
     1211+        data form with the configuration.
     1212         """
     1213 
     1214         xml = """
     1215@@ -1766,7 +1867,7 @@
     1216                      "label": "Owner of the node"}
     1217                 }
     1218 
     1219-        def getConfiguration(request):
     1220+        def configureGet(request):
     1221             return defer.succeed({'pubsub#deliver_payloads': '0',
     1222                                   'pubsub#persist_items': '1',
     1223                                   'pubsub#owner': JID('user@example.org'),
     1224@@ -1800,19 +1901,18 @@
     1225 
    8741226             self.assertNotIn('x-myfield', fields)
    8751227 
    876  
     1228-
    8771229-        self.service.getConfigurationOptions = getConfigurationOptions
    8781230-        self.service.getConfiguration = getConfiguration
    8791231-        verify.verifyObject(iwokkel.IPubSubService, self.service)
    8801232+        self.resource.getConfigurationOptions = getConfigurationOptions
    881 +        self.resource.pubsub_configureGet = getConfiguration
     1233+        self.resource.configureGet = configureGet
    8821234+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    8831235         d = self.handleRequest(xml)
    8841236         d.addCallback(cb)
    8851237         return d
    886 @@ -1306,9 +1307,9 @@
     1238 
     1239 
     1240-    def test_onConfigureSet(self):
     1241+    def test_on_configureSet(self):
     1242         """
     1243         On a node configuration set request the Data Form is parsed and
     1244-        L{PubSubService.setConfiguration} is called with the passed options.
     1245+        L{PubSubResource.configureSet} is called with the passed options.
     1246         """
     1247 
     1248         xml = """
     1249@@ -1842,21 +1942,21 @@
     1250                      "label": "Deliver payloads with event notifications"}
     1251                 }
     1252 
     1253-        def setConfiguration(request):
     1254+        def configureSet(request):
     1255             self.assertEqual({'pubsub#deliver_payloads': False,
    8871256                               'pubsub#persist_items': True}, request.options)
    8881257             return defer.succeed(None)
     
    8921261-        verify.verifyObject(iwokkel.IPubSubService, self.service)
    8931262+        self.resource.getConfigurationOptions = getConfigurationOptions
    894 +        self.resource.pubsub_configureSet = setConfiguration
     1263+        self.resource.configureSet = configureSet
    8951264+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    8961265         return self.handleRequest(xml)
    8971266 
    8981267 
    899 @@ -1336,8 +1337,8 @@
    900          def setConfiguration(request):
     1268-    def test_onConfigureSetCancel(self):
     1269+    def test_on_configureSetCancel(self):
     1270         """
     1271-        The node configuration is cancelled, L{PubSubService.setConfiguration}
     1272-        not called.
     1273+        The node configuration is cancelled,
     1274+        L{PubSubResource.configureSet} not called.
     1275         """
     1276 
     1277         xml = """
     1278@@ -1874,15 +1974,15 @@
     1279         </iq>
     1280         """
     1281 
     1282-        def setConfiguration(request):
     1283+        def configureSet(request):
    9011284             self.fail("Unexpected call to setConfiguration")
    9021285 
    9031286-        self.service.setConfiguration = setConfiguration
    9041287-        verify.verifyObject(iwokkel.IPubSubService, self.service)
    905 +        self.resource.pubsub_configureSet = setConfiguration
     1288+        self.resource.configureSet = configureSet
    9061289+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    9071290         return self.handleRequest(xml)
    9081291 
    9091292 
    910 @@ -1377,9 +1378,9 @@
     1293-    def test_onConfigureSetIgnoreUnknown(self):
     1294+    def test_on_configureSetIgnoreUnknown(self):
     1295         """
     1296         On a node configuration set request unknown fields should be ignored.
     1297         """
     1298@@ -1914,17 +2014,17 @@
     1299                      "label": "Deliver payloads with event notifications"}
     1300                 }
     1301 
     1302-        def setConfiguration(request):
     1303+        def configureSet(request):
    9111304             self.assertEquals(['pubsub#deliver_payloads'],
    9121305                               request.options.keys())
     
    9161309-        verify.verifyObject(iwokkel.IPubSubService, self.service)
    9171310+        self.resource.getConfigurationOptions = getConfigurationOptions
    918 +        self.resource.pubsub_configureSet = setConfiguration
     1311+        self.resource.configureSet = configureSet
    9191312+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    9201313         return self.handleRequest(xml)
    9211314 
    9221315 
    923 @@ -1445,7 +1446,8 @@
     1316-    def test_onConfigureSetBadFormType(self):
     1317+    def test_on_configureSetBadFormType(self):
     1318         """
     1319         On a node configuration set request unknown fields should be ignored.
     1320         """
     1321@@ -1955,7 +2055,7 @@
     1322         return d
     1323 
     1324 
     1325-    def test_onItems(self):
     1326+    def test_on_items(self):
     1327         """
     1328         On a items request, return all items for the given node.
     1329         """
     1330@@ -1981,16 +2081,17 @@
    9241331             self.assertEqual(NS_PUBSUB, item.uri)
    9251332             self.assertEqual('current', item['id'])
    9261333 
    9271334-        self.service.items = items
    928 +        self.resource.pubsub_items = items
     1335+        self.resource.items = items
    9291336+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    9301337         d = self.handleRequest(xml)
    9311338         d.addCallback(cb)
    9321339         return d
    933 @@ -1476,7 +1478,8 @@
    934              self.assertEqual(['item1', 'item2'], request.itemIdentifiers)
     1340 
     1341 
     1342-    def test_onRetract(self):
     1343+    def test_on_retract(self):
     1344         """
     1345-        A retract request should result in L{PubSubService.retract} being
     1346-        called.
     1347+        A retract request should result in L{PubSubResource.retract}
     1348+        being called.
     1349         """
     1350 
     1351         xml = """
     1352@@ -2008,13 +2109,14 @@
     1353         def retract(request):
    9351354             return defer.succeed(None)
    9361355 
    9371356-        self.service.retract = retract
    938 +        self.resource.pubsub_retract = retract
     1357+        self.resource.retract = retract
    9391358+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    9401359         return self.handleRequest(xml)
    9411360 
    9421361 
    943 @@ -1501,7 +1504,8 @@
    944              self.assertEqual('test', request.nodeIdentifier)
     1362-    def test_onPurge(self):
     1363+    def test_on_purge(self):
     1364         """
     1365-        A purge request should result in L{PubSubService.purge} being
     1366+        A purge request should result in L{PubSubResource.purge} being
     1367         called.
     1368         """
     1369 
     1370@@ -2030,13 +2132,14 @@
     1371         def purge(request):
    9451372             return defer.succeed(None)
    9461373 
    9471374-        self.service.purge = purge
    948 +        self.resource.pubsub_purge = purge
     1375+        self.resource.purge = purge
    9491376+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    9501377         return self.handleRequest(xml)
    9511378 
    9521379 
    953 @@ -1526,7 +1530,8 @@
    954              self.assertEqual('test', request.nodeIdentifier)
     1380-    def test_onDelete(self):
     1381+    def test_on_delete(self):
     1382         """
     1383-        A delete request should result in L{PubSubService.delete} being
     1384+        A delete request should result in L{PubSubResource.delete} being
     1385         called.
     1386         """
     1387 
     1388@@ -2052,7 +2155,8 @@
     1389         def delete(request):
    9551390             return defer.succeed(None)
    9561391 
    9571392-        self.service.delete = delete
    958 +        self.resource.pubsub_delete = delete
     1393+        self.resource.delete = delete
    9591394+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    9601395         return self.handleRequest(xml)
    9611396 
    9621397 
    963 @@ -1687,7 +1692,7 @@
    964  
     1398@@ -2103,7 +2207,7 @@
     1399         self.assertEqual(redirectURI, message.event.delete.redirect['uri'])
     1400 
     1401 
     1402-    def test_onSubscriptionsGet(self):
     1403+    def test_on_subscriptionsGet(self):
     1404         """
     1405         Getting subscription options is not supported.
     1406         """
     1407@@ -2130,7 +2234,7 @@
     1408         return d
     1409 
     1410 
     1411-    def test_onSubscriptionsSet(self):
     1412+    def test_on_subscriptionsSet(self):
     1413         """
     1414         Setting subscription options is not supported.
     1415         """
     1416@@ -2157,7 +2261,7 @@
     1417         return d
     1418 
     1419 
     1420-    def test_onAffiliationsGet(self):
     1421+    def test_on_affiliationsGet(self):
     1422         """
     1423         Getting subscription options is not supported.
     1424         """
     1425@@ -2184,7 +2288,7 @@
     1426         return d
     1427 
     1428 
     1429-    def test_onAffiliationsSet(self):
     1430+    def test_on_affiliationsSet(self):
     1431         """
     1432         Setting subscription options is not supported.
     1433         """
     1434@@ -2211,18 +2315,38 @@
     1435         return d
     1436 
     1437 
     1438+
     1439+class PubSubResourceTest(unittest.TestCase):
     1440+
     1441+    def setUp(self):
     1442+        self.resource = pubsub.PubSubResource()
     1443+
     1444+
     1445+    def test_interface(self):
     1446+        """
     1447+        Do instances of L{pubsub.PubSubResource} provide L{iwokkel.IPubSubResource}?
     1448+        """
     1449+        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
     1450+
     1451+
     1452+    def test_getNodes(self):
     1453+        """
     1454+        Default getNodes returns an empty list.
     1455+        """
     1456+        def cb(nodes):
     1457+            self.assertEquals([], nodes)
     1458+
     1459+        d = self.resource.getNodes(JID('user@example.org/home'),
     1460+                                   JID('pubsub.example.org'),
     1461+                                   '')
     1462+        d.addCallback(cb)
     1463+        return d
     1464+
     1465+
    9651466     def test_publish(self):
    9661467         """
    9671468-        Non-overridden L{PubSubService.publish} yields unsupported error.
    968 +        Non-overridden L{PubSubResource.publish} yields unsupported error.
    969          """
    970  
    971          xml = """
     1469-        """
     1470-
     1471-        xml = """
     1472-        <iq type='set' to='pubsub.example.org'
     1473-                       from='user@example.org'>
     1474-          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1475-            <publish node='mynode'/>
     1476-          </pubsub>
     1477-        </iq>
     1478+        Non-overridden L{PubSubResource.publish} yields unsupported
     1479+        error.
     1480         """
     1481 
     1482         def cb(result):
     1483@@ -2231,7 +2355,7 @@
     1484             self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     1485             self.assertEquals('publish', result.appCondition['feature'])
     1486 
     1487-        d = self.handleRequest(xml)
     1488+        d = self.resource.publish(pubsub.PubSubRequest())
     1489         self.assertFailure(d, error.StanzaError)
     1490         d.addCallback(cb)
     1491         return d
     1492@@ -2239,16 +2363,7 @@
     1493 
     1494     def test_subscribe(self):
     1495         """
     1496-        Non-overridden L{PubSubService.subscribe} yields unsupported error.
     1497-        """
     1498-
     1499-        xml = """
     1500-        <iq type='set' to='pubsub.example.org'
     1501-                       from='user@example.org'>
     1502-          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1503-            <subscribe node='test' jid='user@example.org/Home'/>
     1504-          </pubsub>
     1505-        </iq>
     1506+        Non-overridden subscriptions yields unsupported error.
     1507         """
     1508 
     1509         def cb(result):
     1510@@ -2257,7 +2372,7 @@
     1511             self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     1512             self.assertEquals('subscribe', result.appCondition['feature'])
     1513 
     1514-        d = self.handleRequest(xml)
     1515+        d = self.resource.subscribe(pubsub.PubSubRequest())
     1516         self.assertFailure(d, error.StanzaError)
     1517         d.addCallback(cb)
     1518         return d
     1519@@ -2265,16 +2380,7 @@
     1520 
     1521     def test_unsubscribe(self):
     1522         """
     1523-        Non-overridden L{PubSubService.unsubscribe} yields unsupported error.
     1524-        """
     1525-
     1526-        xml = """
     1527-        <iq type='set' to='pubsub.example.org'
     1528-                       from='user@example.org'>
     1529-          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1530-            <unsubscribe node='test' jid='user@example.org/Home'/>
     1531-          </pubsub>
     1532-        </iq>
     1533+        Non-overridden unsubscribe yields unsupported error.
     1534         """
     1535 
     1536         def cb(result):
     1537@@ -2283,7 +2389,7 @@
     1538             self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     1539             self.assertEquals('subscribe', result.appCondition['feature'])
     1540 
     1541-        d = self.handleRequest(xml)
     1542+        d = self.resource.unsubscribe(pubsub.PubSubRequest())
     1543         self.assertFailure(d, error.StanzaError)
     1544         d.addCallback(cb)
     1545         return d
     1546@@ -2291,16 +2397,7 @@
     1547 
     1548     def test_subscriptions(self):
     1549         """
     1550-        Non-overridden L{PubSubService.subscriptions} yields unsupported error.
     1551-        """
     1552-
     1553-        xml = """
     1554-        <iq type='get' to='pubsub.example.org'
     1555-                       from='user@example.org'>
     1556-          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1557-            <subscriptions/>
     1558-          </pubsub>
     1559-        </iq>
     1560+        Non-overridden subscriptions yields unsupported error.
     1561         """
     1562 
     1563         def cb(result):
     1564@@ -2310,7 +2407,7 @@
     1565             self.assertEquals('retrieve-subscriptions',
     1566                               result.appCondition['feature'])
     1567 
     1568-        d = self.handleRequest(xml)
     1569+        d = self.resource.subscriptions(pubsub.PubSubRequest())
     1570         self.assertFailure(d, error.StanzaError)
     1571         d.addCallback(cb)
     1572         return d
     1573@@ -2318,16 +2415,7 @@
     1574 
     1575     def test_affiliations(self):
     1576         """
     1577-        Non-overridden L{PubSubService.affiliations} yields unsupported error.
     1578-        """
     1579-
     1580-        xml = """
     1581-        <iq type='get' to='pubsub.example.org'
     1582-                       from='user@example.org'>
     1583-          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1584-            <affiliations/>
     1585-          </pubsub>
     1586-        </iq>
     1587+        Non-overridden affiliations yields unsupported error.
     1588         """
     1589 
     1590         def cb(result):
     1591@@ -2337,7 +2425,7 @@
     1592             self.assertEquals('retrieve-affiliations',
     1593                               result.appCondition['feature'])
     1594 
     1595-        d = self.handleRequest(xml)
     1596+        d = self.resource.affiliations(pubsub.PubSubRequest())
     1597         self.assertFailure(d, error.StanzaError)
     1598         d.addCallback(cb)
     1599         return d
     1600@@ -2345,16 +2433,7 @@
     1601 
     1602     def test_create(self):
     1603         """
     1604-        Non-overridden L{PubSubService.create} yields unsupported error.
     1605-        """
     1606-
     1607-        xml = """
     1608-        <iq type='set' to='pubsub.example.org'
     1609-                       from='user@example.org'>
     1610-          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1611-            <create node='mynode'/>
     1612-          </pubsub>
     1613-        </iq>
     1614+        Non-overridden create yields unsupported error.
     1615         """
     1616 
     1617         def cb(result):
     1618@@ -2363,87 +2442,51 @@
     1619             self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     1620             self.assertEquals('create-nodes', result.appCondition['feature'])
     1621 
     1622-        d = self.handleRequest(xml)
     1623+        d = self.resource.create(pubsub.PubSubRequest())
     1624         self.assertFailure(d, error.StanzaError)
     1625         d.addCallback(cb)
     1626         return d
     1627 
     1628 
     1629-    def test_getDefaultConfiguration(self):
     1630+    def test_default(self):
     1631         """
     1632-        Non-overridden L{PubSubService.getDefaultConfiguration} yields
     1633-        unsupported error.
     1634-        """
     1635-
     1636-        xml = """
     1637-        <iq type='get' to='pubsub.example.org'
     1638-                       from='user@example.org'>
     1639-          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
     1640-            <default/>
     1641-          </pubsub>
     1642-        </iq>
     1643+        Non-overridden default yields unsupported error.
     1644         """
     1645 
     1646         def cb(result):
     1647             self.assertEquals('feature-not-implemented', result.condition)
     1648             self.assertEquals('unsupported', result.appCondition.name)
     1649             self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     1650-            self.assertEquals('retrieve-default', result.appCondition['feature'])
     1651+            self.assertEquals('retrieve-default',
     1652+                              result.appCondition['feature'])
     1653 
     1654-        d = self.handleRequest(xml)
     1655+        d = self.resource.default(pubsub.PubSubRequest())
     1656         self.assertFailure(d, error.StanzaError)
     1657         d.addCallback(cb)
     1658         return d
     1659 
     1660 
     1661-    def test_getConfiguration(self):
     1662+    def test_configureGet(self):
     1663         """
     1664-        Non-overridden L{PubSubService.getConfiguration} yields unsupported
     1665+        Non-overridden configureGet yields unsupported
     1666         error.
     1667         """
     1668 
     1669-        xml = """
     1670-        <iq type='get' to='pubsub.example.org'
     1671-                       from='user@example.org'>
     1672-          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
     1673-            <configure/>
     1674-          </pubsub>
     1675-        </iq>
     1676-        """
     1677-
     1678         def cb(result):
     1679             self.assertEquals('feature-not-implemented', result.condition)
     1680             self.assertEquals('unsupported', result.appCondition.name)
     1681             self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     1682             self.assertEquals('config-node', result.appCondition['feature'])
     1683 
     1684-        d = self.handleRequest(xml)
     1685+        d = self.resource.configureGet(pubsub.PubSubRequest())
     1686         self.assertFailure(d, error.StanzaError)
     1687         d.addCallback(cb)
     1688         return d
     1689 
     1690 
     1691-    def test_setConfiguration(self):
     1692+    def test_configureSet(self):
     1693         """
     1694-        Non-overridden L{PubSubService.setConfiguration} yields unsupported
     1695-        error.
     1696-        """
     1697-
     1698-        xml = """
     1699-        <iq type='set' to='pubsub.example.org'
     1700-                       from='user@example.org'>
     1701-          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
     1702-            <configure node='test'>
     1703-              <x xmlns='jabber:x:data' type='submit'>
     1704-                <field var='FORM_TYPE' type='hidden'>
     1705-                  <value>http://jabber.org/protocol/pubsub#node_config</value>
     1706-                </field>
     1707-                <field var='pubsub#deliver_payloads'><value>0</value></field>
     1708-                <field var='pubsub#persist_items'><value>1</value></field>
     1709-              </x>
     1710-            </configure>
     1711-          </pubsub>
     1712-        </iq>
     1713+        Non-overridden configureSet yields unsupported error.
     1714         """
     1715 
     1716         def cb(result):
     1717@@ -2452,7 +2495,7 @@
     1718             self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     1719             self.assertEquals('config-node', result.appCondition['feature'])
     1720 
     1721-        d = self.handleRequest(xml)
     1722+        d = self.resource.configureSet(pubsub.PubSubRequest())
     1723         self.assertFailure(d, error.StanzaError)
     1724         d.addCallback(cb)
     1725         return d
     1726@@ -2460,15 +2503,7 @@
     1727 
     1728     def test_items(self):
     1729         """
     1730-        Non-overridden L{PubSubService.items} yields unsupported error.
     1731-        """
     1732-        xml = """
     1733-        <iq type='get' to='pubsub.example.org'
     1734-                       from='user@example.org'>
     1735-          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1736-            <items node='test'/>
     1737-          </pubsub>
     1738-        </iq>
     1739+        Non-overridden items yields unsupported error.
     1740         """
     1741 
     1742         def cb(result):
     1743@@ -2477,7 +2512,7 @@
     1744             self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     1745             self.assertEquals('retrieve-items', result.appCondition['feature'])
     1746 
     1747-        d = self.handleRequest(xml)
     1748+        d = self.resource.items(pubsub.PubSubRequest())
     1749         self.assertFailure(d, error.StanzaError)
     1750         d.addCallback(cb)
     1751         return d
     1752@@ -2485,18 +2520,7 @@
     1753 
     1754     def test_retract(self):
     1755         """
     1756-        Non-overridden L{PubSubService.retract} yields unsupported error.
     1757-        """
     1758-        xml = """
     1759-        <iq type='set' to='pubsub.example.org'
     1760-                       from='user@example.org'>
     1761-          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     1762-            <retract node='test'>
     1763-              <item id='item1'/>
     1764-              <item id='item2'/>
     1765-            </retract>
     1766-          </pubsub>
     1767-        </iq>
     1768+        Non-overridden retract yields unsupported error.
     1769         """
     1770 
     1771         def cb(result):
     1772@@ -2505,7 +2529,7 @@
     1773             self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     1774             self.assertEquals('retract-items', result.appCondition['feature'])
     1775 
     1776-        d = self.handleRequest(xml)
     1777+        d = self.resource.retract(pubsub.PubSubRequest())
     1778         self.assertFailure(d, error.StanzaError)
     1779         d.addCallback(cb)
     1780         return d
     1781@@ -2513,15 +2537,7 @@
     1782 
     1783     def test_purge(self):
     1784         """
     1785-        Non-overridden L{PubSubService.purge} yields unsupported error.
     1786-        """
     1787-        xml = """
     1788-        <iq type='set' to='pubsub.example.org'
     1789-                       from='user@example.org'>
     1790-          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
     1791-            <purge node='test'/>
     1792-          </pubsub>
     1793-        </iq>
     1794+        Non-overridden purge yields unsupported error.
     1795         """
     1796 
     1797         def cb(result):
     1798@@ -2530,7 +2546,7 @@
     1799             self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     1800             self.assertEquals('purge-nodes', result.appCondition['feature'])
     1801 
     1802-        d = self.handleRequest(xml)
     1803+        d = self.resource.purge(pubsub.PubSubRequest())
     1804         self.assertFailure(d, error.StanzaError)
     1805         d.addCallback(cb)
     1806         return d
     1807@@ -2538,15 +2554,7 @@
     1808 
     1809     def test_delete(self):
     1810         """
     1811-        Non-overridden L{PubSubService.delete} yields unsupported error.
     1812-        """
     1813-        xml = """
     1814-        <iq type='set' to='pubsub.example.org'
     1815-                       from='user@example.org'>
     1816-          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
     1817-            <delete node='test'/>
     1818-          </pubsub>
     1819-        </iq>
     1820+        Non-overridden delete yields unsupported error.
     1821         """
     1822 
     1823         def cb(result):
     1824@@ -2555,7 +2563,7 @@
     1825             self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     1826             self.assertEquals('delete-nodes', result.appCondition['feature'])
     1827 
     1828-        d = self.handleRequest(xml)
     1829+        d = self.resource.delete(pubsub.PubSubRequest())
     1830         self.assertFailure(d, error.StanzaError)
     1831         d.addCallback(cb)
     1832         return d
Note: See TracChangeset for help on using the changeset viewer.