source: ralphm-patches/pubsub_resource.patch @ 13:42b22edb29bb

Last change on this file since 13:42b22edb29bb was 13:42b22edb29bb, checked in by Ralph Meijer <ralphm@…>, 12 years ago

Make these backwards compatible.

File size: 62.9 KB
  • wokkel/iwokkel.py

    diff -r 29f67459352b wokkel/iwokkel.py
    a b  
    278278                             C{list} of L{domish.Element})
    279279        """
    280280
     281
    281282    def notifyDelete(service, nodeIdentifier, subscribers,
    282283                     redirectURI=None):
    283284        """
     
    526527        @param nodeIdentifier: The identifier of the node to be delete.
    527528        @type nodeIdentifier: C{unicode}
    528529        """
     530
     531
     532
     533class IPubSubResource(Interface):
     534
     535    def locateResource(request):
     536        """
     537        Locate a resource that will handle the request.
     538
     539        @param request: The publish-subscribe request.
     540        @type request: L{wokkel.pubsub.PubSubRequest}
     541        """
     542
     543
     544    def getInfo(requestor, service, nodeIdentifier):
     545        """
     546        Get node type and meta data.
     547
     548        @param requestor: The entity the request originated from.
     549        @type requestor: L{jid.JID}
     550        @param service: The publish-subscribe service entity.
     551        @type service: L{jid.JID}
     552        @param nodeIdentifier: Identifier of the node to request the info for.
     553        @type nodeIdentifier: L{unicode}
     554        @return: A deferred that fires with a dictionary. If not empty,
     555                 it must have the keys C{'type'} and C{'meta-data'} to keep
     556                 respectively the node type and a dictionary with the meta
     557                 data for that node.
     558        @rtype: L{defer.Deferred}
     559        """
     560
     561
     562    def getNodes(requestor, service, nodeIdentifier):
     563        """
     564        Get all nodes contained by this node.
     565
     566        @param requestor: The entity the request originated from.
     567        @type requestor: L{jid.JID}
     568        @param service: The publish-subscribe service entity.
     569        @type service: L{jid.JID}
     570        @param nodeIdentifier: Identifier of the node to request the childs for.
     571        @type nodeIdentifier: L{unicode}
     572        @return: A deferred that fires with a list of child node identifiers.
     573        @rtype: L{defer.Deferred}
     574        """
     575
     576
     577    def getConfigurationOptions():
     578        """
     579        Retrieve all known node configuration options.
     580
     581        The returned dictionary holds the possible node configuration options
     582        by option name. The value of each entry represents the specifics for
     583        that option in a dictionary:
     584
     585         - C{'type'} (C{str}): The option's type (see
     586           L{Field<wokkel.data_form.Field>}'s doc string for possible values).
     587         - C{'label'} (C{unicode}): A human readable label for this option.
     588         - C{'options'} (C{dict}): Optional list of possible values for this
     589           option.
     590
     591        Example::
     592
     593            {
     594            "pubsub#persist_items":
     595                {"type": "boolean",
     596                 "label": "Persist items to storage"},
     597            "pubsub#deliver_payloads":
     598                {"type": "boolean",
     599                 "label": "Deliver payloads with event notifications"},
     600            "pubsub#send_last_published_item":
     601                {"type": "list-single",
     602                 "label": "When to send the last published item",
     603                 "options": {
     604                     "never": "Never",
     605                     "on_sub": "When a new subscription is processed"}
     606                }
     607            }
     608
     609        @rtype: C{dict}.
     610        """
     611
     612
     613    def publish(request):
     614        """
     615        Called when a publish request has been received.
     616
     617        @param request: The publish-subscribe request.
     618        @type request: L{wokkel.pubsub.PubSubRequest}
     619        @return: deferred that fires on success.
     620        @rtype: L{defer.Deferred}
     621        """
     622
     623
     624    def subscribe(request):
     625        """
     626        Called when a subscribe request has been received.
     627
     628        @param request: The publish-subscribe request.
     629        @type request: L{wokkel.pubsub.PubSubRequest}
     630        @return: A deferred that fires with a
     631                 L{Subscription<wokkel.pubsub.Subscription>}.
     632        @rtype: L{defer.Deferred}
     633        """
     634
     635
     636    def unsubscribe(request):
     637        """
     638        Called when a subscribe request has been received.
     639
     640        @param request: The publish-subscribe request.
     641        @type request: L{wokkel.pubsub.PubSubRequest}
     642        @return: A deferred that fires with C{None} when unsubscription has
     643                 succeeded.
     644        @rtype: L{defer.Deferred}
     645        """
     646
     647
     648    def subscriptions(request):
     649        """
     650        Called when a subscriptions retrieval request has been received.
     651
     652        @param request: The publish-subscribe request.
     653        @type request: L{wokkel.pubsub.PubSubRequest}
     654        @return: A deferred that fires with a C{list} of subscriptions as
     655                 L{Subscription<wokkel.pubsub.Subscription>}.
     656        @rtype: L{defer.Deferred}
     657        """
     658
     659
     660    def affiliations(request):
     661        """
     662        Called when a affiliations retrieval request has been received.
     663
     664        @param request: The publish-subscribe request.
     665        @type request: L{wokkel.pubsub.PubSubRequest}
     666        @return: A deferred that fires with a C{list} of affiliations as
     667                 C{tuple}s of (node identifier as C{unicode}, affiliation state
     668                 as C{str}). The affiliation can be C{'owner'}, C{'publisher'},
     669                 or C{'outcast'}.
     670        @rtype: L{defer.Deferred}
     671        """
     672
     673
     674    def create(request):
     675        """
     676        Called when a node creation request has been received.
     677
     678        @param request: The publish-subscribe request.
     679        @type request: L{wokkel.pubsub.PubSubRequest}
     680        @return: A deferred that fires with a C{unicode} that represents
     681                 the identifier of the new node.
     682        @rtype: L{defer.Deferred}
     683        """
     684
     685
     686    def default(request):
     687        """
     688        Called when a default node configuration request has been received.
     689
     690        @param request: The publish-subscribe request.
     691        @type request: L{wokkel.pubsub.PubSubRequest}
     692        @return: A deferred that fires with a C{dict} representing the default
     693                 node configuration. Keys are C{str}s that represent the
     694                 field name. Values can be of types C{unicode}, C{int} or
     695                 C{bool}.
     696        @rtype: L{defer.Deferred}
     697        """
     698
     699
     700    def configureGet(request):
     701        """
     702        Called when a node configuration retrieval request has been received.
     703
     704        @param request: The publish-subscribe request.
     705        @type request: L{wokkel.pubsub.PubSubRequest}
     706        @return: A deferred that fires with a C{dict} representing the node
     707                 configuration. Keys are C{str}s that represent the field name.
     708                 Values can be of types C{unicode}, C{int} or C{bool}.
     709        @rtype: L{defer.Deferred}
     710        """
     711
     712
     713    def configureSet(request):
     714        """
     715        Called when a node configuration change request has been received.
     716
     717        @param request: The publish-subscribe request.
     718        @type request: L{wokkel.pubsub.PubSubRequest}
     719        @return: A deferred that fires with C{None} when the node's
     720                 configuration has been changed.
     721        @rtype: L{defer.Deferred}
     722        """
     723
     724
     725    def items(request):
     726        """
     727        Called when a items retrieval request has been received.
     728
     729        @param request: The publish-subscribe request.
     730        @type request: L{wokkel.pubsub.PubSubRequest}
     731        @return: A deferred that fires with a C{list} of L{pubsub.Item}.
     732        @rtype: L{defer.Deferred}
     733        """
     734
     735
     736    def retract(request):
     737        """
     738        Called when a item retraction request has been received.
     739
     740        @param request: The publish-subscribe request.
     741        @type request: L{wokkel.pubsub.PubSubRequest}
     742        @return: A deferred that fires with C{None} when the given items have
     743                 been retracted.
     744        @rtype: L{defer.Deferred}
     745        """
     746
     747
     748    def purge(request):
     749        """
     750        Called when a node purge request has been received.
     751
     752        @param request: The publish-subscribe request.
     753        @type request: L{wokkel.pubsub.PubSubRequest}
     754        @return: A deferred that fires with C{None} when the node has been
     755                 purged.
     756        @rtype: L{defer.Deferred}
     757        """
     758
     759
     760    def delete(request):
     761        """
     762        Called when a node deletion request has been received.
     763
     764        @param request: The publish-subscribe request.
     765        @type request: L{wokkel.pubsub.PubSubRequest}
     766        @return: A deferred that fires with C{None} when the node has been
     767                 deleted.
     768        @rtype: L{defer.Deferred}
     769        """
  • wokkel/pubsub.py

    diff -r 29f67459352b wokkel/pubsub.py
    a b  
    1313from zope.interface import implements
    1414
    1515from twisted.internet import defer
     16from twisted.python import log
    1617from twisted.words.protocols.jabber import jid, error, xmlstream
    1718from twisted.words.xish import domish
    1819
    1920from wokkel import disco, data_form, generic, shim
    2021from wokkel.subprotocols import IQHandlerMixin, XMPPHandler
    21 from wokkel.iwokkel import IPubSubClient, IPubSubService
     22from wokkel.iwokkel import IPubSubClient, IPubSubService, IPubSubResource
    2223
    2324# Iq get and set XPath queries
    2425IQ_GET = '/iq[@type="get"]'
     
    8485
    8586class Unsupported(PubSubError):
    8687    def __init__(self, feature, text=None):
     88        self.feature = feature
    8789        PubSubError.__init__(self, 'feature-not-implemented',
    8890                                   'unsupported',
    8991                                   feature,
    9092                                   text)
    9193
     94    def __str__(self):
     95        message = PubSubError.__str__(self)
     96        message += ', feature %r' % self.feature
     97        return message
    9298
    9399
    94100class Subscription(object):
     
    235241        'retract': ['node', 'itemIdentifiers'],
    236242        'purge': ['node'],
    237243        'delete': ['node'],
    238         'affiliationsGet': [],
     244        'affiliationsGet': ['nodeOrEmpty'],
    239245        'affiliationsSet': [],
    240         'subscriptionsGet': [],
     246        'subscriptionsGet': ['nodeOrEmpty'],
    241247        'subscriptionsSet': [],
    242248    }
    243249
     
    806812            '/*': '_onPubSubRequest',
    807813            }
    808814
     815    _legacyHandlers = {
     816        'publish': ('publish', ['sender', 'recipient',
     817                                'nodeIdentifier', 'items']),
     818        'subscribe': ('subscribe', ['sender', 'recipient',
     819                                    'nodeIdentifier', 'subscriber']),
     820        'unsubscribe': ('unsubscribe', ['sender', 'recipient',
     821                                        'nodeIdentifier', 'subscriber']),
     822        'subscriptions': ('subscriptions', ['sender', 'recipient']),
     823        'affiliations': ('affiliations', ['sender', 'recipient']),
     824        'create': ('create', ['sender', 'recipient', 'nodeIdentifier']),
     825        'getConfigurationOptions': ('getConfigurationOptions', []),
     826        'default': ('getDefaultConfiguration',
     827                    ['sender', 'recipient', 'nodeType']),
     828        'configureGet': ('getConfiguration', ['sender', 'recipient',
     829                                              'nodeIdentifier']),
     830        'configureSet': ('setConfiguration', ['sender', 'recipient',
     831                                              'nodeIdentifier', 'options']),
     832        'items': ('items', ['sender', 'recipient', 'nodeIdentifier',
     833                            'maxItems', 'itemIdentifiers']),
     834        'retract': ('retract', ['sender', 'recipient', 'nodeIdentifier',
     835                                'itemIdentifiers']),
     836        'purge': ('purge', ['sender', 'recipient', 'nodeIdentifier']),
     837        'delete': ('delete', ['sender', 'recipient', 'nodeIdentifier']),
     838    }
    809839
    810     def __init__(self):
     840    hideNodes = False
     841
     842    def __init__(self, resource=None):
     843        self.resource = resource
    811844        self.discoIdentity = {'category': 'pubsub',
    812845                              'type': 'generic',
    813846                              'name': 'Generic Publish-Subscribe Service'}
     
    820853
    821854
    822855    def getDiscoInfo(self, requestor, target, nodeIdentifier):
    823         info = []
    824 
    825         if not nodeIdentifier:
    826             category, idType, name = self.discoIdentity
    827             info.append(disco.DiscoIdentity(category, idType, name))
    828 
    829             info.append(disco.DiscoFeature(disco.NS_DISCO_ITEMS))
    830             info.extend([disco.DiscoFeature("%s#%s" % (NS_PUBSUB, feature))
    831                          for feature in self.pubSubFeatures])
    832 
    833         def toInfo(nodeInfo):
     856        def toInfo(nodeInfo, info):
    834857            if not nodeInfo:
    835                 return
     858                return info
    836859
    837860            (nodeType, metaData) = nodeInfo['type'], nodeInfo['meta-data']
    838861            info.append(disco.DiscoIdentity('pubsub', nodeType))
     
    852875
    853876                info.append(form)
    854877
    855         d = self.getNodeInfo(requestor, target, nodeIdentifier or '')
    856         d.addCallback(toInfo)
    857         d.addBoth(lambda result: info)
     878            return info
     879
     880        info = []
     881
     882        request = PubSubRequest('discoInfo')
     883
     884        if self.resource is not None:
     885            resource = self.resource.locateResource(request)
     886            identity = resource.discoIdentity
     887            features = resource.features
     888            getInfo = resource.getInfo
     889        else:
     890            category, idType, name = self.discoIdentity
     891            identity = disco.DiscoIdentity(category, idType, name)
     892            features = self.pubSubFeatures
     893            getInfo = self.getNodeInfo
     894
     895        if not nodeIdentifier:
     896            info.append(identity)
     897            info.append(disco.DiscoFeature(disco.NS_DISCO_ITEMS))
     898            info.extend([disco.DiscoFeature("%s#%s" % (NS_PUBSUB, feature))
     899                         for feature in features])
     900
     901        d = getInfo(requestor, target, nodeIdentifier or '')
     902        d.addCallback(toInfo, info)
     903        d.addErrback(log.err)
    858904        return d
    859905
    860906
    861907    def getDiscoItems(self, requestor, target, nodeIdentifier):
    862         if nodeIdentifier or self.hideNodes:
    863             return defer.succeed([])
     908        if self.hideNodes:
     909            d = defer.succeed([])
     910        elif self.resource is not None:
     911            request = PubSubRequest('discoInfo')
     912            resource = self.resource.locateResource(request)
     913            d = resource.getNodes(requestor, target, nodeIdentifier)
     914        elif nodeIdentifier:
     915            d = self.getNodes(requestor, target)
     916        else:
     917            d = defer.succeed([])
     918           
    864919
    865         d = self.getNodes(requestor, target)
     920
    866921        d.addCallback(lambda nodes: [disco.DiscoItem(target, node)
    867922                                     for node in nodes])
    868923        return d
     
    870925
    871926    def _onPubSubRequest(self, iq):
    872927        request = PubSubRequest.fromElement(iq)
    873         handler = getattr(self, '_on_%s' % request.verb)
    874         return handler(request)
    875928
     929        if self.resource is not None:
     930            resource = self.resource.locateResource(request)
     931        else:
     932            resource = self
    876933
    877     def _on_publish(self, request):
    878         return self.publish(request.sender, request.recipient,
    879                             request.nodeIdentifier, request.items)
     934        # Preprocess the request, knowing the handling resource
     935        try:
     936            preProcessor = getattr(self, '_preProcess_%s' % request.verb)
     937        except AttributeError:
     938            pass
     939        else:
     940            request = preProcessor(resource, request)
     941            if request is None:
     942                return defer.succeed(None)
    880943
     944        # Process the request itself,
     945        if resource is not self:
     946            try:
     947                handler = getattr(resource, request.verb)
     948            except AttributeError:
     949                # fix lookup feature
     950                text = "Request verb: %s" % request.verb
     951                return defer.fail(Unsupported('', text))
    881952
    882     def _on_subscribe(self, request):
     953            d = handler(request)
     954        else:
     955            handlerName, argNames = self._legacyHandlers[request.verb]
     956            handler = getattr(self, handlerName)
     957            args = [getattr(request, arg) for arg in argNames]
     958            d = handler(*args)
    883959
    884         def toResponse(result):
    885             response = domish.Element((NS_PUBSUB, "pubsub"))
    886             subscription = response.addElement("subscription")
    887             if result.nodeIdentifier:
    888                 subscription["node"] = result.nodeIdentifier
    889             subscription["jid"] = result.subscriber.full()
    890             subscription["subscription"] = result.state
    891             return response
     960        # If needed, translate the result into a response
     961        try:
     962            cb = getattr(self, '_toResponse_%s' % request.verb)
     963        except AttributeError:
     964            pass
     965        else:
     966            d.addCallback(cb, resource, request)
    892967
    893         d = self.subscribe(request.sender, request.recipient,
    894                            request.nodeIdentifier, request.subscriber)
    895         d.addCallback(toResponse)
    896968        return d
    897969
    898970
    899     def _on_unsubscribe(self, request):
    900         return self.unsubscribe(request.sender, request.recipient,
    901                                 request.nodeIdentifier, request.subscriber)
     971    def _toResponse_subscribe(self, result, resource, request):
     972        response = domish.Element((NS_PUBSUB, "pubsub"))
     973        subscription = response.addElement("subscription")
     974        if result.nodeIdentifier:
     975            subscription["node"] = result.nodeIdentifier
     976        subscription["jid"] = result.subscriber.full()
     977        subscription["subscription"] = result.state
     978        return response
    902979
    903980
    904     def _on_optionsGet(self, request):
    905         raise Unsupported('subscription-options')
     981    def _toResponse_subscriptions(self, result, resource, request):
     982        response = domish.Element((NS_PUBSUB, 'pubsub'))
     983        subscriptions = response.addElement('subscriptions')
     984        for subscription in result:
     985            item = subscriptions.addElement('subscription')
     986            item['node'] = subscription.nodeIdentifier
     987            item['jid'] = subscription.subscriber.full()
     988            item['subscription'] = subscription.state
     989        return response
    906990
    907991
    908     def _on_optionsSet(self, request):
    909         raise Unsupported('subscription-options')
     992    def _toResponse_affiliations(self, result, resource, request):
     993        response = domish.Element((NS_PUBSUB, 'pubsub'))
     994        affiliations = response.addElement('affiliations')
    910995
     996        for nodeIdentifier, affiliation in result:
     997            item = affiliations.addElement('affiliation')
     998            item['node'] = nodeIdentifier
     999            item['affiliation'] = affiliation
    9111000
    912     def _on_subscriptions(self, request):
     1001        return response
    9131002
    914         def toResponse(result):
     1003
     1004    def _toResponse_create(self, result, resource, request):
     1005        if not request.nodeIdentifier or request.nodeIdentifier != result:
    9151006            response = domish.Element((NS_PUBSUB, 'pubsub'))
    916             subscriptions = response.addElement('subscriptions')
    917             for subscription in result:
    918                 item = subscriptions.addElement('subscription')
    919                 item['node'] = subscription.nodeIdentifier
    920                 item['jid'] = subscription.subscriber.full()
    921                 item['subscription'] = subscription.state
     1007            create = response.addElement('create')
     1008            create['node'] = result
    9221009            return response
    923 
    924         d = self.subscriptions(request.sender, request.recipient)
    925         d.addCallback(toResponse)
    926         return d
    927 
    928 
    929     def _on_affiliations(self, request):
    930 
    931         def toResponse(result):
    932             response = domish.Element((NS_PUBSUB, 'pubsub'))
    933             affiliations = response.addElement('affiliations')
    934 
    935             for nodeIdentifier, affiliation in result:
    936                 item = affiliations.addElement('affiliation')
    937                 item['node'] = nodeIdentifier
    938                 item['affiliation'] = affiliation
    939 
    940             return response
    941 
    942         d = self.affiliations(request.sender, request.recipient)
    943         d.addCallback(toResponse)
    944         return d
    945 
    946 
    947     def _on_create(self, request):
    948 
    949         def toResponse(result):
    950             if not request.nodeIdentifier or request.nodeIdentifier != result:
    951                 response = domish.Element((NS_PUBSUB, 'pubsub'))
    952                 create = response.addElement('create')
    953                 create['node'] = result
    954                 return response
    955             else:
    956                 return None
    957 
    958         d = self.create(request.sender, request.recipient,
    959                         request.nodeIdentifier)
    960         d.addCallback(toResponse)
    961         return d
     1010        else:
     1011            return None
    9621012
    9631013
    9641014    def _makeFields(self, options, values):
     
    9771027        return fields
    9781028
    9791029
    980     def _formFromConfiguration(self, values):
    981         options = self.getConfigurationOptions()
     1030    def _formFromConfiguration(self, resource, values):
     1031        options = resource.getConfigurationOptions()
    9821032        fields = self._makeFields(options, values)
    9831033        form = data_form.Form(formType="form",
    9841034                              formNamespace=NS_PUBSUB_NODE_CONFIG,
     
    9871037        return form
    9881038
    9891039
    990     def _checkConfiguration(self, values):
    991         options = self.getConfigurationOptions()
     1040    def _checkConfiguration(self, resource, values):
     1041        options = resource.getConfigurationOptions()
    9921042        processedValues = {}
    9931043
    9941044        for key, value in values.iteritems():
     
    10121062        return processedValues
    10131063
    10141064
    1015     def _on_default(self, request):
     1065    def _preProcess_default(self, resource, request):
     1066        if request.nodeType not in ('leaf', 'collection'):
     1067            raise error.StanzaError('not-acceptable')
     1068        else:
     1069            return request
    10161070
    1017         def toResponse(options):
    1018             response = domish.Element((NS_PUBSUB_OWNER, "pubsub"))
    1019             default = response.addElement("default")
    1020             default.addChild(self._formFromConfiguration(options).toElement())
    1021             return response
    10221071
    1023         if request.nodeType not in ('leaf', 'collection'):
    1024             return defer.fail(error.StanzaError('not-acceptable'))
     1072    def _toResponse_default(self, options, resource, request):
     1073        response = domish.Element((NS_PUBSUB_OWNER, "pubsub"))
     1074        default = response.addElement("default")
     1075        form = self._formFromConfiguration(resource, options)
     1076        default.addChild(form.toElement())
     1077        return response
    10251078
    1026         d = self.getDefaultConfiguration(request.sender, request.recipient,
    1027                                          request.nodeType)
    1028         d.addCallback(toResponse)
    1029         return d
    10301079
     1080    def _toResponse_configureGet(self, options, resource, request):
     1081        response = domish.Element((NS_PUBSUB_OWNER, "pubsub"))
     1082        configure = response.addElement("configure")
     1083        form = self._formFromConfiguration(resource, options)
     1084        configure.addChild(form.toElement())
    10311085
    1032     def _on_configureGet(self, request):
    1033         def toResponse(options):
    1034             response = domish.Element((NS_PUBSUB_OWNER, "pubsub"))
    1035             configure = response.addElement("configure")
    1036             form = self._formFromConfiguration(options)
    1037             configure.addChild(form.toElement())
     1086        if request.nodeIdentifier:
     1087            configure["node"] = request.nodeIdentifier
    10381088
    1039             if request.nodeIdentifier:
    1040                 configure["node"] = request.nodeIdentifier
     1089        return response
    10411090
    1042             return response
    10431091
    1044         d = self.getConfiguration(request.sender, request.recipient,
    1045                                   request.nodeIdentifier)
    1046         d.addCallback(toResponse)
    1047         return d
    1048 
    1049 
    1050     def _on_configureSet(self, request):
     1092    def _preProcess_configureSet(self, resource, request):
    10511093        if request.options:
    1052             request.options = self._checkConfiguration(request.options)
    1053             return self.setConfiguration(request.sender, request.recipient,
    1054                                          request.nodeIdentifier,
    1055                                          request.options)
     1094            request.options = self._checkConfiguration(resource,
     1095                                                       request.options)
     1096            return request
    10561097        else:
    10571098            return None
    10581099
    10591100
     1101    def _toResponse_items(self, result, resource, request):
     1102        response = domish.Element((NS_PUBSUB, 'pubsub'))
     1103        items = response.addElement('items')
     1104        items["node"] = request.nodeIdentifier
    10601105
    1061     def _on_items(self, request):
     1106        for item in result:
     1107            items.addChild(item)
    10621108
    1063         def toResponse(result):
    1064             response = domish.Element((NS_PUBSUB, 'pubsub'))
    1065             items = response.addElement('items')
    1066             items["node"] = request.nodeIdentifier
     1109        return response
    10671110
    1068             for item in result:
    1069                 items.addChild(item)
    1070 
    1071             return response
    1072 
    1073         d = self.items(request.sender, request.recipient,
    1074                        request.nodeIdentifier, request.maxItems,
    1075                        request.itemIdentifiers)
    1076         d.addCallback(toResponse)
    1077         return d
    1078 
    1079 
    1080     def _on_retract(self, request):
    1081         return self.retract(request.sender, request.recipient,
    1082                             request.nodeIdentifier, request.itemIdentifiers)
    1083 
    1084 
    1085     def _on_purge(self, request):
    1086         return self.purge(request.sender, request.recipient,
    1087                           request.nodeIdentifier)
    1088 
    1089 
    1090     def _on_delete(self, request):
    1091         return self.delete(request.sender, request.recipient,
    1092                            request.nodeIdentifier)
    1093 
    1094 
    1095     def _on_affiliationsGet(self, iq):
    1096         raise Unsupported('modify-affiliations')
    1097 
    1098 
    1099     def _on_affiliationsSet(self, iq):
    1100         raise Unsupported('modify-affiliations')
    1101 
    1102 
    1103     def _on_subscriptionsGet(self, iq):
    1104         raise Unsupported('manage-subscriptions')
    1105 
    1106 
    1107     def _on_subscriptionsSet(self, iq):
    1108         raise Unsupported('manage-subscriptions')
    1109 
    1110     # public methods
    11111111
    11121112    def _createNotification(self, eventType, service, nodeIdentifier,
    11131113                                  subscriber, subscriptions=None):
     
    11311131
    11321132        return message
    11331133
     1134    # public methods
     1135
    11341136    def notifyPublish(self, service, nodeIdentifier, notifications):
    11351137        for subscriber, subscriptions, items in notifications:
    11361138            message = self._createNotification('items', service,
     
    12151217
    12161218    def delete(self, requestor, service, nodeIdentifier):
    12171219        raise Unsupported('delete-nodes')
     1220
     1221
     1222
     1223class PubSubResource(object):
     1224
     1225    implements(IPubSubResource)
     1226
     1227    features = []
     1228    discoIdentity = disco.DiscoIdentity('pubsub',
     1229                                        'service',
     1230                                        'Publish-Subscribe Service')
     1231
     1232
     1233    def locateResource(self, request):
     1234        return self
     1235
     1236
     1237    def getInfo(self, requestor, service, nodeIdentifier):
     1238        return defer.succeed(None)
     1239
     1240
     1241    def getNodes(self, requestor, service, nodeIdentifier):
     1242        return defer.succeed([])
     1243
     1244
     1245    def getConfigurationOptions(self):
     1246        return {}
     1247
     1248
     1249    def publish(self, request):
     1250        return defer.fail(Unsupported('publish'))
     1251
     1252
     1253    def subscribe(self, request):
     1254        return defer.fail(Unsupported('subscribe'))
     1255
     1256
     1257    def unsubscribe(self, request):
     1258        return defer.fail(Unsupported('subscribe'))
     1259
     1260
     1261    def subscriptions(self, request):
     1262        return defer.fail(Unsupported('retrieve-subscriptions'))
     1263
     1264
     1265    def affiliations(self, request):
     1266        return defer.fail(Unsupported('retrieve-affiliations'))
     1267
     1268
     1269    def create(self, request):
     1270        return defer.fail(Unsupported('create-nodes'))
     1271
     1272
     1273    def default(self, request):
     1274        return defer.fail(Unsupported('retrieve-default'))
     1275
     1276
     1277    def configureGet(self, request):
     1278        return defer.fail(Unsupported('config-node'))
     1279
     1280
     1281    def configureSet(self, request):
     1282        return defer.fail(Unsupported('config-node'))
     1283
     1284
     1285    def items(self, request):
     1286        return defer.fail(Unsupported('retrieve-items'))
     1287
     1288
     1289    def retract(self, request):
     1290        return defer.fail(Unsupported('retract-items'))
     1291
     1292
     1293    def purge(self, request):
     1294        return defer.fail(Unsupported('purge-nodes'))
     1295
     1296
     1297    def delete(self, request):
     1298        return defer.fail(Unsupported('delete-nodes'))
     1299
     1300
     1301    def affiliationsGet(self, request):
     1302        return defer.fail(Unsupported('modify-affiliations'))
     1303
     1304
     1305    def affiliationsSet(self, request):
     1306        return defer.fail(Unsupported('modify-affiliations'))
     1307
     1308
     1309    def subscriptionsGet(self, request):
     1310        return defer.fail(Unsupported('manage-subscriptions'))
     1311
     1312
     1313    def subscriptionsSet(self, request):
     1314        return defer.fail(Unsupported('manage-subscriptions'))
  • wokkel/test/test_pubsub.py

    diff -r 29f67459352b wokkel/test/test_pubsub.py
    a b  
    12221222
    12231223    def setUp(self):
    12241224        self.stub = XmlStreamStub()
    1225         self.service = pubsub.PubSubService()
     1225        self.resource = pubsub.PubSubResource()
     1226        self.service = pubsub.PubSubService(self.resource)
    12261227        self.service.send = self.stub.xmlstream.send
    12271228
    12281229    def test_interface(self):
     
    12601261        Test getDiscoInfo calls getNodeInfo and returns some minimal info.
    12611262        """
    12621263        def cb(info):
    1263             self.assertEqual(2, len(info))
     1264            discoInfo = disco.DiscoInfo()
     1265            for item in info:
     1266                discoInfo.append(item)
     1267            self.assertIn(('pubsub', 'service'), discoInfo.identities)
     1268            self.assertIn(disco.NS_DISCO_ITEMS, discoInfo.features)
    12641269
    1265         def getNodeInfo(requestor, target, nodeIdentifier):
    1266             return defer.succeed(None)
    1267 
    1268         self.service.getNodeInfo = getNodeInfo
    12691270        d = self.service.getDiscoInfo(JID('user@example.org/home'),
    12701271                                      JID('pubsub.example.org'), '')
    12711272        d.addCallback(cb)
     
    12821283                discoInfo.append(item)
    12831284            self.assertIn(('pubsub', 'collection'), discoInfo.identities)
    12841285
    1285         def getNodeInfo(requestor, target, nodeIdentifier):
     1286        def getInfo(requestor, target, nodeIdentifier):
    12861287            return defer.succeed({'type': 'collection',
    12871288                                  'meta-data': {}})
    12881289
    1289         self.service.getNodeInfo = getNodeInfo
     1290        self.resource.getInfo = getInfo
    12901291        d = self.service.getDiscoInfo(JID('user@example.org/home'),
    12911292                                      JID('pubsub.example.org'), '')
    12921293        d.addCallback(cb)
     
    13071308            form = discoInfo.extensions[NS_PUBSUB_META_DATA]
    13081309            self.assertIn('pubsub#node_type', form.fields)
    13091310
    1310         def getNodeInfo(requestor, target, nodeIdentifier):
     1311        def getInfo(requestor, target, nodeIdentifier):
    13111312            metaData = [{'var': 'pubsub#persist_items',
    13121313                         'label': 'Persist items to storage',
    13131314                         'value': True}]
    13141315            return defer.succeed({'type': 'leaf', 'meta-data': metaData})
    13151316
    1316         self.service.getNodeInfo = getNodeInfo
     1317        self.resource.getInfo = getInfo
    13171318        d = self.service.getDiscoInfo(JID('user@example.org/home'),
    13181319                                      JID('pubsub.example.org'), '')
    13191320        d.addCallback(cb)
    13201321        return d
    13211322
    13221323
    1323     def test_onPublish(self):
     1324    def test_getDiscoInfoResourceFeatures(self):
     1325        """
     1326        Test getDiscoInfo with the resource features.
     1327        """
     1328        def cb(info):
     1329            discoInfo = disco.DiscoInfo()
     1330            for item in info:
     1331                discoInfo.append(item)
     1332            self.assertIn('http://jabber.org/protocol/pubsub#publish',
     1333                          discoInfo.features)
     1334
     1335        self.resource.features = ['publish']
     1336        d = self.service.getDiscoInfo(JID('user@example.org/home'),
     1337                                      JID('pubsub.example.org'), '')
     1338        d.addCallback(cb)
     1339        return d
     1340
     1341
     1342    def test_getDiscoItemsRoot(self):
     1343        """
     1344        Test getDiscoItems on the root node.
     1345        """
     1346        def getNodes(requestor, service, nodeIdentifier):
     1347            return defer.succeed(['node1', 'node2'])
     1348
     1349        def cb(items):
     1350            self.assertEqual(2, len(items))
     1351            item1, item2 = items
     1352
     1353            self.assertEqual(JID('pubsub.example.org'), item1.entity)
     1354            self.assertEqual('node1', item1.nodeIdentifier)
     1355
     1356            self.assertEqual(JID('pubsub.example.org'), item2.entity)
     1357            self.assertEqual('node2', item2.nodeIdentifier)
     1358
     1359        self.resource.getNodes = getNodes
     1360        d = self.service.getDiscoItems(JID('user@example.org/home'),
     1361                                       JID('pubsub.example.org'),
     1362                                       '')
     1363        d.addCallback(cb)
     1364        return d
     1365
     1366
     1367    def test_getDiscoItemsRootHideNodes(self):
     1368        """
     1369        Test getDiscoItems on the root node.
     1370        """
     1371        def getNodes(requestor, service, nodeIdentifier):
     1372            raise Exception("Unexpected call to getNodes")
     1373
     1374        def cb(items):
     1375            self.assertEqual([], items)
     1376
     1377        self.service.hideNodes = True
     1378        self.resource.getNodes = getNodes
     1379        d = self.service.getDiscoItems(JID('user@example.org/home'),
     1380                                       JID('pubsub.example.org'),
     1381                                       '')
     1382        d.addCallback(cb)
     1383        return d
     1384
     1385
     1386    def test_getDiscoItemsNonRoot(self):
     1387        """
     1388        Test getDiscoItems on a non-root node.
     1389        """
     1390        def getNodes(requestor, service, nodeIdentifier):
     1391            return defer.succeed(['node1', 'node2'])
     1392
     1393        def cb(items):
     1394            self.assertEqual(2, len(items))
     1395
     1396        self.resource.getNodes = getNodes
     1397        d = self.service.getDiscoItems(JID('user@example.org/home'),
     1398                                       JID('pubsub.example.org'),
     1399                                       'test')
     1400        d.addCallback(cb)
     1401        return d
     1402
     1403
     1404    def test_on_publish(self):
    13241405        """
    13251406        A publish request should result in L{PubSubService.publish} being
    13261407        called.
     
    13351416        </iq>
    13361417        """
    13371418
    1338         def publish(requestor, service, nodeIdentifier, items):
     1419        def publish(request):
    13391420            return defer.succeed(None)
    13401421
    1341         self.service.publish = publish
    1342         verify.verifyObject(iwokkel.IPubSubService, self.service)
     1422        self.resource.publish = publish
     1423        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    13431424        return self.handleRequest(xml)
    13441425
    13451426
    1346     def test_onSubscribe(self):
     1427    def test_on_subscribe(self):
    13471428        """
    13481429        A successful subscription should return the current subscription.
    13491430        """
     
    13571438        </iq>
    13581439        """
    13591440
    1360         def subscribe(requestor, service, nodeIdentifier, subscriber):
    1361             return defer.succeed(pubsub.Subscription(nodeIdentifier,
    1362                                                      subscriber,
     1441        def subscribe(request):
     1442            return defer.succeed(pubsub.Subscription(request.nodeIdentifier,
     1443                                                     request.subscriber,
    13631444                                                     'subscribed'))
    13641445
    13651446        def cb(element):
     
    13711452            self.assertEqual('user@example.org/Home', subscription['jid'])
    13721453            self.assertEqual('subscribed', subscription['subscription'])
    13731454
    1374         self.service.subscribe = subscribe
    1375         verify.verifyObject(iwokkel.IPubSubService, self.service)
     1455        self.resource.subscribe = subscribe
     1456        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    13761457        d = self.handleRequest(xml)
    13771458        d.addCallback(cb)
    13781459        return d
    13791460
    13801461
    1381     def test_onSubscribeEmptyNode(self):
     1462    def test_on_subscribeEmptyNode(self):
    13821463        """
    13831464        A successful subscription on root node should return no node attribute.
    13841465        """
     
    13921473        </iq>
    13931474        """
    13941475
    1395         def subscribe(requestor, service, nodeIdentifier, subscriber):
    1396             return defer.succeed(pubsub.Subscription(nodeIdentifier,
    1397                                                      subscriber,
     1476        def subscribe(request):
     1477            return defer.succeed(pubsub.Subscription(request.nodeIdentifier,
     1478                                                     request.subscriber,
    13981479                                                     'subscribed'))
    13991480
    14001481        def cb(element):
    14011482            self.assertFalse(element.subscription.hasAttribute('node'))
    14021483
    1403         self.service.subscribe = subscribe
    1404         verify.verifyObject(iwokkel.IPubSubService, self.service)
     1484        self.resource.subscribe = subscribe
     1485        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    14051486        d = self.handleRequest(xml)
    14061487        d.addCallback(cb)
    14071488        return d
    14081489
    14091490
    1410     def test_onUnsubscribe(self):
     1491    def test_on_unsubscribe(self):
    14111492        """
    14121493        A successful unsubscription should return an empty response.
    14131494        """
     
    14211502        </iq>
    14221503        """
    14231504
    1424         def unsubscribe(requestor, service, nodeIdentifier, subscriber):
     1505        def unsubscribe(request):
    14251506            return defer.succeed(None)
    14261507
    14271508        def cb(element):
    14281509            self.assertIdentical(None, element)
    14291510
    1430         self.service.unsubscribe = unsubscribe
    1431         verify.verifyObject(iwokkel.IPubSubService, self.service)
     1511        self.resource.unsubscribe = unsubscribe
     1512        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    14321513        d = self.handleRequest(xml)
    14331514        d.addCallback(cb)
    14341515        return d
    14351516
    14361517
    1437     def test_onOptionsGet(self):
     1518    def test_on_optionsGet(self):
    14381519        """
    14391520        Getting subscription options is not supported.
    14401521        """
     
    14591540        return d
    14601541
    14611542
    1462     def test_onOptionsSet(self):
     1543    def test_on_optionsSet(self):
    14631544        """
    14641545        Setting subscription options is not supported.
    14651546        """
     
    14911572        return d
    14921573
    14931574
    1494     def test_onSubscriptions(self):
     1575    def test_on_subscriptions(self):
    14951576        """
    14961577        A subscriptions request should result in
    14971578        L{PubSubService.subscriptions} being called and the result prepared
     
    15071588        </iq>
    15081589        """
    15091590
     1591        def subscriptions(request):
     1592            subscription = pubsub.Subscription('test', JID('user@example.org'),
     1593                                               'subscribed')
     1594            return defer.succeed([subscription])
     1595
    15101596        def cb(element):
    15111597            self.assertEqual('pubsub', element.name)
    15121598            self.assertEqual(NS_PUBSUB, element.uri)
     
    15201606            self.assertEqual('test', subscription['node'])
    15211607            self.assertEqual('subscribed', subscription['subscription'])
    15221608
    1523 
    1524         def subscriptions(requestor, service):
    1525             subscription = pubsub.Subscription('test', JID('user@example.org'),
    1526                                                'subscribed')
    1527             return defer.succeed([subscription])
    1528 
    1529         self.service.subscriptions = subscriptions
    1530         verify.verifyObject(iwokkel.IPubSubService, self.service)
     1609        self.resource.subscriptions = subscriptions
     1610        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    15311611        d = self.handleRequest(xml)
    15321612        d.addCallback(cb)
    15331613        return d
    15341614
    15351615
    1536     def test_onAffiliations(self):
     1616    def test_on_affiliations(self):
    15371617        """
    15381618        A subscriptions request should result in
    15391619        L{PubSubService.affiliations} being called and the result prepared
     
    15491629        </iq>
    15501630        """
    15511631
     1632        def affiliations(request):
     1633            affiliation = ('test', 'owner')
     1634            return defer.succeed([affiliation])
     1635
    15521636        def cb(element):
    15531637            self.assertEqual('pubsub', element.name)
    15541638            self.assertEqual(NS_PUBSUB, element.uri)
     
    15611645            self.assertEqual('test', affiliation['node'])
    15621646            self.assertEqual('owner', affiliation['affiliation'])
    15631647
    1564 
    1565         def affiliations(requestor, service):
    1566             affiliation = ('test', 'owner')
    1567             return defer.succeed([affiliation])
    1568 
    1569         self.service.affiliations = affiliations
    1570         verify.verifyObject(iwokkel.IPubSubService, self.service)
     1648        self.resource.affiliations = affiliations
     1649        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    15711650        d = self.handleRequest(xml)
    15721651        d.addCallback(cb)
    15731652        return d
    15741653
    15751654
    1576     def test_onCreate(self):
     1655    def test_on_create(self):
    15771656        """
    15781657        Replies to create node requests don't return the created node.
    15791658        """
     
    15871666        </iq>
    15881667        """
    15891668
    1590         def create(requestor, service, nodeIdentifier):
    1591             return defer.succeed(nodeIdentifier)
     1669        def create(request):
     1670            return defer.succeed(request.nodeIdentifier)
    15921671
    15931672        def cb(element):
    15941673            self.assertIdentical(None, element)
    15951674
    1596         self.service.create = create
    1597         verify.verifyObject(iwokkel.IPubSubService, self.service)
     1675        self.resource.create = create
     1676        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    15981677        d = self.handleRequest(xml)
    15991678        d.addCallback(cb)
    16001679        return d
    16011680
    16021681
    1603     def test_onCreateChanged(self):
     1682    def test_on_createChanged(self):
    16041683        """
    16051684        Replies to create node requests return the created node if changed.
    16061685        """
     
    16141693        </iq>
    16151694        """
    16161695
    1617         def create(requestor, service, nodeIdentifier):
     1696        def create(request):
    16181697            return defer.succeed(u'myrenamednode')
    16191698
    16201699        def cb(element):
     
    16241703            self.assertEqual(u'myrenamednode',
    16251704                             element.create.getAttribute('node'))
    16261705
    1627         self.service.create = create
    1628         verify.verifyObject(iwokkel.IPubSubService, self.service)
     1706        self.resource.create = create
     1707        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    16291708        d = self.handleRequest(xml)
    16301709        d.addCallback(cb)
    16311710        return d
    16321711
    16331712
    1634     def test_onCreateInstant(self):
     1713    def test_on_createInstant(self):
    16351714        """
    16361715        Replies to create instant node requests return the created node.
    16371716        """
     
    16451724        </iq>
    16461725        """
    16471726
    1648         def create(requestor, service, nodeIdentifier):
     1727        def create(request):
    16491728            return defer.succeed(u'random')
    16501729
    16511730        def cb(element):
     
    16541733            self.assertEqual(NS_PUBSUB, element.create.uri)
    16551734            self.assertEqual(u'random', element.create.getAttribute('node'))
    16561735
    1657         self.service.create = create
    1658         verify.verifyObject(iwokkel.IPubSubService, self.service)
     1736        self.resource.create = create
     1737        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    16591738        d = self.handleRequest(xml)
    16601739        d.addCallback(cb)
    16611740        return d
    16621741
    16631742
    1664     def test_onDefault(self):
     1743    def test_on_default(self):
    16651744        """
    16661745        A default request should result in
    16671746        L{PubSubService.getDefaultConfiguration} being called.
     
    16861765                     "label": "Deliver payloads with event notifications"}
    16871766                }
    16881767
    1689         def getDefaultConfiguration(requestor, service, nodeType):
     1768        def default(request):
    16901769            return defer.succeed({})
    16911770
    16921771        def cb(element):
     
    16961775            form = data_form.Form.fromElement(element.default.x)
    16971776            self.assertEqual(NS_PUBSUB_CONFIG, form.formNamespace)
    16981777
    1699         self.service.getConfigurationOptions = getConfigurationOptions
    1700         self.service.getDefaultConfiguration = getDefaultConfiguration
    1701         verify.verifyObject(iwokkel.IPubSubService, self.service)
     1778        self.resource.getConfigurationOptions = getConfigurationOptions
     1779        self.resource.default = default
     1780        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    17021781        d = self.handleRequest(xml)
    17031782        d.addCallback(cb)
    17041783        return d
    17051784
    17061785
    1707     def test_onDefaultCollection(self):
     1786    def test_on_defaultCollection(self):
    17081787        """
    17091788        Responses to default requests should depend on passed node type.
    17101789        """
     
    17351814                     "label": "Deliver payloads with event notifications"}
    17361815                }
    17371816
    1738         def getDefaultConfiguration(requestor, service, nodeType):
     1817        def default(request):
    17391818            return defer.succeed({})
    17401819
    1741         self.service.getConfigurationOptions = getConfigurationOptions
    1742         self.service.getDefaultConfiguration = getDefaultConfiguration
    1743         verify.verifyObject(iwokkel.IPubSubService, self.service)
     1820        self.resource.getConfigurationOptions = getConfigurationOptions
     1821        self.resource.default = default
     1822        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    17441823        return self.handleRequest(xml)
    17451824
    17461825
    1747     def test_onDefaultUnknownNodeType(self):
     1826    def test_on_defaultUnknownNodeType(self):
    17481827        """
    17491828        A default request should result in
    1750         L{PubSubService.getDefaultConfiguration} being called.
     1829        L{PubSubResource.default} being called.
    17511830        """
    17521831
    17531832        xml = """
     
    17691848        </iq>
    17701849        """
    17711850
    1772         def getDefaultConfiguration(requestor, service, nodeType):
     1851        def default(request):
    17731852            self.fail("Unexpected call to getConfiguration")
    17741853
    17751854        def cb(result):
    17761855            self.assertEquals('not-acceptable', result.condition)
    17771856
    1778         self.service.getDefaultConfiguration = getDefaultConfiguration
    1779         verify.verifyObject(iwokkel.IPubSubService, self.service)
     1857        self.resource.default = default
     1858        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    17801859        d = self.handleRequest(xml)
    17811860        self.assertFailure(d, error.StanzaError)
    17821861        d.addCallback(cb)
    17831862        return d
    17841863
    17851864
    1786     def test_onConfigureGet(self):
     1865    def test_on_configureGet(self):
    17871866        """
    1788         On a node configuration get request L{PubSubService.getConfiguration}
    1789         is called and results in a data form with the configuration.
     1867        On a node configuration get
     1868        requestL{PubSubResource.configureGet} is called and results in a
     1869        data form with the configuration.
    17901870        """
    17911871
    17921872        xml = """
     
    18111891                     "label": "Owner of the node"}
    18121892                }
    18131893
    1814         def getConfiguration(requestor, service, nodeIdentifier):
     1894        def configureGet(request):
    18151895            return defer.succeed({'pubsub#deliver_payloads': '0',
    18161896                                  'pubsub#persist_items': '1',
    18171897                                  'pubsub#owner': JID('user@example.org'),
     
    18451925
    18461926            self.assertNotIn('x-myfield', fields)
    18471927
    1848 
    1849         self.service.getConfigurationOptions = getConfigurationOptions
    1850         self.service.getConfiguration = getConfiguration
    1851         verify.verifyObject(iwokkel.IPubSubService, self.service)
     1928        self.resource.getConfigurationOptions = getConfigurationOptions
     1929        self.resource.configureGet = configureGet
     1930        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    18521931        d = self.handleRequest(xml)
    18531932        d.addCallback(cb)
    18541933        return d
    18551934
    18561935
    1857     def test_onConfigureSet(self):
     1936    def test_on_configureSet(self):
    18581937        """
    18591938        On a node configuration set request the Data Form is parsed and
    1860         L{PubSubService.setConfiguration} is called with the passed options.
     1939        L{PubSubResource.configureSet} is called with the passed options.
    18611940        """
    18621941
    18631942        xml = """
     
    18871966                     "label": "Deliver payloads with event notifications"}
    18881967                }
    18891968
    1890         def setConfiguration(requestor, service, nodeIdentifier, options):
     1969        def configureSet(request):
    18911970            self.assertEqual({'pubsub#deliver_payloads': False,
    1892                               'pubsub#persist_items': True}, options)
     1971                              'pubsub#persist_items': True}, request.options)
    18931972            return defer.succeed(None)
    18941973
    1895         self.service.getConfigurationOptions = getConfigurationOptions
    1896         self.service.setConfiguration = setConfiguration
    1897         verify.verifyObject(iwokkel.IPubSubService, self.service)
     1974        self.resource.getConfigurationOptions = getConfigurationOptions
     1975        self.resource.configureSet = configureSet
     1976        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    18981977        return self.handleRequest(xml)
    18991978
    19001979
    1901     def test_onConfigureSetCancel(self):
     1980    def test_on_configureSetCancel(self):
    19021981        """
    1903         The node configuration is cancelled, L{PubSubService.setConfiguration}
    1904         not called.
     1982        The node configuration is cancelled,
     1983        L{PubSubResource.configureSet} not called.
    19051984        """
    19061985
    19071986        xml = """
     
    19191998        </iq>
    19201999        """
    19212000
    1922         def setConfiguration(requestor, service, nodeIdentifier, options):
     2001        def configureSet(request):
    19232002            self.fail("Unexpected call to setConfiguration")
    19242003
    1925         self.service.setConfiguration = setConfiguration
    1926         verify.verifyObject(iwokkel.IPubSubService, self.service)
     2004        self.resource.configureSet = configureSet
     2005        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    19272006        return self.handleRequest(xml)
    19282007
    19292008
    1930     def test_onConfigureSetIgnoreUnknown(self):
     2009    def test_on_configureSetIgnoreUnknown(self):
    19312010        """
    19322011        On a node configuration set request unknown fields should be ignored.
    19332012        """
     
    19592038                     "label": "Deliver payloads with event notifications"}
    19602039                }
    19612040
    1962         def setConfiguration(requestor, service, nodeIdentifier, options):
    1963             self.assertEquals(['pubsub#deliver_payloads'], options.keys())
     2041        def configureSet(request):
     2042            self.assertEquals(['pubsub#deliver_payloads'],
     2043                              request.options.keys())
    19642044
    1965         self.service.getConfigurationOptions = getConfigurationOptions
    1966         self.service.setConfiguration = setConfiguration
    1967         verify.verifyObject(iwokkel.IPubSubService, self.service)
     2045        self.resource.getConfigurationOptions = getConfigurationOptions
     2046        self.resource.configureSet = configureSet
     2047        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    19682048        return self.handleRequest(xml)
    19692049
    19702050
    1971     def test_onConfigureSetBadFormType(self):
     2051    def test_on_configureSetBadFormType(self):
    19722052        """
    19732053        On a node configuration set request unknown fields should be ignored.
    19742054        """
     
    19992079        return d
    20002080
    20012081
    2002     def test_onItems(self):
     2082    def test_on_items(self):
    20032083        """
    20042084        On a items request, return all items for the given node.
    20052085        """
     
    20122092        </iq>
    20132093        """
    20142094
    2015         def items(requestor, service, nodeIdentifier, maxItems,
    2016                   itemIdentifiers):
     2095        def items(request):
    20172096            return defer.succeed([pubsub.Item('current')])
    20182097
    20192098        def cb(element):
     
    20262105            self.assertEqual(NS_PUBSUB, item.uri)
    20272106            self.assertEqual('current', item['id'])
    20282107
    2029         self.service.items = items
     2108        self.resource.items = items
     2109        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    20302110        d = self.handleRequest(xml)
    20312111        d.addCallback(cb)
    20322112        return d
    20332113
    20342114
    2035     def test_onRetract(self):
     2115    def test_on_retract(self):
    20362116        """
    2037         A retract request should result in L{PubSubService.retract} being
    2038         called.
     2117        A retract request should result in L{PubSubResource.retract}
     2118        being called.
    20392119        """
    20402120
    20412121        xml = """
     
    20502130        </iq>
    20512131        """
    20522132
    2053         def retract(requestor, service, nodeIdentifier, itemIdentifiers):
     2133        def retract(request):
    20542134            return defer.succeed(None)
    20552135
    2056         self.service.retract = retract
     2136        self.resource.retract = retract
     2137        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    20572138        return self.handleRequest(xml)
    20582139
    20592140
    2060     def test_onPurge(self):
     2141    def test_on_purge(self):
    20612142        """
    2062         A purge request should result in L{PubSubService.purge} being
     2143        A purge request should result in L{PubSubResource.purge} being
    20632144        called.
    20642145        """
    20652146
     
    20722153        </iq>
    20732154        """
    20742155
    2075         def purge(requestor, service, nodeIdentifier):
     2156        def purge(request):
    20762157            return defer.succeed(None)
    20772158
    2078         self.service.purge = purge
     2159        self.resource.purge = purge
     2160        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    20792161        return self.handleRequest(xml)
    20802162
    20812163
    2082     def test_onDelete(self):
     2164    def test_on_delete(self):
    20832165        """
    2084         A delete request should result in L{PubSubService.delete} being
     2166        A delete request should result in L{PubSubResource.delete} being
    20852167        called.
    20862168        """
    20872169
     
    20942176        </iq>
    20952177        """
    20962178
    2097         def delete(requestor, service, nodeIdentifier):
     2179        def delete(request):
    20982180            return defer.succeed(None)
    20992181
    2100         self.service.delete = delete
     2182        self.resource.delete = delete
     2183        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
    21012184        return self.handleRequest(xml)
    21022185
    21032186
     
    21482231        self.assertEqual(redirectURI, message.event.delete.redirect['uri'])
    21492232
    21502233
    2151     def test_onSubscriptionsGet(self):
     2234    def test_on_subscriptionsGet(self):
    21522235        """
    21532236        Getting subscription options is not supported.
    21542237        """
     
    21752258        return d
    21762259
    21772260
    2178     def test_onSubscriptionsSet(self):
     2261    def test_on_subscriptionsSet(self):
    21792262        """
    21802263        Setting subscription options is not supported.
    21812264        """
     
    22022285        return d
    22032286
    22042287
    2205     def test_onAffiliationsGet(self):
     2288    def test_on_affiliationsGet(self):
    22062289        """
    22072290        Getting subscription options is not supported.
    22082291        """
     
    22292312        return d
    22302313
    22312314
    2232     def test_onAffiliationsSet(self):
     2315    def test_on_affiliationsSet(self):
    22332316        """
    22342317        Setting subscription options is not supported.
    22352318        """
     
    22562339        return d
    22572340
    22582341
     2342
     2343class PubSubServiceWithoutResourceTest(unittest.TestCase, TestableRequestHandlerMixin):
     2344
     2345    def setUp(self):
     2346        self.stub = XmlStreamStub()
     2347        self.service = pubsub.PubSubService()
     2348        self.service.send = self.stub.xmlstream.send
     2349
     2350
    22592351    def test_publish(self):
    22602352        """
    22612353        Non-overridden L{PubSubService.publish} yields unsupported error.
     
    26042696        self.assertFailure(d, error.StanzaError)
    26052697        d.addCallback(cb)
    26062698        return d
     2699
     2700
     2701
     2702class PubSubResourceTest(unittest.TestCase):
     2703
     2704    def setUp(self):
     2705        self.resource = pubsub.PubSubResource()
     2706
     2707
     2708    def test_interface(self):
     2709        """
     2710        Do instances of L{pubsub.PubSubResource} provide L{iwokkel.IPubSubResource}?
     2711        """
     2712        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
     2713
     2714
     2715    def test_getNodes(self):
     2716        """
     2717        Default getNodes returns an empty list.
     2718        """
     2719        def cb(nodes):
     2720            self.assertEquals([], nodes)
     2721
     2722        d = self.resource.getNodes(JID('user@example.org/home'),
     2723                                   JID('pubsub.example.org'),
     2724                                   '')
     2725        d.addCallback(cb)
     2726        return d
     2727
     2728
     2729    def test_publish(self):
     2730        """
     2731        Non-overridden L{PubSubResource.publish} yields unsupported
     2732        error.
     2733        """
     2734
     2735        def cb(result):
     2736            self.assertEquals('feature-not-implemented', result.condition)
     2737            self.assertEquals('unsupported', result.appCondition.name)
     2738            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     2739            self.assertEquals('publish', result.appCondition['feature'])
     2740
     2741        d = self.resource.publish(pubsub.PubSubRequest())
     2742        self.assertFailure(d, error.StanzaError)
     2743        d.addCallback(cb)
     2744        return d
     2745
     2746
     2747    def test_subscribe(self):
     2748        """
     2749        Non-overridden subscriptions yields unsupported error.
     2750        """
     2751
     2752        def cb(result):
     2753            self.assertEquals('feature-not-implemented', result.condition)
     2754            self.assertEquals('unsupported', result.appCondition.name)
     2755            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     2756            self.assertEquals('subscribe', result.appCondition['feature'])
     2757
     2758        d = self.resource.subscribe(pubsub.PubSubRequest())
     2759        self.assertFailure(d, error.StanzaError)
     2760        d.addCallback(cb)
     2761        return d
     2762
     2763
     2764    def test_unsubscribe(self):
     2765        """
     2766        Non-overridden unsubscribe yields unsupported error.
     2767        """
     2768
     2769        def cb(result):
     2770            self.assertEquals('feature-not-implemented', result.condition)
     2771            self.assertEquals('unsupported', result.appCondition.name)
     2772            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     2773            self.assertEquals('subscribe', result.appCondition['feature'])
     2774
     2775        d = self.resource.unsubscribe(pubsub.PubSubRequest())
     2776        self.assertFailure(d, error.StanzaError)
     2777        d.addCallback(cb)
     2778        return d
     2779
     2780
     2781    def test_subscriptions(self):
     2782        """
     2783        Non-overridden subscriptions yields unsupported error.
     2784        """
     2785
     2786        def cb(result):
     2787            self.assertEquals('feature-not-implemented', result.condition)
     2788            self.assertEquals('unsupported', result.appCondition.name)
     2789            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     2790            self.assertEquals('retrieve-subscriptions',
     2791                              result.appCondition['feature'])
     2792
     2793        d = self.resource.subscriptions(pubsub.PubSubRequest())
     2794        self.assertFailure(d, error.StanzaError)
     2795        d.addCallback(cb)
     2796        return d
     2797
     2798
     2799    def test_affiliations(self):
     2800        """
     2801        Non-overridden affiliations yields unsupported error.
     2802        """
     2803
     2804        def cb(result):
     2805            self.assertEquals('feature-not-implemented', result.condition)
     2806            self.assertEquals('unsupported', result.appCondition.name)
     2807            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     2808            self.assertEquals('retrieve-affiliations',
     2809                              result.appCondition['feature'])
     2810
     2811        d = self.resource.affiliations(pubsub.PubSubRequest())
     2812        self.assertFailure(d, error.StanzaError)
     2813        d.addCallback(cb)
     2814        return d
     2815
     2816
     2817    def test_create(self):
     2818        """
     2819        Non-overridden create yields unsupported error.
     2820        """
     2821
     2822        def cb(result):
     2823            self.assertEquals('feature-not-implemented', result.condition)
     2824            self.assertEquals('unsupported', result.appCondition.name)
     2825            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     2826            self.assertEquals('create-nodes', result.appCondition['feature'])
     2827
     2828        d = self.resource.create(pubsub.PubSubRequest())
     2829        self.assertFailure(d, error.StanzaError)
     2830        d.addCallback(cb)
     2831        return d
     2832
     2833
     2834    def test_default(self):
     2835        """
     2836        Non-overridden default yields unsupported error.
     2837        """
     2838
     2839        def cb(result):
     2840            self.assertEquals('feature-not-implemented', result.condition)
     2841            self.assertEquals('unsupported', result.appCondition.name)
     2842            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     2843            self.assertEquals('retrieve-default',
     2844                              result.appCondition['feature'])
     2845
     2846        d = self.resource.default(pubsub.PubSubRequest())
     2847        self.assertFailure(d, error.StanzaError)
     2848        d.addCallback(cb)
     2849        return d
     2850
     2851
     2852    def test_configureGet(self):
     2853        """
     2854        Non-overridden configureGet yields unsupported
     2855        error.
     2856        """
     2857
     2858        def cb(result):
     2859            self.assertEquals('feature-not-implemented', result.condition)
     2860            self.assertEquals('unsupported', result.appCondition.name)
     2861            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     2862            self.assertEquals('config-node', result.appCondition['feature'])
     2863
     2864        d = self.resource.configureGet(pubsub.PubSubRequest())
     2865        self.assertFailure(d, error.StanzaError)
     2866        d.addCallback(cb)
     2867        return d
     2868
     2869
     2870    def test_configureSet(self):
     2871        """
     2872        Non-overridden configureSet yields unsupported error.
     2873        """
     2874
     2875        def cb(result):
     2876            self.assertEquals('feature-not-implemented', result.condition)
     2877            self.assertEquals('unsupported', result.appCondition.name)
     2878            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     2879            self.assertEquals('config-node', result.appCondition['feature'])
     2880
     2881        d = self.resource.configureSet(pubsub.PubSubRequest())
     2882        self.assertFailure(d, error.StanzaError)
     2883        d.addCallback(cb)
     2884        return d
     2885
     2886
     2887    def test_items(self):
     2888        """
     2889        Non-overridden items yields unsupported error.
     2890        """
     2891
     2892        def cb(result):
     2893            self.assertEquals('feature-not-implemented', result.condition)
     2894            self.assertEquals('unsupported', result.appCondition.name)
     2895            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     2896            self.assertEquals('retrieve-items', result.appCondition['feature'])
     2897
     2898        d = self.resource.items(pubsub.PubSubRequest())
     2899        self.assertFailure(d, error.StanzaError)
     2900        d.addCallback(cb)
     2901        return d
     2902
     2903
     2904    def test_retract(self):
     2905        """
     2906        Non-overridden retract yields unsupported error.
     2907        """
     2908
     2909        def cb(result):
     2910            self.assertEquals('feature-not-implemented', result.condition)
     2911            self.assertEquals('unsupported', result.appCondition.name)
     2912            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     2913            self.assertEquals('retract-items', result.appCondition['feature'])
     2914
     2915        d = self.resource.retract(pubsub.PubSubRequest())
     2916        self.assertFailure(d, error.StanzaError)
     2917        d.addCallback(cb)
     2918        return d
     2919
     2920
     2921    def test_purge(self):
     2922        """
     2923        Non-overridden purge yields unsupported error.
     2924        """
     2925
     2926        def cb(result):
     2927            self.assertEquals('feature-not-implemented', result.condition)
     2928            self.assertEquals('unsupported', result.appCondition.name)
     2929            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     2930            self.assertEquals('purge-nodes', result.appCondition['feature'])
     2931
     2932        d = self.resource.purge(pubsub.PubSubRequest())
     2933        self.assertFailure(d, error.StanzaError)
     2934        d.addCallback(cb)
     2935        return d
     2936
     2937
     2938    def test_delete(self):
     2939        """
     2940        Non-overridden delete yields unsupported error.
     2941        """
     2942
     2943        def cb(result):
     2944            self.assertEquals('feature-not-implemented', result.condition)
     2945            self.assertEquals('unsupported', result.appCondition.name)
     2946            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     2947            self.assertEquals('delete-nodes', result.appCondition['feature'])
     2948
     2949        d = self.resource.delete(pubsub.PubSubRequest())
     2950        self.assertFailure(d, error.StanzaError)
     2951        d.addCallback(cb)
     2952        return d
Note: See TracBrowser for help on using the repository browser.