diff -r 7740d56a1644 wokkel/disco.py --- a/wokkel/disco.py Mon Jan 18 09:16:50 2010 +0100 +++ b/wokkel/disco.py Thu Jan 21 11:39:08 2010 +0100 @@ -495,10 +495,7 @@ """ Gather results from a list of deferreds. - Similar to L{defer.gatherResults}, but flattens the returned results, - consumes errors after the first one and fires the errback of the - returned deferred with the failure of the first deferred that fires its - errback. + Similar to L{defer.gatherResults}, but flattens the returned results. @param deferredList: List of deferreds for which the results should be gathered. @@ -512,13 +509,9 @@ results.extend(value) return results - def eb(failure): - failure.trap(defer.FirstError) - return failure.value.subFailure - d = defer.DeferredList(deferredList, fireOnOneErrback=1, consumeErrors=1) - d.addCallbacks(cb, eb) + d.addCallback(cb) return d diff -r 7740d56a1644 wokkel/pubsub.py --- a/wokkel/pubsub.py Mon Jan 18 09:16:50 2010 +0100 +++ b/wokkel/pubsub.py Thu Jan 21 11:39:08 2010 +0100 @@ -1011,7 +1011,7 @@ @type pubSubFeatures: C{list} or C{None} """ - implements(IPubSubService) + implements(IPubSubService, disco.IDisco) iqHandlers = { '/*': '_onPubSubRequest', @@ -1057,10 +1057,10 @@ self.xmlstream.addObserver(PUBSUB_REQUEST, self.handleRequest) - def getDiscoInfo(self, requestor, target, nodeIdentifier): - def toInfo(nodeInfo, info): + def getDiscoInfo(self, requestor, target, nodeIdentifier=''): + def toInfo(nodeInfo): if not nodeInfo: - return info + return (nodeType, metaData) = nodeInfo['type'], nodeInfo['meta-data'] info.append(disco.DiscoIdentity('pubsub', nodeType)) @@ -1080,7 +1080,7 @@ info.append(form) - return info + return info = [] @@ -1106,12 +1106,13 @@ for feature in features]) d = defer.maybeDeferred(getInfo, requestor, target, nodeIdentifier or '') - d.addCallback(toInfo, info) + d.addCallback(toInfo) d.addErrback(log.err) + d.addCallback(lambda _: info) return d - def getDiscoItems(self, requestor, target, nodeIdentifier): + def getDiscoItems(self, requestor, target, nodeIdentifier=''): if self.hideNodes: d = defer.succeed([]) elif self.resource is not None: diff -r 7740d56a1644 wokkel/test/test_disco.py --- a/wokkel/test/test_disco.py Mon Jan 18 09:16:50 2010 +0100 +++ b/wokkel/test/test_disco.py Thu Jan 21 11:39:08 2010 +0100 @@ -9,9 +9,10 @@ from twisted.internet import defer from twisted.trial import unittest +from twisted.words.protocols.jabber.error import StanzaError from twisted.words.protocols.jabber.jid import JID from twisted.words.protocols.jabber.xmlstream import toResponse -from twisted.words.xish import domish +from twisted.words.xish import domish, utility from wokkel import data_form, disco from wokkel.generic import parseXml @@ -596,6 +597,46 @@ self.service = disco.DiscoHandler() + def test_connectionInitializedObserveInfo(self): + """ + An observer for Disco Info requests is setup on stream initialization. + """ + xml = """ + + """ % NS_DISCO_INFO + + def handleRequest(iq): + called.append(iq) + + called = [] + self.service.xmlstream = utility.EventDispatcher() + self.service.handleRequest = handleRequest + self.service.connectionInitialized() + self.service.xmlstream.dispatch(parseXml(xml)) + self.assertEqual(1, len(called)) + + + def test_connectionInitializedObserveItems(self): + """ + An observer for Disco Items requests is setup on stream initialization. + """ + xml = """ + + """ % NS_DISCO_ITEMS + + def handleRequest(iq): + called.append(iq) + + called = [] + self.service.xmlstream = utility.EventDispatcher() + self.service.handleRequest = handleRequest + self.service.connectionInitialized() + self.service.xmlstream.dispatch(parseXml(xml)) + self.assertEqual(1, len(called)) + + def test_onDiscoInfo(self): """ C{onDiscoInfo} should process an info request and return a response. @@ -661,6 +702,30 @@ return d + def test_onDiscoInfoWithNodeNoResults(self): + """ + An info request for a node with no results returns items-not-found. + """ + xml = """ + + """ % NS_DISCO_INFO + + def cb(exc): + self.assertEquals('item-not-found', exc.condition) + + def info(requestor, target, nodeIdentifier): + self.assertEqual('test', nodeIdentifier) + + return defer.succeed([]) + + self.service.info = info + d = self.handleRequest(xml) + self.assertFailure(d, StanzaError) + d.addCallback(cb) + return d + + def test_onDiscoItems(self): """ C{onDiscoItems} should process an items request and return a response. diff -r 7740d56a1644 wokkel/test/test_pubsub.py --- a/wokkel/test/test_pubsub.py Mon Jan 18 09:16:50 2010 +0100 +++ b/wokkel/test/test_pubsub.py Thu Jan 21 11:39:08 2010 +0100 @@ -1903,6 +1903,13 @@ verify.verifyObject(iwokkel.IPubSubService, self.service) + def test_interfaceIDisco(self): + """ + Do instances of L{pubsub.PubSubService} provide L{iwokkel.IDisco}? + """ + verify.verifyObject(iwokkel.IDisco, self.service) + + def test_connectionMade(self): """ Verify setup of observers in L{pubsub.connectionMade}. @@ -2009,6 +2016,42 @@ return d + def test_getDiscoInfoBadResponse(self): + """ + If getInfo returns invalid response, it should be logged, then ignored. + """ + def cb(info): + self.assertEquals([], info) + self.assertEqual(1, len(self.flushLoggedErrors(TypeError))) + + def getInfo(requestor, target, nodeIdentifier): + return defer.succeed('bad response') + + self.resource.getInfo = getInfo + d = self.service.getDiscoInfo(JID('user@example.org/home'), + JID('pubsub.example.org'), 'test') + d.addCallback(cb) + return d + + + def test_getDiscoInfoException(self): + """ + If getInfo returns invalid response, it should be logged, then ignored. + """ + def cb(info): + self.assertEquals([], info) + self.assertEqual(1, len(self.flushLoggedErrors(NotImplementedError))) + + def getInfo(requestor, target, nodeIdentifier): + return defer.fail(NotImplementedError()) + + self.resource.getInfo = getInfo + d = self.service.getDiscoInfo(JID('user@example.org/home'), + JID('pubsub.example.org'), 'test') + d.addCallback(cb) + return d + + def test_getDiscoItemsRoot(self): """ Test getDiscoItems on the root node.